FC2カウンター FPGAの部屋 2011年09月
fc2ブログ

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

FPGAの部屋

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

Spartan-3A Starter KitでEDKを使ってカメラ表示25(LCD、Rotary EncoderカスタムIPの追加3)

Spartan-3A Starter KitでEDKを使ってカメラ表示24(LCD、Rotary EncoderカスタムIPの追加2)”の続き。

前回は、.paoファイルにHDLファイルを追加するのを忘れてしまった。

rotary_encoder_v2_1_0.paoから追加する。下に内容を示す。

##############################################################################
## Filename: H:/HDL/FndtnISEWork/Spartan3A_starter_kit/CamDisp_EDK_OV7670_LCD/system/pcores/rotary_encoder_v1_00_a/data/rotary_encoder_v2_1_0.pao
## Description: Peripheral Analysis Order
## Date: Tue Sep 27 05:24:05 2011 (by Create and Import Peripheral Wizard)
##############################################################################

lib proc_common_v3_00_a all
lib plbv46_slave_single_v1_01_a all
lib rotary_encoder_v1_00_a user_logic vhdl
lib rotary_encoder_v1_00_a rotary_encoder vhdl
lib rotary_encoder_v1_00_a rot_enc_cont.vhd vhdl
lib rotary_encoder_v1_00_a ROTSW_SM.vhd vhdl
lib rotary_encoder_v1_00_a swdiv_rot.vhd vhdl


次に、lcd_controller_v2_1_0.paoの内容を下に示す。

##############################################################################
## Filename: H:/HDL/FndtnISEWork/Spartan3A_starter_kit/CamDisp_EDK_OV7670_LCD/system/pcores/lcd_controller_v1_00_a/data/lcd_controller_v2_1_0.pao
## Description: Peripheral Analysis Order
## Date: Tue Sep 27 05:26:28 2011 (by Create and Import Peripheral Wizard)
##############################################################################

lib proc_common_v3_00_a all
lib plbv46_slave_single_v1_01_a all
lib lcd_controller_v1_00_a user_logic vhdl
lib lcd_controller_v1_00_a lcd_controller vhdl
lib lcd_controller_v1_00_a lcd_ctlr.vhd vhdl


これで、XPSでProjectメニューから> Rescan User Repositoriesを選択して、生成したカスタムIPの変更をもう一度、XPSに認識させた。

(注)もう一度、元のEDKプロジェクトをコピーして、カスタムIPを作りなおしても、(PAOファイルが完全でも)やはり同様にワーニングが出ている。PAOファイルは関係なかったみたいだ。
もしかすると、複数PLBバスがあると何処にアサインするか分からないのかもしれない?


system.ucf にロータリー・エンコーダとLCDの入出力ピンの制約を追加した。追加した制約を下に示す。

# ロータリーエンコーダ
NET "rot_center" LOC = "R13" | IOSTANDARD = LVTTL | PULLDOWN ;
NET "rot_a" LOC = "T13" | IOSTANDARD = LVTTL | PULLUP ;
NET "rot_b" LOC = "R14" | IOSTANDARD = LVTTL | PULLUP ;

# LCD
NET "LCD_E" LOC = "AB4" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_RS" LOC = "Y14" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_RW" LOC = "W13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<7>" LOC = "Y15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<6>" LOC = "AB16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<5>" LOC = "Y16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<4>" LOC = "AA12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<3>" LOC = "AB12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<2>" LOC = "AB17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<1>" LOC = "AB18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;
NET "LCD_DB<0>" LOC = "Y13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = QUIETIO ;



これでインプリメントを試みた。しかし、MAPでエラー発生。
Spa3A_SKit_OV7670_106_110929.png

1つ目のエラーの内容を示す。

ERROR:MapLib:979 - LUT2 symbol "system_i/rotary_encoder_0/rotary_encoder_0/USER_LOGIC_I/rot_enc_cont_i/ROTSW_SM_inst/next_center_pulse1" (output signal=system_i/rotary_encoder_0/rotary_encoder_0/USER_LOGIC_I/rot_enc_cont_i/ROTSW_SM_inst/next_center_pulse) has input signal "system_i/rotary_encoder_0/rotary_encoder_0/USER_LOGIC_I/rot_enc_cont_i/rot_center_node" which will be trimmed. See Section 5 of the Map Report File for details about why the input signal will become undriven.


信号が削除されたので、入力が無くなったというようなエラーだった。

原因がわかったぞ。。。入出力ピンを追加したのにXPSのトップファイルを再生成していないためだ…
早速、Project NavigatorでXPSを選択して、ProcessesウインドウのGenerate Top HDL Sourceをダブルクリックした。下の図は実行後。
Spa3A_SKit_OV7670_107_110930.png

やった~~~。MAP通った… よかった。
インプリメントが終了した。今回は、大分苦労してしまった。
Spa3A_SKit_OV7670_108_110930.png

MAPリポートの一部を下に示す。

elease 13.2 Map O.61xd (nt)
Xilinx Mapping Report File for Design 'system_top'

Design Information
------------------
Command Line   : map -intstyle ise -p xc3s700a-fg484-4 -cm speed -ir off -pr off
-c 100 -o system_top_map.ncd system_top.ngd system_top.pcf 
Target Device  : xc3s700a
Target Package : fg484
Target Speed   : -4
Mapper Version : spartan3a -- $Revision: 1.55 $
Mapped Date    : FRI 30 SEP 5:23:31 2011

Design Summary
--------------
Number of errors:      0
Number of warnings:  251
Logic Utilization:
  Number of Slice Flip Flops:         5,830 out of  11,776   49%
  Number of 4 input LUTs:             6,458 out of  11,776   54%
Logic Distribution:
  Number of occupied Slices:          5,551 out of   5,888   94%
    Number of Slices containing only related logic:   5,551 out of   5,551 100%
    Number of Slices containing unrelated logic:          0 out of   5,551   0%
      *See NOTES below for an explanation of the effects of unrelated logic.
  Total Number of 4 input LUTs:       6,836 out of  11,776   58%
    Number used as logic:             5,900
    Number used as a route-thru:        378
    Number used for Dual Port RAMs:     320
      (Two LUTs used per Dual Port RAM)
    Number used as Shift registers:     238

  The Slice Logic Distribution report is not meaningful if the design is
  over-mapped for a non-slice resource or if Placement fails.

  Number of bonded IOBs:                114 out of     372   30%
    IOB Flip Flops:                      23
    IOB Master Pads:                      3
    IOB Slave Pads:                       3
  Number of ODDR2s used:                 24
    Number of DDR_ALIGNMENT = NONE       24
    Number of DDR_ALIGNMENT = C0          0
    Number of DDR_ALIGNMENT = C1          0
  Number of BUFGMUXs:                    10 out of      24   41%
  Number of DCMs:                         4 out of       8   50%
  Number of BSCANs:                       1 out of       1  100%
  Number of BSCAN_SPARTAN3As:             1 out of       1  100%
  Number of MULT18X18SIOs:                3 out of      20   15%
  Number of RAMB16BWEs:                  19 out of      20   95%

  Number of RPM macros:            1
Average Fanout of Non-Clock Nets:                3.28

Peak Memory Usage:  242 MB
Total REAL time to MAP completion:  29 secs 
Total CPU time to MAP completion:   25 secs 


前回、LCDコントローラとロータリー・エンコーダのコントローラを入れる前は、Number of Slice Flip Flopsが47%だったが、今回は49%だった。順調に増えているようなので、大丈夫だろう?と思う。
  1. 2011年09月30日 05:35 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示24(LCD、Rotary EncoderカスタムIPの追加2)

Spartan-3A Starter KitでEDKを使ってカメラ表示23(LCD、Rotary EncoderカスタムIPの追加)”の続き。

今回は、lcd_controller のVHDLファイルを追加し、user_logic.vhd, lcd_controller.vhd の修正を行う。

まずは、CamDisp_EDK_OV7670_LCD\system\pcores\lcd_controller_v1_00_a\hdl\vhdl にlcd_ctlr.vhd をコピーした。
Spa3A_SKit_OV7670_97_110928.png

user_logic.vhd を修正する。VHDLコードの主要な部分を下に示す。まだコードチェックをしていないので間違っているかもしれない。この他にもsignal宣言、component宣言、ポート宣言を追加した。

  -- lcd_ctlr.vhd を接続
  
  -- data_ena を生成する
    process( Bus2IP_Clk ) begin
        if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
            if Bus2IP_Reset = '1' then
                data_ena <= '0';
            else
                if slv_reg_write_sel="1" then
                    data_ena <= '1';
                else
                    data_ena <= '0';
                end if;
            end if;
        end if;
    end process;
    
  LCD_ctlr_i : LCD_ctlr port map (
      CLK => Bus2IP_Clk,
      RESET => Bus2IP_Reset,
      DIN => slv_reg0(C_SLV_DWIDTH-1-15 to C_SLV_DWIDTH-1); -- 下位16ビット  
      CS => data_ena,
      LCD_DB => LCD_DB,
      LCD_RS => LCD_RS, 
      LCD_RW => LCD_RW,
      LCD_E => LCD_E
  );


lcd_controller.vhd にLCD用のポート宣言とそのポート接続を追加した。ポート宣言部分の一部を下に示す。

entity lcd_controller is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_BASEADDR                     : std_logic_vector     := X"FFFFFFFF";

    ...

    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
      LCD_DB : out std_logic_vector(7 downto 0);
      LCD_RS : out std_logic;
      LCD_RW : out std_logic;
      LCD_E : out std_logic;
    -- ADD USER PORTS ABOVE THIS LINE ------------------


rotary_encoder_v2_1_0.mpdを開いて、ポート宣言を追加した。

PORT rot_a = "", DIR = I
PORT rot_b = "", DIR = I
PORT rot_center = "", DIR = I


lcd_controller_v2_1_0.mpdを開いて、ポート宣言を追加した。

PORT LCD_DB = "", DIR = O, VEC = [7:0]
PORT LCD_RS = "", DIR = O
PORT LCD_RW = "", DIR = O
PORT LCD_E = "", DIR = O


XPSでProjectメニューから> Rescan User Repositoriesを選択して、生成したカスタムIPの変更をXPSに認識させた。

xps_timerはすでに入っているので、rotary_encoder, lcd_controller を右クリックメニューからAdd IPした。

XPS Core Configダイアログが開いたが、次のInstantiate and Connect IPダイアログが開かなかった。XPSを見るとrotary_encoder, lcd_controllerが入っていたが、どのPLBにも接続されていなかった。
Spa3A_SKit_OV7670_98_110929.png

rotary_encoder, lcd_controller のSPLBをmb_plbに接続した。(MicroBlazeのPLBバス)
Spa3A_SKit_OV7670_99_110929.png

Portsタブで、右クリックメニューからMake External を選択し、外部出力信号に定義した。
Spa3A_SKit_OV7670_100_110929.png

External Portsの名前を変更した。
Spa3A_SKit_OV7670_101_110929.png

Spa3A_SKit_OV7670_102_110929.png

Addressesタブをクリックすると、rotary_encoder, lcd_controllerがUでマップされていない。
Spa3A_SKit_OV7670_103_110929.png

双方にSizeのプルダウンメニューから64Kを割り振った。MicroBlazeのアドレス内に入ったがBase Addressが0のままだった。
Spa3A_SKit_OV7670_104_110929.png

rotary_encoderに0x840A0000, lcd_controllerに0x840C0000 のベース・アドレスを割り振った。
Spa3A_SKit_OV7670_105_110929.png

(追記)
なんで自動的にアドレスがマップされないのか?と思ったら、ワーニングが出ていました。

WARNING:EDK:2137 - Peripheral rotary_encoder_0 is not accessible from any processor in the system. Check Bus Interface connections and address parameters.
WARNING:EDK:2137 - Peripheral lcd_controller_0 is not accessible from any processor in the system. Check Bus Interface connections and address parameters.


考えてみたら、.paoファイルに自分で追加したファイルの設定をするのを忘れていました。後で記事を書き換えます。
もう一度、元のEDKプロジェクトをコピーして、カスタムIPを作りなおしても、(PAOファイルが完全でも)やはり同様にワーニングが出ている。PAOファイルは関係なかったみたいだ。
もしかすると、複数PLBバスがあると何処にアサインするか分からないのかもしれない?
  1. 2011年09月29日 05:49 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示23(LCD、Rotary EncoderカスタムIPの追加)

Spartan-3A Starter KitでEDKを使ってカメラ表示22(一応完成)”の続き。

前回、CMOSカメラの画像データをディスプレイに表示することができた。それでも、MicroBlazeプロセッサは何も仕事をしていない。ハードウェアだけで表示している。これでは、MicroBlazeプロセッサがかわいそうなので、仕事を割り振ることにした。以前はSMMでやっていたのだが、LCDに主要なCMOSカメラのパラメータを表示して、ロータリー・エンコーダでパラメータを設定して、LCDで表示するという機能をMicroBlazeに割り振ることにした。(”The Simple MicroBlaze Microcontroller 19 (SCCB設定レジスタを設定できたが...)”参照)
Cソースはあるのだが、SMM用なので、MicroBlaze用に修正する必要がある。例えば、タイマーはSMM用でなく、axi_timerを使用するので、そこは修正が必要だ。後はアドレスは修正する必要がある。

さて、今までのXPSプロジェクトにlcd_controller とrotary_encoder の新しい2つのカスタムIPを生成した。2つともスレーブIPだ。
Spa3A_SKit_OV7670_95_110928.png

まずはロータリー・エンコーダの方から、関連するVHDLファイルをコピーした。
Spa3A_SKit_OV7670_96_110928.png

user_logic.vhd を修正する。VHDLコードの主要な部分を下に示す。まだコードチェックをしていないので間違っているかもしれない。この他にもsignal宣言、component宣言、ポート宣言を追加した。

  -- implement slave model software accessible register(s) read mux
  SLAVE_REG_READ_PROC : process( slv_reg_read_sel, slv_reg0 ) is
  begin

    case slv_reg_read_sel is
      when "1" =>
        slv_ip2bus_data(0 to C_SLV_DWIDTH-5) <= (others => '0');
        slv_ip2bus_data(C_SLV_DWIDTH-4) <= center_hold;
        slv_ip2bus_data(C_SLV_DWIDTH-3) <= left_hold;
        slv_ip2bus_data(C_SLV_DWIDTH-2) <= right_hold;
        slv_ip2bus_data(C_SLV_DWIDTH-1) <= '0';
      when others => slv_ip2bus_data <= (others => '0');
    end case;

  end process SLAVE_REG_READ_PROC;

  ------------------------------------------
  -- Example code to drive IP to Bus signals
  ------------------------------------------
  IP2Bus_Data  <= slv_ip2bus_data when slv_read_ack = '1' else
                  (others => '0');

  IP2Bus_WrAck <= slv_write_ack;
  IP2Bus_RdAck <= slv_read_ack;
  IP2Bus_Error <= '0';

    -- rot_enc_cont.vhd を接続
    
    -- CS_rot_enc_wr を生成する
    process( Bus2IP_Clk ) begin
        if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
            if Bus2IP_Reset = '1' then
                CS_rot_enc_wr <= '0';
            else
                if slv_reg_write_sel="1" then
                    CS_rot_enc_wr <= '1';
                else
                    CS_rot_enc_wr <= '0';
                end if;
            end if;
        end if;
    end process;    
    
    -- ロータリーエンコーダ
    rot_enc_cont_i : rot_enc_cont port map(
        clk => Bus2IP_Clk,
        reset => Bus2IP_Reset,
        rot_a => rot_a,
        rot_b => rot_b,
        rot_center => rot_center,
        right_pulse => right_pulse,
        left_pulse => left_pulse,
        center_pulse => center_pulse
    );
    
    -- right_pulse, left_pulse をホールドするFF
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                right_hold <= '0';
                left_hold <= '0';
                center_hold <= '0';
            else
                if right_pulse = '1' then
                    right_hold <= '1';
                elsif CS_rot_enc_wr='1' then 
                    right_hold <= '0';
                end if;
                
                if left_pulse='1' then
                    left_hold <= '1';
                elsif CS_rot_enc_wr='1' then
                    left_hold <= '0';
                end if;
                
                if center_pulse='1' then
                    center_hold <= '1';
                elsif CS_rot_enc_wr='1' then
                    center_hold <= '0';
                end if;
            end if;
        end if;
    end process;


レジスタReadのcenter_hold, left_hold, right_hold のビット割り当ては、以前のSMMの時のハードウェアに合わせてある。

rotary_encoder.vhd にロータリー・エンコーダ用のポート宣言とそのポート接続を追加した。ポート宣言部分の一部を下に示す。

entity rotary_encoder is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_BASEADDR                     : std_logic_vector     := X"FFFFFFFF";
    
    ...

    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
    rot_a : in std_logic;
    rot_b : in std_logic;
    rot_center : in std_logic;
    -- ADD USER PORTS ABOVE THIS LINE ------------------


ロータリー・エンコーダのA相(rot_a)、B相(rot_b)、センター・スイッチ(rot_center)を入力ポートとして定義した。

  1. 2011年09月28日 05:37 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトを更新(2011/09/25)

FPGAの部屋のまとめサイトを更新しました。
EDK, ISim, Core Generator, MicroBlazeクロスコンパイル, VHDLの書き方のページを更新しました。特にEDKのページの追加がほとんどです。
  1. 2011年09月25日 21:28 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

”FPGA ボードで学ぶ組込みシステム開発入門 ~Altera編~”(本)を買いました

FPGA ボードで学ぶ組込みシステム開発入門 ~Altera編~”を買いました。FPGAの本です。

まだ1/3しか読んでいませんが、DE0やDE1のFPGAボードで、FPGAを初歩から勉強していく方にお勧めの本だと思いました。ただ、論理回路の知識は前提条件として必要です。

巻末を見ると、なんと、第4章のSignalTap II の参考Webサイトとして、FPGAの部屋のまとめサイトが載っていました。びっくり。
第5章 Nios II プログラミング、ROM化方法ではSim's blogさんが、第6章のAvalonバス関連では長船さん(FPGA技術 No.5)が参考文献・Webサイトとして載っていました。

読みやすい本でとても良いと思いますが、シミュレーションの記述がないのが残念だと思いました。ModelSimについて解説して欲しかったです。ページ数が増えてしまうと思いますが、ぜひシミュレーションを実行するというステップをFPGA初心者の方にも習慣付けて欲しいと思っています。

本の中で紹介のあるサポートベージが見つかりません。現在、出版社に問い合わせ中です。サポートベージが見つかれば、少しやってみたいと思っています。

著者の小林優さんは、本当に近くに来られることがあるようなので、今度一度、お会いしてお話ししてみたいと思っています。

(2011/9/26:追記)
FPGAボードで学ぶ組込みシステム開発入門 ~Altera編~のサポートベージが開設されました。ここからDE0とDE1用のファイルがダウンロードできます。
  1. 2011年09月25日 05:36 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:4

Spartan-3A Starter KitでEDKを使ってカメラ表示22(一応完成)

Spartan-3A Starter KitでEDKを使ってカメラ表示21(インプリメント)”でインプリメントが終了したので、Spartan-3A Starter Kitにダウンロードして確かめてみた。

こんな感じでaitendoのOV7670カメラをSpartan-3A Starter Kitに付けて実験している。CMOSカメラ搭載基板の作り方はこちら
Spa3A_SKit_OV7670_93_110923.jpg

画像は写ったが、右の画像が左に来ていた。
Spa3A_SKit_OV7670_92_110923.jpg

左の時計は、右に見えているはずなのだ。
画面の比を測ってみると、画面の横が37.6cmだったが、そのうちの7.7cmずれていた。何ドットずれているか計算してみると、

640ドット / 37.6cm × 7.7cm ≒ 131ドット


128ドットずれているか?
最初に128ドットずれてしまうのかもしれない?
そこで、VSYNCの時に非同期FIFOやアドレスをリセットするようにした。そうしたら、正常に表示されるようになった。動作してとっても嬉しいが、EDKが入っているプロジェクトをシミュレーションするにも、インプリメントするにも時間がかかってしまった。今日はデバックしていた。

うまく行ったという記念写真を下に貼る。
Spa3A_SKit_OV7670_94_110923.jpg

MicroBlazeのソフトウェアは何も入れていないが、この場合は暴走しているのだろうか?HALTしているのかな?
ロータリーエンコーダでCMOSカメラの設定をするソフトウェアを書いてあるので、走らせてみたい。これは、SMM(Simple Micro Blaze)用に書いてあるので、修正する必要がある。

とりあえず、これで一応、EDKを使用して、自分でカスタム・マスタIP、カスタム・スレーブIPを作って、カメラ表示回路を作ることができた。うれしい…
特に、カスタム・マスタIPの作り方は資料が少なく、推測で作った部分も多いが動作して本当に良かった。

  1. 2011年09月23日 20:18 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示21(インプリメント)

Spartan-3A Starter KitでEDKを使ってカメラ表示20(カメラ回路のシミュレーション)”の続き。

今回は、シミュレーションで問題が無い様なので、インプリメントしてみることにした。早速インプリメントしてみたが、エラーが出てしまった。エラーを下に示す。

ERROR:Place:1138 - Automatic clock placement failed. Please attempt to analyze the global clocking required for this design and either lock the clock placement or area locate the logic driven by the clocks so that the clocks may be placed in such a way that all logic driven by them may be routed. The main restriction on clock placement is that only one clock output signal for any competing Global / Side pair of clocks may enter any region. For further information see the "Quadrant Clock Routing" section in the Spartan3a Family Datasheet.


ERROR_Place_1138_1_110922.png

Webで検索の結果、エラー番号は違うが、”9.2i EDK, Spartan-3A DSP - "ERROR:Place:848 - Automatic clock placement failed"”がヒットした。

それによると、XPSのProjectタブのProject Filesの下にfast_runtime.optがあるということなのだが、な~い。

ファイルを検索した所、system\etcフォルダの下にあることがわかった。
ERROR_Place_1138_2_110922.png

the Program MAP sectionの-timingを消せばよいらしい。

Program mapがあったので、-timing;を消した。
ERROR_Place_1138_3_110922.png

ついでに、XPSのProjectメニューからClean All Generate Filesをやっておいた。

Project Navigatorに戻って、もう一度、Rerun all でインプリメントしたが、やはり同じエラーが出てしまった。

仕方が無いので、fast_runtime.optの-timingオプションを戻してから、PlanAheadを使用して、DCMを固定してみることにした。
DCMは、CamDisp_EDK_OV7670\elaborate\clock_generator_0_v4_02_a\hdl\vhdl\clock_generator.vhd を見たところ、DCMは2つ使ってあって、DCM1が50MHzクロック・オシレータから入力されたクロックを125MHzに変換していた。それをDCM0が受け、125MHzの0度クロック、125MHz90度クロック、2分周された62.5MHzクロックの3つのクロック全てを出力していた。つまりすべてのクロックをDCM1が出力していて、こちらのほうがBUFGを多く使っていた。

Project Navigator のProcessesウインドウのUser Costraintsを展開して、Floorplan Area/IO/Logic (PlanAhead) を起動して、DCMの位置を固定して、からインプリメントした。
PlanAheadを立ち上げると、Spartan-3Aの左側にDDR2 SDRAMのリソースが固定されていた。これはそこのパッドにDDR2 SDRAMが接続されているからだ。

DCM0, DCM1をいろいろ配置にしてみたが、”ERROR:Place:1138 - Automatic clock placement failed. ”が出るのは、DCM1がFPGAチップの上側の右側、DCM0を下側に配置したときに出るようだ。
Spa3A_SKit_OV7670_89_110923.png

その時のUCFファイルを示す。

INST "system_i/clock_generator_0/clock_generator_0/DCM1_INST/Using_Virtex.DCM_INST" LOC = DCM_X2Y3;
INST "system_i/clock_generator_0/clock_generator_0/DCM0_INST/Using_Virtex.DCM_INST" LOC = DCM_X1Y0;


それ以外の場合は、DCMなどの配置が最適じゃないので、CLOCK_DEDICATED_ROUTEを使えというようなエラーが出た。
DCM1の出力をCLOCK_DEDICATED_ROUTEしなくてはいけない場合は、カメラ表示回路の動作が危なくなるので、そのようなDCMの配置は使えない。

いろいろやってみた結果、DCM1をFPGAチップの左側の上、DCM0を上側の左に配置した時が良いとわかった。ここの位置だと、50MHzクロック・オシレータからDCM1への入力は遠くなってしまい、CLOCK_DEDICATED_ROUTEが必要だが、その他のエラーは出ない。カメラ表示回路の入出力は入力クロックに対して、入力や出力の制約がないので、ここの時間が伸びるのは問題ない。下にDCMの配置を示す。(このPlanAheadの図はインプリメント後のものだ)
Spa3A_SKit_OV7670_90_110923.png

追加したUCFファイルを下に示す。

INST "system_i/clock_generator_0/clock_generator_0/DCM0_INST/Using_Virtex.DCM_INST" LOC = DCM_X1Y3;
INST "system_i/clock_generator_0/clock_generator_0/DCM1_INST/Using_Virtex.DCM_INST" LOC = DCM_X0Y2;
NET "fpga_0_clk_1_sys_clk_pin" CLOCK_DEDICATED_ROUTE = FALSE;
PIN "system_i/clock_generator_0/clock_generator_0/DCM1_INST/Using_Virtex.DCM_INST/DCM_SP.CLKIN" CLOCK_DEDICATED_ROUTE = FALSE;


これで、もう一度インプリメントしたら成功した。やった~。

下にインプリメント後のProject Navigator を示す。やっとインプリメント成功。
Spa3A_SKit_OV7670_91_110923.png

LUT使用率は53%、FF使用率は47%だった。下にMAPのリポートの一部を示す。

Release 13.2 Map O.61xd (nt)
Xilinx Mapping Report File for Design 'system_top'

Design Information
------------------
Command Line   : map -intstyle ise -p xc3s700a-fg484-4 -cm speed -ir off -pr off
-c 100 -o system_top_map.ncd system_top.ngd system_top.pcf 
Target Device  : xc3s700a
Target Package : fg484
Target Speed   : -4
Mapper Version : spartan3a -- $Revision: 1.55 $
Mapped Date    : THU 22 SEP 23:18:57 2011

Design Summary
--------------
Number of errors:      0
Number of warnings:  251
Logic Utilization:
  Number of Slice Flip Flops:         5,598 out of  11,776   47%
  Number of 4 input LUTs:             6,271 out of  11,776   53%
Logic Distribution:
  Number of occupied Slices:          5,366 out of   5,888   91%
    Number of Slices containing only related logic:   5,366 out of   5,366 100%
    Number of Slices containing unrelated logic:          0 out of   5,366   0%
      *See NOTES below for an explanation of the effects of unrelated logic.
  Total Number of 4 input LUTs:       6,629 out of  11,776   56%
    Number used as logic:             5,713
    Number used as a route-thru:        358
    Number used for Dual Port RAMs:     320
      (Two LUTs used per Dual Port RAM)
    Number used as Shift registers:     238

  The Slice Logic Distribution report is not meaningful if the design is
  over-mapped for a non-slice resource or if Placement fails.

  Number of bonded IOBs:                100 out of     372   26%
    IOB Flip Flops:                      23
    IOB Master Pads:                      3
    IOB Slave Pads:                       3
  Number of ODDR2s used:                 24
    Number of DDR_ALIGNMENT = NONE       24
    Number of DDR_ALIGNMENT = C0          0
    Number of DDR_ALIGNMENT = C1          0
  Number of BUFGMUXs:                    10 out of      24   41%
  Number of DCMs:                         4 out of       8   50%
  Number of BSCANs:                       1 out of       1  100%
  Number of BSCAN_SPARTAN3As:             1 out of       1  100%
  Number of MULT18X18SIOs:                3 out of      20   15%
  Number of RAMB16BWEs:                  19 out of      20   95%

  Number of RPM macros:            1
Average Fanout of Non-Clock Nets:                3.30

Peak Memory Usage:  240 MB
Total REAL time to MAP completion:  39 secs 
Total CPU time to MAP completion:   25 secs 


  1. 2011年09月23日 05:59 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示20(カメラ回路のシミュレーション)

Spartan-3A Starter KitでEDKを使ってカメラ表示19(InitDoneの処理)”の続き。

前回、ディスプレイ回路はシミュレーションの結果、問題なく動作していそうだということがわかった。今度はカメラ回路のシミュレーションを行った。カメラ回路はカメラからデータを取得して、DDR2 SDRAMに書きこむのでWrite動作を行う。

シミュレーションは全体のシミュレーションのため1msのシミュレーションに長い時間がかかる。測ってなかったが10分以上かかるので、すぐにvsyncが出るようにOV7670モデルを調整して行った。

Cam_Controller_Top.vhdのIPICインタフェース部分のシミュレーション結果を下に示す。
Spa3A_SKit_OV7670_87_110922.png

1.IP2Bus_MstWr_Reqが1になって、コマンド転送が始まる。

2.IP2Bus_Mst_Addrにアドレスをセット、IP2Bus_Mst_Lengthに転送長(040、0x40バイト、64バイト、16バースト)をセットする。

3.96nsec(6クロック後)にBus2IP_Mst_CmdAckが1になって、コマンド転送は終了。

4.1.と同時にデータ転送もスタートし、IP2Bus_MstWr_dにデータを出力、IP2Bus_MstWr_sof_nを0にアサートして最初のデータであることを宣言する。

5.同時に、IP2Bus_MstWr_src_rdy_nを0にアサートする。

6.Bus2IP_MstWr_dst_rdy_nが0にアサートされるのは、48nsec(3クロック)後だった。IP2Bus_MstWr_src_rdy_nとBus2IP_MstWr_dst_rdy_nが同時にアサートされるときに1個のデータ転送が完了する。

7.2つ目のデータ転送は、80nsec(5クロック)待たされた。5クロック後にBus2IP_MstWr_dst_rdy_nがアサートされ、2つ目のデータ転送が完了した。(IP2Bus_MstWr_src_rdy_nは0にアサートし続けている)

8.その後のデータ転送はWait無く終了し、最後に、Bus2IP_Mst_Cmpltが1にアサートされて終了となる。

Writeが開始されて完了するまでの時間は448nsecとなった。

次に、シミュレーション波形の時間間隔を伸ばすと下のシミュレーション波形となった。
Spa3A_SKit_OV7670_88_110922.png

ここで、Writeの間隔は、2.56usecとなった。
32ビット幅のバスで2.56usecで16バースト転送を行っているので、スループットは、(16バースト×4バイト)/ 2.56X(10の-6乗)= 25MBytes/sec となった。

MPMCのDDR2 SDRAMの理想的な帯域は、125MHzでDDRで16ビットデータ幅なので、125MHz×2×2バイト=500MBytes/sec となった。1/20の帯域を使っていることになる。

前回のディスプレイ回路は全帯域の1/5、カメラ回路は1/20の帯域をピークで使用する。両方あわせて5/20、つまり、1/4の帯域を使用する。MPMCのDDR2 SDRAMはピークの帯域を想定しているので、それよりも少ない帯域になるが、1/4の帯域しか使用しないとなると、まだ余裕があるといえると思う。
カメラ回路もディスプレイ回路もなるべく長いバースト長を使用することで、ベースとなる帯域を減らさないように工夫している。
  1. 2011年09月22日 05:30 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示19(InitDoneの処理)

Spartan-3A Starter KitでEDKを使ってカメラ表示18(シミュレーションでデバック2)”の続き。

前回、MPMC(Multi-Port Memory Controller)の初期化が済んでいないのが原因だとわかった。
camera_controller, display_controller, sccb_controller の各モジュールにMPMC_InitDone信号を追加して、今までのリセット信号とORをとり、クロックで同期した信号を新たなリセット信号とすることにした。

次に、それぞれの.MPDファイルにMPMC_InitDone 信号を追加した。

PORT MPMC_InitDone = "", DIR = I


XPSでProjectメニューから> Rescan User Repositories をしてから、Portタブを見ると、camera_controller, display_controller, sccb_controller の各モジュールにMPMC_InitDone信号が追加された。
Spa3A_SKit_OV7670_82_110920.png

これを、MPMCのMPMC_InitDone と接続した。
Spa3A_SKit_OV7670_83_110920.png

ついでに、試しにインプリメントしてみたら、BRAMが足りなかったので、キャッシュを取り外すことにする。
Use Instruction and Data Caches のチェックを外した。
Spa3A_SKit_OV7670_84_110920.png


もう一度、XPSでProjectメニューから> Rescan User Repositories をする。

XPSを終了して、再度、シミュレーションを行った。今回は、ip2bus_mstrd_reqを1(アクティブ)にするタイミングをInitDoneが1になった後にしたのがわかると思う。
Spa3A_SKit_OV7670_86_110921.png

次に、Disp_Controller_Top.vhd のIPICのプロトコル部分を下図に示す。”Spartan-3A Starter KitでEDKを使ってカメラ表示6(PLBV46 Master Burstのバースト転送)”のFixed Length Burst Read Operationを参照。
Spa3A_SKit_OV7670_85_110921.png

ip2bus_mstrd_reqを1(アクティブ)にした後、6クロック(96nsec) でip2bus_mst_cmdackが1にアサートされている。ip2bus_mst_cmdackが1にアサートされた後、15クロック(240nsec) で、bus2ip_mstrd_src_rdy_n が0にアサートされている。その後、bus2ip_mstrd_src_rdy_nは、ディアサートされること無く連続してアサートされている。
1つのバースト転送の処理時間は、43クロック(688nsec) となった。32ビット幅のバスで688nsecで16バースト転送を行っているので、スループットは、(16バースト×4バイト)/ 688X(10の-9乗)≒ 93MBytes/sec となった。

MPMCのDDR2 SDRAMの理想的な帯域は、125MHzでDDRで16ビットデータ幅なので、125MHz×2×2バイト=500MBytes/sec となった。約1/5の帯域を使っていることになる。
  1. 2011年09月21日 05:55 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示18(シミュレーションでデバック2)

Spartan-3A Starter KitでEDKを使ってカメラ表示17(シミュレーションでデバック1)”の続き。

前回、クロックがカスタムIPにつながって、やっとシミュレーションを実行することができるようになった。
シミュレーションを行うと、ip2bus_mstrd_reqを1(アクティブ)にしても、ip2buf_mst_cmdackが帰ってこない。下図参照。
Spa3A_SKit_OV7670_79_110920.png

何でか?といろいろ悩んでいたのだが、ふと気がついた。もしかしたらDDR2 SDRAMコントローラのMPMC(Multi-Port Memory Controller)の初期化が済んでいないのではないか?
MPMCのInitDone信号を入れて(もう入っているが。。。)、それを観察してみることにした。
300usecほどシミュレーションしてみた。その結果を下図に示す。
Spa3A_SKit_OV7670_80_110920.png

220usec手前辺りで、ip2buf_mst_cmdackが帰ってきているのがわかる。一番上のInitDoneを見ると、その辺りで1になっていることがわかった。
明らかにMPMCに初期化までip2buf_mst_cmdackは帰らないことになっているようだ。
そういえば、自分のカメラ表示回路では、DDR2 SDRAMコントローラの初期化が終了するまで、その他の回路が動かないようにトップモジュールで処理していたのだった。今回、EDKで作っているので、各モジュールで何とかする必要がある。

XPSを立ち上げて、Portタブをクリックして、DDR2_SDRAMを見てみると、MPMC_InitDone信号が出ていた。これをカスタムIPに接続して、1になるまで動作しないようにすれば良いはず。。。
Spa3A_SKit_OV7670_81_110920.png

MPMC_InitDone信号をカスタムIPで使用して、1になるまでリセットするようにHDLを変更しよう。
  1. 2011年09月20日 04:46 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示17(シミュレーションでデバック1)

Spartan-3A Starter KitでEDKを使ってカメラ表示16(回路をXPSに登録)”の続き。

Spartan-3A Starter Kitにダウンロードして、ディスプレイが同期もしていなかったので、いくら何でもおかしいということでシミュレーションを行った。”EDKのシミュレーション”を参考にした。

Project Navigatorでテストベンチのテンプレートを作成して修正した。テストベンチsystem_top_tb.vの自分で追加した部分を下に示す。

    assign resetx = ~fpga_0_rst_1_sys_rst_pin;
    
    OV7670_Model OV7670_inst (
        .clk(fpga_0_rst_1_sys_rst_pin),
        .resetx(resetx),
        .vsync(cam_vsync),
        .href(cam_href),
        .pclk(cam_pclk),
        .ydata(cam_data)
    );
        
    parameter PERIOD = 200; // 200MHz clock
    parameter real DUTY_CYCLE = 0.5;
    parameter OFFSET = 0;
    
    initial    // Clock process for clk
    begin
        fpga_0_clk_1_sys_clk_pin = 1'b0;
        #OFFSET;
        forever begin
            fpga_0_clk_1_sys_clk_pin = 1'b0;
            #(PERIOD-(PERIOD*DUTY_CYCLE)) fpga_0_clk_1_sys_clk_pin = 1'b1;
            #(PERIOD*DUTY_CYCLE);
        end
    end

    initial begin
        // Initialize Inputs
        fpga_0_RS232_DTE_RX_pin = 0;
        fpga_0_RS232_DCE_RX_pin = 0;
        fpga_0_DIPs_4Bit_GPIO_IO_I_pin = 0;
        fpga_0_BTNs_4Bit_GPIO_IO_I_pin = 0;
        fpga_0_DDR2_SDRAM_DDR2_DQS_Div_I_pin = 0;
        fpga_0_rst_1_sys_rst_pin = 1'b1;

        // Wait 100 ns for global reset to finish
        #1000;
        
        // Add stimulus here
        #500
        fpga_0_rst_1_sys_rst_pin = 1'b0;
        
    end
 


これで、Simulate Behavioral Modelをダブルクリックコンパイルして、ISimを起動した。
Spa3A_SKit_OV7670_76_110919.png

そうすると、ipif_Bus2IP_MstRd_sof_n等が'U'になっていた。(慌ててデバックしたので、画像を取ってありませんでした)
いろいろ見ていると、CamDisp_EDK_OV7670\system\pcores\display_controller_v1_00_a\hdl\vhdlフォルダのdisplay_controller.vhdのMPLB_Clkが0のままだったことが判明した。それで、レジスタの初期化もできていないので、'U'になっていたみたいだ。
ソースを見ると、CamDisp_EDK_OV7670フォルダのsystem.v を見ると、plb_v46_1のPLB_Clkがnet_gnd0 に接続されていた。これではクロックが来ていない。

  plb_v46_1_wrapper
    plb_v46_1 (
      .PLB_Clk ( net_gnd0 ),


plb_v46_0 もnet_gnd0 に接続されていた。
ちなみに、plb_v46_1がdisplay_controllerに接続されているPLBで、plb_v46_0がcamera_controllerに接続されているPLBだ。
Spa3A_SKit_OV7670_77_110919.png

どうやって、PLBにクロックを入れるのか?と思ってXPSをいじってみたが、GUIで設定はできないようだった。
system.mhsを見ると、mb_plbの記述に対して、

BEGIN plb_v46
 PARAMETER INSTANCE = mb_plb
 PARAMETER HW_VER = 1.05.a
 PORT PLB_Clk = clk_62_5000MHz
 PORT SYS_Rst = sys_bus_reset
END


に対して、plb_v46_0, plb_v46_1には、PLB_ClkとSYS_Rstの記述がなかった。

BEGIN plb_v46
 PARAMETER INSTANCE = plb_v46_0
 PARAMETER HW_VER = 1.05.a
 PARAMETER C_ARB_TYPE = 0
END

BEGIN plb_v46
 PARAMETER INSTANCE = plb_v46_1
 PARAMETER HW_VER = 1.05.a
END


plb_v46_0, plb_v46_1にPLB_ClkとSYS_Rstの記述をmb_plb同様に追加した。

BEGIN plb_v46
 PARAMETER INSTANCE = plb_v46_0
 PARAMETER HW_VER = 1.05.a
 PARAMETER C_ARB_TYPE = 0
 PORT PLB_Clk = clk_62_5000MHz
 PORT SYS_Rst = sys_bus_reset
END

BEGIN plb_v46
 PARAMETER INSTANCE = plb_v46_1
 PARAMETER HW_VER = 1.05.a
 PORT PLB_Clk = clk_62_5000MHz
 PORT SYS_Rst = sys_bus_reset
END


これで、XPSをXPSでProjectメニューから> Clean All Generate Filesして、XPSでProjectメニューから> Rescan User Repositoriesしてから、シミュレーションすると、CamDisp_EDK_OV7670\system\pcores\display_controller_v1_00_a\hdl\vhdlフォルダのdisplay_controller.vhdのMPLB_Clkにクロックが出力された。
Spa3A_SKit_OV7670_78_110919.png

ipif_Bus2IP_MstRd_sof_nなども'U'にならないで、ちゃんとした信号が出るようになった。

CamDisp_EDK_OV7670フォルダのsystem.v を見ると、plb_v46_1のPLB_Clkがきちんとclk_62_5000MHzに接続されていた。

  plb_v46_1_wrapper
    plb_v46_1 (
      .PLB_Clk ( clk_62_5000MHz ),
      .SYS_Rst ( sys_bus_reset[0] ),

  1. 2011年09月19日 05:22 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示16(回路をXPSに登録)

Spartan-3A Starter KitでEDKを使ってカメラ表示15(SCCBコントローラの接続)”の続き。

AXIバスのEDKでキャラクタ・ディスプレイ・コントローラのカスタムIPを作る3”を参照しながら、カメラ回路とディスプレイ回路、SCCBコントローラをXPSに登録する。

1.CamDisp_EDK_OV7670\system\pcores\camera_controller_v1_00_a\dataフォルダのcamera_controller_v2_1_0.mpd を開いて、##Portsの項目にポート宣言を追加する。

PORT cam_href = "", DIR = I
PORT cam_vsync ="", DIR = I
PORT cam_pclk = "", DIR = I
PORT cam_data = "", DIR = I, VEC = [7:0]
PORT cam_clk = "", DIR = O
PORT afifo_overflow = "", DIR = O
PORT afifo_underflow = "", DIR = O


2.CamDisp_EDK_OV7670\system\pcores\display_controller_v1_00_a\dataフォルダのdisplay_controller_v2_1_0.mpd を開いて、##Portsの項目にポート宣言を追加する。

PORT red_out = "", DIR = O, VEC = [3:0]
PORT green_out = "", DIR = O, VEC = [3:0]
PORT blue_out = "", DIR = O, VEC = [3:0]
PORT hsyncx = "", DIR = O
PORT vsyncx = "", DIR = O
PORT afifo_overflow = "", DIR = O
PORT afifo_underflow = "", DIR = O
PORT addr_is_zero = "", DIR = O
PORT h_v_is_zero = "", DIR = O


3.CamDisp_EDK_OV7670\system\pcores\sccb_controller_v1_00_a\dataフォルダのsccb_controller_v2_1_0.mpd を開いて、##Portsの項目にポート宣言を追加する。

PORT SCL = "", DIR = O
PORT SDA = "", DIR = O


4.XPSでProjectメニューから> Rescan User Repositoriesを選択して、chardispc pcoreの変更をXPSに認識させる。
5.XPSで、Portsタブをクリックすると、今まで設定したすべてのポートが入っている。
Spa3A_SKit_OV7670_71_110916.png

6..Portsタブをクリックする。camera_controller_0, display_controller_0, sccb_controller_0を展開して、必要な信号をすべて選択して、右クリックメニューからMake External を選択する。
Spa3A_SKit_OV7670_72_110916.png

7.外部ピンは、名前の前にモジュール名が付いて、名前の後ろに_pinが付いたファイル名になった。(SDA, SCLは下過ぎて見えていない)
Spa3A_SKit_OV7670_73_110916.png

8.名前が長いので、適当な名前に書き換えた。sccb_controller は表示されていないが、sccb_SDA, sccb_SCLに書き変えた。
Spa3A_SKit_OV7670_74_110916.png

9.XPSのUCF File: data/system.ucfをダブルクリックして、system.ucfファイルに追加する信号の制約を追加した。

NET "cam_clk" LOC = B4;
NET "cam_data[0]" LOC = A5;
NET "cam_data[1]" LOC = B6;
NET "cam_data[2]" LOC = A6;
NET "cam_data[3]" LOC = A7;
NET "cam_data[4]" LOC = A8;
NET "cam_data[5]" LOC = A9;
NET "cam_data[6]" LOC = C10;
NET "cam_data[7]" LOC = A10;
NET "cam_href" LOC = A11;
NET "cam_pclk" LOC = A12;
NET "cam_vsync" LOC = A4;

NET "cam_clk" IOSTANDARD = LVTTL;
NET "cam_data[0]" IOSTANDARD = LVTTL;
NET "cam_data[1]" IOSTANDARD = LVTTL;
NET "cam_data[2]" IOSTANDARD = LVTTL;
NET "cam_data[3]" IOSTANDARD = LVTTL;
NET "cam_data[4]" IOSTANDARD = LVTTL;
NET "cam_data[5]" IOSTANDARD = LVTTL;
NET "cam_data[6]" IOSTANDARD = LVTTL;
NET "cam_data[7]" IOSTANDARD = LVTTL;
NET "cam_href" IOSTANDARD = LVTTL;
NET "cam_pclk" IOSTANDARD = LVTTL;
NET "cam_vsync" IOSTANDARD = LVTTL;

NET "disp_red_out[3]" IOSTANDARD = LVTTL;
NET "disp_red_out[3]" DRIVE = 8;
NET "disp_red_out[3]" SLEW = FAST;
NET "disp_red_out[3]" LOC = C8;
NET "disp_red_out[2]" IOSTANDARD = LVTTL;
NET "disp_red_out[2]" DRIVE = 8;
NET "disp_red_out[2]" SLEW = FAST;
NET "disp_red_out[2]" LOC = B8;
NET "disp_red_out[1]" IOSTANDARD = LVTTL;
NET "disp_red_out[1]" DRIVE = 8;
NET "disp_red_out[1]" SLEW = FAST;
NET "disp_red_out[1]" LOC = B3;
NET "disp_red_out[0]" IOSTANDARD = LVTTL;
NET "disp_red_out[0]" DRIVE = 8;
NET "disp_red_out[0]" SLEW = FAST;
NET "disp_red_out[0]" LOC = A3;
NET "disp_green_out[3]" IOSTANDARD = LVTTL;
NET "disp_green_out[3]" DRIVE = 8;
NET "disp_green_out[3]" SLEW = FAST;
NET "disp_green_out[3]" LOC = D6;
NET "disp_green_out[2]" IOSTANDARD = LVTTL;
NET "disp_green_out[2]" DRIVE = 8;
NET "disp_green_out[2]" SLEW = FAST;
NET "disp_green_out[2]" LOC = C6;
NET "disp_green_out[1]" IOSTANDARD = LVTTL;
NET "disp_green_out[1]" DRIVE = 8;
NET "disp_green_out[1]" SLEW = FAST;
NET "disp_green_out[1]" LOC = D5;
NET "disp_green_out[0]" IOSTANDARD = LVTTL;
NET "disp_green_out[0]" DRIVE = 8;
NET "disp_green_out[0]" SLEW = FAST;
NET "disp_green_out[0]" LOC = C5;
NET "disp_blue_out[3]" IOSTANDARD = LVTTL;
NET "disp_blue_out[3]" DRIVE = 8;
NET "disp_blue_out[3]" SLEW = FAST;
NET "disp_blue_out[3]" LOC = C9;
NET "disp_blue_out[2]" IOSTANDARD = LVTTL;
NET "disp_blue_out[2]" DRIVE = 8;
NET "disp_blue_out[2]" SLEW = FAST;
NET "disp_blue_out[2]" LOC = B9;
NET "disp_blue_out[1]" IOSTANDARD = LVTTL;
NET "disp_blue_out[1]" DRIVE = 8;
NET "disp_blue_out[1]" SLEW = FAST;
NET "disp_blue_out[1]" LOC = D7;
NET "disp_blue_out[0]" IOSTANDARD = LVTTL;
NET "disp_blue_out[0]" DRIVE = 8;
NET "disp_blue_out[0]" SLEW = FAST;
NET "disp_blue_out[0]" LOC = C7;
NET "disp_hsyncx" IOSTANDARD = LVTTL;
NET "disp_hsyncx" DRIVE = 8;
NET "disp_hsyncx" SLEW = FAST;
NET "disp_hsyncx" LOC = C11;
NET "disp_vsyncx" IOSTANDARD = LVTTL;
NET "disp_vsyncx" DRIVE = 8;
NET "disp_vsyncx" SLEW = FAST;
NET "disp_vsyncx" LOC = B11;

NET "sccb_SCL" LOC = "AA3" | IOSTANDARD = LVTTL;
NET "sccb_SDA" LOC = "AB2" | IOSTANDARD = LVTTL;


10.XPSを閉じて、Project Navigatorに戻り、Hierarchyウインドウでsystemを選択する。下のProcessesウインドウでGenerate Top HDL Source をダブルクリックして、トップレベルファイルを生成する。(外部信号を追加したため再ジェネレート)

11.ProcessesウインドウでGenerate Programming File をダブルクリックして、インプリメントを開始した。


論理合成で.ngcで指定したIPがないと言われて止まってしまいます。試行錯誤したのですが、結局、IPの.vhdファイルをそれぞれのVHDLフォルダに入れて、.paoファイルに追加しました。
これでいろいろバグはありましたが、なんとかインプリメント成功しました。

Spa3A_SKit_OV7670_75_110917.png

早速、Spartan-3A Starter Kitにコンフィグしてみたが、ディスプレイに表示しなかった。
次は、シミュレーションしてみようと思う。
  1. 2011年09月16日 05:35 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示15(SCCBコントローラの接続)

Spartan-3A Starter KitでEDKを使ってカメラ表示14(ディスプレイ回路のIPを登録)”の続き。

今度は、最後のSCCBコントローラを接続する。今回はIPICマスタではなくスレーブなので、大分楽ができるはず。。。
user_logic.vhd を修正して、レジスタのWrite時の32ビット幅の下位16ビットをSCCB_Reg_Controller.vhdのaddr_dataポートに接続する。ad_enable は、位相を合わせるために、slv_reg_write_sel="01"の条件の時に、クロックで同期して'1'とする。
レジスタのReadでは、最下位ビットにSCCBbusy をマップした。user_logic.vhd の該当する部分を下に示す。

  -- implement slave model software accessible register(s) read mux
  SLAVE_REG_READ_PROC : process( slv_reg_read_sel, SCCBbusy ) is
  begin
    
    -- スレーブIPのReadは、最下位ビットにSCCBbusy が割り当てられる。
    case slv_reg_read_sel is
      when "1" =>
        slv_ip2bus_data(0 to C_SLV_DWIDTH-2) <= (others => '0');
        slv_ip2bus_data(C_SLV_DWIDTH-1) <= SCCBbusy;
      when others => slv_ip2bus_data <= (others => '0');
    end case;

  end process SLAVE_REG_READ_PROC;

  ------------------------------------------
  -- Example code to drive IP to Bus signals
  ------------------------------------------
  IP2Bus_Data  <= slv_ip2bus_data when slv_read_ack = '1' else
                  (others => '0');

  IP2Bus_WrAck <= slv_write_ack;
  IP2Bus_RdAck <= slv_read_ack;
  IP2Bus_Error <= '0';

  -- SCCB_Reg_Controller.vhd を接続
  
  -- ad_enable を生成する
    process( Bus2IP_Clk ) begin
        if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
            if Bus2IP_Resetn = '0' then
                ad_enable <= '0';
            else
                if slv_reg_write_sel="01" then
                    ad_enable <= '1';
                else
                    ad_enable <= '0';
                end if;
            end if;
        end if;
    end process;
    
    Bus2IP_Reset <= not Bus2IP_Resetn;
    addr_data <= slv_reg0(16 to 31); -- 下位16ビット
    
    SCCB_Reg_Controller_inst : SCCB_Reg_Controller port map(
        clkin         => Bus2IP_Clk,
        reset         => Bus2IP_Reset,
        addr_data     => addr_data,
        ad_enable    => ad_enable,
        SCCBbusy     => SCCBbusy,
        SCL            => SCL,
        SDA            => SDA
    );


user_logic.vhd のポート定義にSCLとSDAを追加した。

entity user_logic is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_SLV_DWIDTH                   : integer              := 32;
    C_NUM_REG                      : integer              := 1
    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
    SCL : out std_logic; -- SCCBのクロック
    SDA : out std_logic; -- SCCBのデータ
    
    -- ADD USER PORTS ABOVE THIS LINE ------------------


次に、sccb_controller.vhd にポート定義とポート接続を追加する。
ポート定義を下に示す。

entity sccb_controller is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_BASEADDR                     : std_logic_vector     := X"FFFFFFFF";
    C_HIGHADDR                     : std_logic_vector     := X"00000000";
    C_SPLB_AWIDTH                  : integer              := 32;
    C_SPLB_DWIDTH                  : integer              := 128;
    C_SPLB_NUM_MASTERS             : integer              := 8;
    C_SPLB_MID_WIDTH               : integer              := 3;
    C_SPLB_NATIVE_DWIDTH           : integer              := 32;
    C_SPLB_P2P                     : integer              := 0;
    C_SPLB_SUPPORT_BURSTS          : integer              := 0;
    C_SPLB_SMALLEST_MASTER         : integer              := 32;
    C_SPLB_CLK_PERIOD_PS           : integer              := 10000;
    C_INCLUDE_DPHASE_TIMER         : integer              := 1;
    C_FAMILY                       : string               := "virtex6"
    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
    -- ADD USER PORTS ABOVE THIS LINE ------------------
    SCL : out std_logic; -- SCCBのクロック
    SDA : out std_logic; -- SCCBのデータ

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol ports, do not add to or delete
    SPLB_Clk                       : in  std_logic;
    SPLB_Rst                       : in  std_logic;


ポート接続を下に示す。

  USER_LOGIC_I : entity sccb_controller_v1_00_a.user_logic
    generic map
    (
      -- MAP USER GENERICS BELOW THIS LINE ---------------
      --USER generics mapped here
      -- MAP USER GENERICS ABOVE THIS LINE ---------------

      C_SLV_DWIDTH                   => USER_SLV_DWIDTH,
      C_NUM_REG                      => USER_NUM_REG
    )
    port map
    (
      -- MAP USER PORTS BELOW THIS LINE ------------------
      --USER ports mapped here
        SCL            => SCL,
        SDA            => SDA
      -- MAP USER PORTS ABOVE THIS LINE ------------------

      Bus2IP_Clk                     => ipif_Bus2IP_Clk,
      Bus2IP_Reset                   => ipif_Bus2IP_Reset,
      Bus2IP_Data                    => ipif_Bus2IP_Data,
      Bus2IP_BE                      => ipif_Bus2IP_BE,
      Bus2IP_RdCE                    => user_Bus2IP_RdCE,
      Bus2IP_WrCE                    => user_Bus2IP_WrCE,
      IP2Bus_Data                    => user_IP2Bus_Data,
      IP2Bus_RdAck                   => user_IP2Bus_RdAck,
      IP2Bus_WrAck                   => user_IP2Bus_WrAck,
      IP2Bus_Error                   => user_IP2Bus_Error
    );


CamDisp_EDK_OV7670\system\pcores\sccb_controller_v1_00_a\dataフォルダのsccb_controller_v2_1_0.paoにSCCB_Reg_Controller.vhd とその下のVHDLファイルを追加した。
sccb_controller_v2_1_0.paoの内容を下に示す。

##############################################################################
## Filename: H:/HDL/FndtnISEWork/Spartan3A_starter_kit/CamDisp_EDK_OV7670/system/pcores/sccb_controller_v1_00_a/data/sccb_controller_v2_1_0.pao
## Description: Peripheral Analysis Order
## Date: Sun Aug 21 18:10:38 2011 (by Create and Import Peripheral Wizard)
##############################################################################

lib proc_common_v3_00_a all
lib plbv46_slave_single_v1_01_a all
lib sccb_controller_v1_00_a user_logic vhdl
lib sccb_controller_v1_00_a sccb_controller vhdl
lib sccb_controller_v1_00_a SCCB_reg_values_ROM.vhd vhdl
lib sccb_controller_v1_00_a freqdiv.vhd vhdl
lib sccb_controller_v1_00_a One_Transaction_SCCB.vhd vhdl
lib sccb_controller_v1_00_a SCCB_Reg_Controller.vhd vhdl


最後に、CamDisp_EDK_OV7670\system\pcores\sccb_controller_v1_00_a\hdl\vhdlフォルダにSCCB_Reg_Controller.vhd とその下のVHDLファイルを追加して、今回は終了。
Spa3A_SKit_OV7670_70_110915.png

SCCB_reg_values_ROM.vhdの初期化ファイル、SCCB_reg_values.dataも一緒のフォルダに入れておいたが、この扱いが気になるところではある。
  1. 2011年09月15日 04:56 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Arduinoシミュレータ

Arduinoのシミュレータがないかネットで検索していたら、”Virtual BreadBoardのArduinoシミュレータで遊んで見る”のページが検索できました。

VirtualBreadBoardというシミュレータがあるようです。ダウンロードして、試してみると本格的なシミュレータのようでした。Arduinoを選択して、いろんな部品を付けられるようですね。
VirtualBreadBoard_1_110914.png

再生ボタンをクリックすると、実際の動作をシミュレーションします。ここでは、Blinkなので、右はじのLEDが点滅します。
VirtualBreadBoard_2_110914.png

スケッチ(プログラミング)を変えて、0ポートのLEDと1ポートのLEDを交互に点灯するようにしました。スケッチはBlinkを修正してあります。

const int ledPin = 0  ;   // LED connected to digital pin 13

// The setup() method runs once, when the sketch starts

void setup()   {                
    // initialize the digital pin as an output:

    pinMode(ledPin, OUTPUT); 
    pinMode(1, OUTPUT);

}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()                     
{

    digitalWrite(ledPin, HIGH);   // set the LED on
    digitalWrite(1, LOW);
    delay(1000);                  // wait for a second
    digitalWrite(ledPin, LOW);    // set the LED off
    digitalWrite(1, HIGH);
    delay(1000);                  // wait for a second
  
}


これを実行すると0番のLEDと1番のLEDが交互に点滅するようになりました。

新規回路の作り方は、”Virtual BreadBoardのArduinoシミュレータで遊んで見る”のページに書いてありますし、動画もありました。

それから、Windows7 64ビット版のパソコンだと動作に問題がないのですが、家のWindows XPだと、動作が止まってしまう時があります。なんか問題があるのかもしれません。
まだ全然使いこなしてないですが、とにかく機能が多くて便利に使えるシミュレータだと思います。
  1. 2011年09月14日 04:35 |
  2. マイコン関連
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示14(ディスプレイ回路のIPを登録)

Spartan-3A Starter KitでEDKを使ってカメラ表示13(ディスプレイ回路のHDLファイル)”の続き。

前回はカメラ回路とIPICのインターフェース部分を作り、テストベンチも作ってシミュレーションを行った。今回は、user_logic.vhd にDisp_Controller_Top.vhd のインスタンスを接続して、カスタムIPとして登録する。

最初に、user_logic.vhd にDisp_Controller_Topのインスタンスを接続した。その一部を下に示す。

    -- Master Read (Disp_Controller_Top.vhd)
    Disp_Controller_Top : Disp_Cont_Top generic map(
        C_SLV_DWIDTH => C_SLV_DWIDTH,
        C_MST_AWIDTH => C_MST_AWIDTH,
        C_MST_DWIDTH => C_MST_DWIDTH,
        C_NUM_REG => C_NUM_REG
    ) port map (
        red_out            => red_out,
        green_out        => green_out,
        blue_out        => blue_out,
        hsyncx            => hsyncx,
        vsyncx            => vsyncx,
        afifo_overflow    => afifo_overflow,
        afifo_underflow    => afifo_underflow,
        addr_is_zero    => addr_is_zero,
        h_v_is_zero        =>    h_v_is_zero,
        
        Bus2IP_Clk             => Bus2IP_Clk,
        Bus2IP_Reset         => Bus2IP_Reset,
        IP2Bus_MstRd_Req     => IP2Bus_MstRd_Req,
        IP2Bus_MstWr_Req     => IP2Bus_MstWr_Req,
        IP2Bus_Mst_Addr     => IP2Bus_Mst_Addr,
        IP2Bus_Mst_BE         => IP2Bus_Mst_BE,
        IP2Bus_Mst_Length     => IP2Bus_Mst_Length,
        IP2Bus_Mst_Type     => IP2Bus_Mst_Type,
        IP2Bus_Mst_Lock     => IP2Bus_Mst_Lock,
        IP2Bus_Mst_Reset     => IP2Bus_Mst_Reset,
        Bus2IP_Mst_CmdAck     => Bus2IP_Mst_CmdAck,
        Bus2IP_Mst_Cmplt     => Bus2IP_Mst_Cmplt,
        Bus2IP_Mst_Error     => Bus2IP_Mst_Error,
        Bus2IP_Mst_Rearbitrate => Bus2IP_Mst_Rearbitrate,
        Bus2IP_Mst_Cmd_Timeout => Bus2IP_Mst_Cmd_Timeout,
        Bus2IP_MstRd_d         => Bus2IP_MstRd_d,
        Bus2IP_MstRd_rem    => Bus2IP_MstRd_rem,
        Bus2IP_MstRd_sof_n    => Bus2IP_MstRd_sof_n,
        Bus2IP_MstRd_eof_n    => Bus2IP_MstRd_eof_n,
        Bus2IP_MstRd_src_rdy_n => Bus2IP_MstRd_src_rdy_n,
        Bus2IP_MstRd_src_dsc_n => Bus2IP_MstRd_src_dsc_n,
        IP2Bus_MstRd_dst_rdy_n => IP2Bus_MstRd_dst_rdy_n,
        IP2Bus_MstRd_dst_dsc_n => IP2Bus_MstRd_dst_dsc_n,

        IP2Bus_MstWr_d        => IP2Bus_MstWr_d,
        IP2Bus_MstWr_rem    => IP2Bus_MstWr_rem,
        IP2Bus_MstWr_sof_n    => IP2Bus_MstWr_sof_n,
        IP2Bus_MstWr_eof_n    => IP2Bus_MstWr_eof_n,
        IP2Bus_MstWr_src_rdy_n => IP2Bus_MstWr_src_rdy_n,
        IP2Bus_MstWr_src_dsc_n => IP2Bus_MstWr_src_dsc_n
    );


次に、”XPSのカスタムIPにCore Generatorで生成したIPのネットリストを追加する”を参考にして、XPSのカスタムIPに自分で作った回路や、Core Generatorで生成したIPのネットリストを追加する。

・MPD(display_controller_v2_1_0.mpd)ファイルに”OPTION STYLE = MIX”を追加した。一部を下に示す。

###################################################################
##
## Name : display_controller
## Desc : Microprocessor Peripheral Description
## : Automatically generated by PsfUtility
##
###################################################################

BEGIN display_controller

## Peripheral Options
OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION HDL = VHDL
OPTION IP_GROUP = MICROBLAZE:PPC:USER
OPTION DESC = DISPLAY_CONTROLLER
OPTION ARCH_SUPPORT_MAP = (others=DEVELOPMENT)
OPTION STYLE = MIX


・CamDisp_EDK_OV7670\system\pcores\display_controller_v1_00_a\dataフォルダの下に、camera_controller_v2_1_0.bbdを作った。ファイルの内容を下に示す。

FILES
cam_data_afifo.ngc


Spa3A_SKit_OV7670_68_110913.png

・CamDisp_EDK_OV7670\system\pcores\display_controller_v1_00_aフォルダの下に netlist フォルダを作って、その中に、cam_data_afifo.ngc をコピーした。
Spa3A_SKit_OV7670_69_110913.png

・CamDisp_EDK_OV7670\system\pcores\display_controller_v1_00_a\dataフォルダのdisplay_controller_v2_1_0.pao ファイルを以下のように書き換えた。

##############################################################################
## Filename: H:/HDL/FndtnISEWork/Spartan3A_starter_kit/CamDisp_EDK_OV7670/system/pcores/display_controller_v1_00_a/data/display_controller_v2_1_0.pao
## Description: Peripheral Analysis Order
## Date: Sun Aug 21 18:03:25 2011 (by Create and Import Peripheral Wizard)
##############################################################################

lib proc_common_v3_00_a all
lib plbv46_slave_single_v1_01_a all
lib plbv46_master_burst_v1_01_a all
lib display_controller_v1_00_a user_logic vhdl
lib display_controller_v1_00_a display_controller vhdl
lib display_controller_v1_00_a Disp_Controller_Top.vhd vhdl
lib display_controller_v1_00_a dcm_DISP_clk.v verilog
lib display_controller_v1_00_a VGA_Display_Controller.v verilog
lib display_controller_v1_00_a cam_data_afifo vhdl


インクルードファイルのdisp_timing_parameters.vhは、どうしようか?迷ったが、.vhの拡張子のままではverilogファイルと認識してくれないかもしれないので、同じフォルダにあってインクルードしてくれることを期待して、display_controller_v2_1_0.paoには追加していない。

(2011/9/14:修正).paoファイルには拡張子がかけたので、disp_timing_parameters.vhもVerilogとして追加した。

(2011/9/17:修正)disp_timing_parameters.vhの行は削除した。.paoのリストに入れているとエラーになる。cam_data_afifo が見つからないとエラーが出るので、VHDLフォルダにcam_data_afifo.vhdを入れて、.paoファイルに追加した。

vhdl, verilogフォルダには、display_controller_v2_1_0.paoに追加したファイルをすでに入れてあるので、これで終了とする。

(2011/9/15:追記)
display_controller.vhdのポート定義とポート接続が抜けていたので、追記する。
まずは、ポートの定義から下に示す。

entity display_controller is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_BASEADDR                     : std_logic_vector     := X"FFFFFFFF";
    C_HIGHADDR                     : std_logic_vector     := X"00000000";
    C_SPLB_AWIDTH                  : integer              := 32;
    C_SPLB_DWIDTH                  : integer              := 128;
    C_SPLB_NUM_MASTERS             : integer              := 8;
    C_SPLB_MID_WIDTH               : integer              := 3;
    C_SPLB_NATIVE_DWIDTH           : integer              := 32;
    C_SPLB_P2P                     : integer              := 0;
    C_SPLB_SUPPORT_BURSTS          : integer              := 0;
    C_SPLB_SMALLEST_MASTER         : integer              := 32;
    C_SPLB_CLK_PERIOD_PS           : integer              := 10000;
    C_INCLUDE_DPHASE_TIMER         : integer              := 1;
    C_FAMILY                       : string               := "virtex6";
    C_MPLB_AWIDTH                  : integer              := 32;
    C_MPLB_DWIDTH                  : integer              := 128;
    C_MPLB_NATIVE_DWIDTH           : integer              := 32;
    C_MPLB_P2P                     : integer              := 0;
    C_MPLB_SMALLEST_SLAVE          : integer              := 32;
    C_MPLB_CLK_PERIOD_PS           : integer              := 10000
    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
    -- ADD USER PORTS ABOVE THIS LINE ------------------
    red_out        : out std_logic_vector(3 downto 0);
    green_out    : out std_logic_vector(3 downto 0);
    blue_out    : out std_logic_vector(3 downto 0);
    hsyncx        : out std_logic;
    vsyncx        : out std_logic;
    afifo_overflow    : out std_logic;
    afifo_underflow    : out std_logic;
    addr_is_zero    : out std_logic;
    h_v_is_zero        : out std_logic

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol ports, do not add to or delete
    SPLB_Clk                       : in  std_logic;
    SPLB_Rst                       : in  std_logic;


次にポート接続を下に示す。

  USER_LOGIC_I : entity display_controller_v1_00_a.user_logic
    generic map
    (
      -- MAP USER GENERICS BELOW THIS LINE ---------------
      --USER generics mapped here
      -- MAP USER GENERICS ABOVE THIS LINE ---------------

      C_SLV_DWIDTH                   => USER_SLV_DWIDTH,
      C_MST_AWIDTH                   => USER_MST_AWIDTH,
      C_MST_DWIDTH                   => USER_MST_DWIDTH,
      C_NUM_REG                      => USER_NUM_REG
    )
    port map
    (
      -- MAP USER PORTS BELOW THIS LINE ------------------
      --USER ports mapped here
        red_out            => red_out,
        green_out        => green_out,
        blue_out        => blue_out,
        hsyncx            => hsyncx,
        vsyncx            => vsyncx,
        afifo_overflow    => afifo_overflow,
        afifo_underflow    => afifo_underflow,
        addr_is_zero    => addr_is_zero,
        h_v_is_zero        =>    h_v_is_zero,
     -- MAP USER PORTS ABOVE THIS LINE ------------------

      Bus2IP_Clk                     => ipif_Bus2IP_Clk,
      Bus2IP_Reset                   => ipif_Bus2IP_Reset,


  1. 2011年09月13日 04:47 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

”ワクワクするArduinoワークショップ ~新入門編~”のセミナに参加してきました

今日は、はんだづけカフェに行って、”ワクワクするArduinoワークショップ ~新入門編~”のセミナに参加してきました。

最初に、Arduino.ccからIDEをダウンロードして、ドライバをインストールしました。IDEを立ち上げて、Arduinoのプログラムをコンパイルします。
IDEを立ち上げ、Arduino上のLEDのブリンクを行いました。Arduinoのプログラムはsetup()とloop()の2つの関数で行うのだそうです。setup()は最初に1回実行するそうです。loop()で書くと、関数を繰り返し実行するとのことでした。

LEDブリンクはsetup()にpinMode()を書いて、ピンを出力に設定して、loop()のdigitalWrite()でHIGHとLOWを交互にポートに書くというものでした。HIGHやLOWを設定した後は、delay(1000);で1秒Waitします。
簡単です。

1.スイッチ入力を使ったLED点滅

2.ボリュームの電圧をA/Dコンバータ入力を使用して測定し、それに応じてPWMでLEDの明るさを変える

3.温度センサーを利用した温度の表示

4.スピーカーから音や音楽を出す

そんな感じでした。とても良くわかって、良いセミナでした。ライブラリが充実していて、簡単にいろんなことができそうです。Arduinoのことを知らなかったので、勉強になりました。後で購入して職場で勉強会してみようと思いました。
  1. 2011年09月11日 20:52 |
  2. マイコン関連
  3. | トラックバック:0
  4. | コメント:0

VHDLのgenericの値を下位モジュールのVerilogのparameterとして渡す

今回、VHDLからVerilogに値を渡すのにどうしようか?迷った。具体的には、VHDLのgeneric文で書いた値を、Verilogで書かれた下位モジュールにどうやって渡すかということだ。

Verilogのみだったら、”Verilogでincludeを使用せずにパラメータをポート宣言に使う”に書いてあるが、VHDLが上位モジュールでVerilogが下位モジュールの場合は未経験だった。
XSTユーザーガイド(Virtex-4 、Virtex-5 、Spartan-3 および CPLD デバイス用)”の569ページの”混合言語サポートの概要”に、

VHDL デザインでは、VHDL タイプ、ジェネリック、およびポートの制限されたサブセットを Verilog モジュールとの境界に使用できます。


と書いてあるので、どうやらできそうだということがわかった。

実際に、Disp_Controller_Top.vhd で、VGA_Display_Controller.v をインスタンスしてみた。
Disp_Controller_Top.vhd のインスタンシエーションを下に示す。

architecture RTL of Disp_Controller_Top is
constant    DDR2_SDRAM_ADDR_START    : std_logic_vector(31 downto 0) := x"46000000"; -- 32MB目から1MBを使用する。
constant    TRANSFER_LENGTH            : integer := 128;

...

    VGA_Disp_Cont_inst : VGA_Display_Controller generic map(
        AFIFO_FULL_VAL        => TRANSFER_LENGTH*2,
        AFIFO_HALF_FULL_VAL    => TRANSFER_LENGTH
    ) port map (
        clk_disp        => clk_disp,
        clk_ddr2        => Bus2IP_Clk,
        reset_disp        => reset_disp,
        reset_ddr2        => Bus2IP_Reset,
        request            => request,
        grant            => grant,
        address            => open,
        req_we            => req_we,
        addr_fifo_full    => '0',
        data_in            => Bus2IP_MstRd_d,
        data_valid        => Bus2IP_MstRd_src_rdy,
        red_out            => red,
        green_out        => green,
        blue_out        => blue,
        hsyncx            => hsyncx_node,
        vsyncx            => vsyncx_node,
        afifo_overflow    => afifo_overflow,
        afifo_underflow    => afifo_underflow,
        addr_is_zero    => addr_is_zero,
        h_v_is_zero        => h_v_is_zero
    );


インスタンスされたVGA_Display_Controller.v の一部分を下に示す。

module VGA_Display_Controller #(
    parameter AFIFO_FULL_VAL = 256,
    parameter AFIFO_HALF_FULL_VAL = 128
)
(
    input    wire    clk_disp,    // 25MHzのディスプレイ表示用クロック
    input    wire    clk_ddr2,    // 133.33MHzのDDR2 SDRAM用クロック
    input    wire    reset_disp,    // clk_disp 用リセット
    input    wire    reset_ddr2,    // clk_ddr2 用リセット
    output    reg        request,        // データ転送のrequest
    input    wire    grant,        // データ転送のgrant
    output    wire    [18:0]    address,    // DDR2 SDRAMのアドレス
    output    reg        req_we,        // Read要求のWrite Enable
    input    wire    addr_fifo_full,    // Read要求用FIFOのFULL
    input    wire    [31:0]    data_in,    // DDR2 SDRAMの画像データ(YUV)
    input    wire    data_valid,
    output    reg        [7:0]    red_out,
    output    reg        [7:0]    green_out,
    output    reg      [7:0]    blue_out,
    output    reg     hsyncx,
    output    reg     vsyncx,
    output    wire    afifo_overflow, // 非同期FIFO のオーバーフロー・エラー
    output    wire    afifo_underflow,    // 非同期FIFO のアンダーフロー・エラー
    output    reg        addr_is_zero,    // for test
    output    reg        h_v_is_zero        // for test
);


これで、VHDLのgeneric文で書いた値を、Verilogで書かれた下位モジュールにparameter 渡しで値を渡すことができた。
下に、ISimでVGA_Display_Controller.v のAFIFO_FULL_VAL, AFIFO_HALF_FULL_VALを見た場合を示す。
VHDL2Verilog_para_1_110911.png

Disp_Controller_Top.vhd の

AFIFO_HALF_FULL_VAL => TRANSFER_LENGTH



AFIFO_HALF_FULL_VAL => TRANSFER_LENGTH+1


に変更すると、ISimのコンスタント値も変更された。
VHDL2Verilog_para_2_110911.png

  1. 2011年09月11日 05:43 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示13(ディスプレイ回路のHDLファイル)

Spartan-3A Starter KitでEDKを使ってカメラ表示12(ディスプレイ回路のシミュレーション)”の続き。

今回は、下位モジュールを貼っておく。
まずは、VGA_Display_Controller.v 。

// VGA Display Controller
// SRAMから24MHz、16bit幅で2回に1回読みだされた輝度情報をRGBに変換してカラーで表示する
// UVデータを入力して、YUV-RGB変換を行う。変換式は以下のものを使用する
// R = (Y<<8 + "1_0110_0100"*V - X"B380")>>8
// G = (Y<<8 - "1011_0111"*V - "0101_1000"*U + X"8780")>>8
// B = (Y<<8 + "1_1100_0110"*U - X"E300")>>8
// 上の式で計算を行う。ビット長は19ビット
// YUVデータ保存用非同期FIFO, Wirte側32ビット幅128深度、Read側16ビット256深度とする。これはAFIFO_FULL_VALにwr_data_countに達したときにリクエストを止めると、その時点で要求されていたRead要求分のデータが帰ってくるためである
// RGB444用に変更

`default_nettype none

// synthesis translate_off
// `include "std_ovl_defines.h"
// synthesis translate_on

module VGA_Display_Controller #(
    parameter AFIFO_FULL_VAL = 256,
    parameter AFIFO_HALF_FULL_VAL = 128
)
(
    input    wire    clk_disp,    // 25MHzのディスプレイ表示用クロック
    input    wire    clk_ddr2,    // 133.33MHzのDDR2 SDRAM用クロック
    input    wire    reset_disp,    // clk_disp 用リセット
    input    wire    reset_ddr2,    // clk_ddr2 用リセット
    output    reg        request,        // データ転送のrequest
    input    wire    grant,        // データ転送のgrant
    output    wire    [18:0]    address,    // DDR2 SDRAMのアドレス
    output    reg        req_we,        // Read要求のWrite Enable
    input    wire    addr_fifo_full,    // Read要求用FIFOのFULL
    input    wire    [31:0]    data_in,    // DDR2 SDRAMの画像データ(YUV)
    input    wire    data_valid,
    output    reg        [7:0]    red_out,
    output    reg        [7:0]    green_out,
    output    reg      [7:0]    blue_out,
    output    reg     hsyncx,
    output    reg     vsyncx,
    output    wire    afifo_overflow, // 非同期FIFO のオーバーフロー・エラー
    output    wire    afifo_underflow,    // 非同期FIFO のアンダーフロー・エラー
    output    reg        addr_is_zero,    // for test
    output    reg        h_v_is_zero        // for test
);
    `include "./disp_timing_parameters.vh"
    
    // parameter AFIFO_FULL_VAL = 10'b01_0000_0000; // Write側の値。Write側は32ビットなので、64でRead側は128となる
    // parameter AFIFO_HALF_FULL_VAL = 10'b00_1000_0000; // Write側の値。Write側は32ビットなので、32でRead側は64となる
    
    parameter [3:0]    idle_rdg=            4'b0001,
                    init_full_mode=        4'b0010,
                    wait_half_full=        4'b0100,
                    req_burst=            4'b1000;
    reg    [3:0] cs_rdg;
    parameter [1:0]    req_we_low=        2'b01,
                    req_we_high=    2'b10; // active
    reg [1:0] cs_vrw;
    reg afifo_rd_en;
    wire [15:0] afifo_dout;
    wire afifo_full;
    wire afifo_empty;
    wire [9:0] wr_data_count;
    reg [18:0] addr_count;
    wire hv_count_enable;
    reg [9:0] read_count;
    reg hv_cnt_ena_d1, hv_cnt_ena_d2;
    reg [10:0] h_count;
    reg [9:0] v_count;
    reg [7:0] red_node, green_node, blue_node;
    reg hsyncx_node, vsyncx_node;
    reg [15:0] RGBX;
    reg addr_is_zero_node, h_v_is_zero_node;
    
    parameter VGA_CON_STAR_ADDR = 8;
    
    // synthesis translate_off
//    wire [`OVL_FIRE_WIDTH-1:0] fire_overflow, fire_underflow;
    // synthesis translate_on
    
    // YUVデータ保存用非同期FIFO, Wirte側32ビット幅128深度、Read側16ビット256深度とする
    cam_data_afifo camd_afifo_inst (
        .rst(reset_ddr2),
        .wr_clk(clk_ddr2),
        .rd_clk(clk_disp),
        .din(data_in), // Bus [31 : 0] 
        .wr_en(data_valid),
        .rd_en(afifo_rd_en),
        .dout(afifo_dout), // Bus [15 : 0] 
        .full(afifo_full),
        .overflow(afifo_overflow),
        .empty(afifo_empty),
        .underflow(afifo_underflow),
        .wr_data_count(wr_data_count) // ouput [9 : 0] wr_data_count
    );
    
    // DDR2 SDRAMのアドレスカウンタ(DDR2 SDRAMクロックドメイン)カウンタの単位は16ビット=1画素(UYまたはVY)
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            addr_count <= VGA_CON_STAR_ADDR;
        else begin
            if (addr_count>=(H_ACTIVE_VIDEO * V_ACTIVE_VIDEO)) // 1フレーム分描画終了したので、0にクリアする
                addr_count <= 0;
            else if (req_we) // DDR2 SDRAMへのRead要求のweがでたらカウントアップ
                addr_count <= addr_count + 19'd4; // DDR2 SDRAMは4バーストするので、+4
        end
    end
    assign address = addr_count;
    
    // Read コマンド生成モジュール
    
    // Read コマンド生成モジュール用ステートマシン
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            cs_rdg <= idle_rdg;
        else begin
            case (cs_rdg)
                idle_rdg :
                    cs_rdg <= init_full_mode;
                init_full_mode : // 最初にcam_data_afifo をFULLにするステート、このステートではVGA信号は出力しないで、ひたすらcam_data_afifo がFULLになるのを待つ。
                    if (wr_data_count>=AFIFO_FULL_VAL)
                        cs_rdg <= wait_half_full;
                    else
                        cs_rdg <= init_full_mode;
                wait_half_full : // cam_data_afifo がHALF_FULLになるまでこのステートで待機
                    if (wr_data_count<=AFIFO_HALF_FULL_VAL)
                        cs_rdg <= req_burst;
                    else
                        cs_rdg <= wait_half_full;
                req_burst :
                    if (read_count==0 && wr_data_count>AFIFO_HALF_FULL_VAL) // VRAMのREAD要求をカウントするカウンタが0になって、wr_data_count がHALF_FULL以上になったら
                        cs_rdg <= wait_half_full;
                    else
                        cs_rdg <= req_burst;
            endcase
        end
    end
    assign hv_count_enable = (cs_rdg==wait_half_full || cs_rdg==req_burst) ? 1'b1 : 1'b0;
    
    // request の実装。VRAMのデータをReadしたいときにアクティベート。アービタへ
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            request <= 1'b0;
        else begin
            if (cs_rdg==req_burst || cs_rdg==init_full_mode)
                request <= 1'b1;
            else
                request <= 1'b0;
        end
    end
    
    // read_count の実装、DDR2 SDRAM へのRead要求のカウントをする。
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            read_count <= AFIFO_HALF_FULL_VAL;
        else begin
            if (cs_rdg==wait_half_full)
                read_count <= AFIFO_HALF_FULL_VAL;
            else if (cs_rdg==req_burst) begin
                if (read_count!=0 && addr_fifo_full==1'b0) // 0になるまで、VRAMへの要求アドレスFIFOがFULLでない時に要求を書き込む
                    read_count <= read_count - 1;
            end
        end
    end
    
    // req_we の実装、req_we はクロック2回に1回出力する。こうすることによってaddr_fifo_full のみでも、req_we をFF出力とすることができる。READのレイテンシは長いので、2回に1回のRead要求発行でも問題ないはず。。。
    always @(posedge clk_ddr2) begin
        if (reset_ddr2) begin
            cs_vrw <= req_we_low;
            req_we <= 1'b0;
        end else begin
            case (cs_vrw)
                req_we_low :
                    if ((cs_rdg==req_burst || cs_rdg==init_full_mode) && read_count!=0 && ~addr_fifo_full && grant) begin // 最初にpixel_async_fifo をFULLにする時とHALFまで行ってFULLにするとき
                        cs_vrw <= req_we_high;
                        req_we <= 1'b1;
                    end
                req_we_high : begin
                    cs_vrw <= req_we_low;
                    req_we <= 1'b0;
                end
            endcase
        end
    end
    // Read コマンド生成モジュール,終了    
    
    // ビットマップVGAコントローラのclk_disp (25MHz)動作部
    
    // h_count、v_count用に133.33MHz動作のcs_rdg の値を使用するので2回25MHz動作のFFでラッチする
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            hv_cnt_ena_d1 <= 1'b0;
            hv_cnt_ena_d2 <= 1'b0;
        end else begin
            hv_cnt_ena_d1 <= hv_count_enable;
            hv_cnt_ena_d2 <= hv_cnt_ena_d1;
        end
    end
    
    // h_countの実装(水平カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            h_count <= 0;
        else if (h_count>=(H_SUM-1)) // h_count がH_SUM-1よりも大きければ0に戻す(mod H_SUM)
            h_count <= 0;
        else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
            h_count <= h_count + 11'd1;
    end
    
    // v_countの実装(垂直カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            v_count <= 0;
        else if (h_count>=(H_SUM-1)) begin // 水平カウンタがクリアされるとき
            if (v_count>=(V_SUM-1)) // v_count がV_SUM-1よりも大きければ0に戻す(mode V_SUM)
                v_count <= 0;
            else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
                v_count <= v_count + 10'd1;
        end
    end
    
    // RGBXを保存しておく
    always @(posedge clk_disp) begin // U
        if (reset_disp)
            RGBX <= 0;
        else
            RGBX <= afifo_dout;
    end

    // Red, Green, Blue出力
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_node <= 0;
            green_node <= 0;
            blue_node <= 0;
        end else begin
            if (~hv_cnt_ena_d2) begin // 最初にpixel_async_fifo がフルになるまで画像データを出力しない。
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) begin // 表示している期間のみ画像データを出力する R 11:8 G 15:12 B 7:4
                // red_node <= {RGBX[11:8], 4'b000};
                // green_node <= {RGBX[7:4], 4'b000};
                // blue_node <= {RGBX[3:0], 4'b000};
                red_node <= {RGBX[3:0], 4'b000};
                green_node <= {RGBX[7:4], 4'b000};
                blue_node <= {RGBX[11:8], 4'b000};
            end else begin
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end 
                
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_out <= 0;
            green_out <= 0;
            blue_out <= 0;
        end else begin
            red_out <= red_node;
            green_out <= green_node;
            blue_out <= blue_node;
        end
    end
    
    // hsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx_node <= 1'b1;
        else
            if (h_count>(H_ACTIVE_VIDEO + H_FRONT_PORCH-1) && h_count<=(H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE-1)) // 水平同期期間
                hsyncx_node <= 1'b0;
            else
                hsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx <= 1'b1;
        else
            hsyncx <= hsyncx_node;
    end
    
    // vsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx_node <= 1'b1;
        else
            if (v_count>(V_ACTIVE_VIDEO + V_FRONT_PORCH-1) && v_count<=(V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE-1)) // 垂直同期期間
                vsyncx_node <= 1'b0;
            else
                vsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx <= 1'b1;
        else
            vsyncx <= vsyncx_node;
    end
    
    // afifo_rd_en の処理
    always @(posedge clk_disp) begin
        if (reset_disp)
            afifo_rd_en <= 1'b0;
        else begin
            if (~hv_cnt_ena_d2) // 初期化中
                afifo_rd_en <= 1'b0;
            else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) // 表示期間
                afifo_rd_en <= 1'b1;
            else
                afifo_rd_en <= 1'b0;
        end
    end

    
    // アサーション
    // synthesis translate_off
    always @ (posedge clk_ddr2) begin
        if (reset_ddr2)
            ;
        else begin
            if (afifo_overflow) begin 
                $display("%m: at time %t ERROR : FIFOがフルなのにライトした",$time);
                $stop;
            end
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            ;
        else begin
            if (afifo_underflow) begin
                $display("%m: at time %t ERROR : FIFOが空なのにリードした",$time);
                $stop;
            end
        end
    end
    
    // ovl_never #(
        // `OVL_ERROR,            // severity_level
        // `OVL_ASSERT,        // property_type
        // "ERROR : FIFOがフルなのにライトした", // msg
        // `OVL_COVER_DEFAULT,    // coverage_level
        // `OVL_POSEDGE,        // clock_edge
        // `OVL_ACTIVE_HIGH,    // reset_polarity
        // `OVL_GATE_CLOCK    // gating_type
    // ) afifo_overflow_assertion (
        // clk_ddr2,
        // reset_ddr2,
        // 1'b1,
        // afifo_overflow,
        // fire_overflow
    // );
        
    // ovl_never #(
        // `OVL_ERROR,            // severity_level
        // `OVL_ASSERT,        // property_type
        // "ERROR : FIFOが空なのにリードした", // msg
        // `OVL_COVER_DEFAULT,    // coverage_level
        // `OVL_POSEDGE,        // clock_edge
        // `OVL_ACTIVE_HIGH,    // reset_polarity
        // `OVL_GATE_CLOCK    // gating_type
    // ) afifo_underflow_assertion (
        // clk_disp,
        // reset_disp,
        // 1'b1,
        // afifo_underflow,
        // fire_underflow
    // );
    // synthesis translate_on
    
    //  for test
    always @(posedge clk_ddr2) begin
        if (reset_ddr2) begin
            addr_is_zero_node <= 1'b0;
            addr_is_zero <= 1'b0;
        end else begin
            if (addr_count == 0)
                addr_is_zero_node <= 1'b1;
            else
                addr_is_zero_node <= 1'b0;
            addr_is_zero <= addr_is_zero_node;
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            h_v_is_zero_node <= 1'b0;
            h_v_is_zero <= 1'b0;
        end else begin
            if (h_count==0 && v_count==0)
                h_v_is_zero_node <= 1'b1;
            else
                h_v_is_zero_node <= 1'b0;
            h_v_is_zero <= h_v_is_zero_node;
        end
    end
            
endmodule

`default_nettype wire


次は、disp_timing_parameters.vh 。

// 表示タイミングの定義

parameter H_ACTIVE_VIDEO= 640;
parameter H_FRONT_PORCH = 16;
parameter H_SYNC_PULSE = 96;
parameter H_BACK_PORCH = 48;
parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

parameter V_ACTIVE_VIDEO = 480;
parameter V_FRONT_PORCH = 10;
parameter V_SYNC_PULSE = 2;
parameter V_BACK_PORCH = 29;
parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

parameter H_DISPLAY_SIZE = H_ACTIVE_VIDEO/8; // 横80桁
parameter V_DISPLAY_SIZE = V_ACTIVE_VIDEO/8; // 縦60行

parameter RED_DOT_POS = 9; // 9ビット目がRED
parameter GREEN_DOT_POS = 8; // 8ビット目がGREEN
parameter BLUE_DOT_POS = 7; // 7ビット目がBLUE


次は、dcm_DISP_clk.v 。

// DCM module
// 62.5MHzを入力して、25MHzの表示用のclkを生成する(VGA)。

`default_nettype none
`timescale 1ns / 1ps

(* KEEP_HIERARCHY = "TRUE" *)module dcm_DISP_clk (sysclk, reset, clk_disp, dcm_locked_out);
    input    wire    sysclk;
    input    wire    reset;
    output    wire    clk_disp;
    output    wire    dcm_locked_out;
    
    wire clk_bufg, clk_node, dcm1_locked;
    wire clk_cam_node, clk_cam_bufg;
        
    DCM dcm_DDR2_clk_dcm (
        .CLKIN(sysclk),
        .CLKFB(clk_bufg),
        .DSSEN(1'b0),
        .PSINCDEC(1'b0),
        .PSEN(1'b0),
        .PSCLK(1'b0),
        .RST(reset),     // 前段のDCMがロックするまでリセット
        .CLK0(clk_node),
        .CLK90(),
        .CLK180(),
        .CLK270(),
        .CLK2X(),
        .CLK2X180(),
        .CLKDV(),
        .CLKFX(clk_cam_node),
        .CLKFX180(),
        .LOCKED(dcm1_locked),
        .PSDONE(),
        .STATUS()
    );
    defparam dcm_DDR2_clk_dcm.CLKIN_PERIOD = 16.0;
    defparam dcm_DDR2_clk_dcm.DLL_FREQUENCY_MODE = "LOW";
    defparam dcm_DDR2_clk_dcm.DUTY_CYCLE_CORRECTION = "TRUE";
    defparam dcm_DDR2_clk_dcm.CLKDV_DIVIDE = 2.0;
    defparam dcm_DDR2_clk_dcm.PHASE_SHIFT = 0;
    defparam dcm_DDR2_clk_dcm.CLKOUT_PHASE_SHIFT = "NONE";
    defparam dcm_DDR2_clk_dcm.STARTUP_WAIT = "FALSE";
    defparam dcm_DDR2_clk_dcm.CLKFX_DIVIDE = 5;
    defparam dcm_DDR2_clk_dcm.CLKFX_MULTIPLY = 2;
    
    BUFG CLK_BUFG_INST (
        .I(clk_node),
        .O(clk_bufg)
    );
    
    BUFG CLK_CAM_BUFG_INST (
        .I(clk_cam_node),
        .O(clk_cam_bufg)
    );
    assign dcm_locked_out = dcm1_locked;
    assign clk_disp = clk_cam_bufg;
endmodule

`default_nettype wire


最後に、cam_data_afifo.xco 。

##############################################################
#
# Xilinx Core Generator version 13.2
# Date: Thu Sep 08 19:15:36 2011
#
##############################################################
#
# This file contains the customisation parameters for a
# Xilinx CORE Generator IP GUI. It is strongly recommended
# that you do not manually alter this file as it may cause
# unexpected and unsupported behavior.
#
##############################################################
#
# Generated from component: xilinx.com:ip:fifo_generator:6.1
#
##############################################################
#
# BEGIN Project Options
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = VHDL
SET device = xc3s700a
SET devicefamily = spartan3a
SET flowvendor = Foundation_ISE
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = fg484
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -4
SET verilogsim = false
SET vhdlsim = true
# END Project Options
# BEGIN Select
SELECT Fifo_Generator family Xilinx,_Inc. 6.1
# END Select
# BEGIN Parameters
CSET almost_empty_flag=false
CSET almost_full_flag=false
CSET component_name=cam_data_afifo
CSET data_count=false
CSET data_count_width=9
CSET disable_timing_violations=false
CSET dout_reset_value=0
CSET empty_threshold_assert_value=4
CSET empty_threshold_negate_value=5
CSET enable_ecc=false
CSET enable_int_clk=false
CSET enable_reset_synchronization=true
CSET fifo_implementation=Independent_Clocks_Block_RAM
CSET full_flags_reset_value=1
CSET full_threshold_assert_value=509
CSET full_threshold_negate_value=508
CSET inject_dbit_error=false
CSET inject_sbit_error=false
CSET input_data_width=32
CSET input_depth=512
CSET output_data_width=16
CSET output_depth=1024
CSET overflow_flag=true
CSET overflow_sense=Active_High
CSET performance_options=First_Word_Fall_Through
CSET programmable_empty_type=No_Programmable_Empty_Threshold
CSET programmable_full_type=No_Programmable_Full_Threshold
CSET read_clock_frequency=1
CSET read_data_count=false
CSET read_data_count_width=11
CSET reset_pin=true
CSET reset_type=Asynchronous_Reset
CSET underflow_flag=true
CSET underflow_sense=Active_High
CSET use_dout_reset=true
CSET use_embedded_registers=false
CSET use_extra_logic=true
CSET valid_flag=false
CSET valid_sense=Active_High
CSET write_acknowledge_flag=false
CSET write_acknowledge_sense=Active_High
CSET write_clock_frequency=1
CSET write_data_count=true
CSET write_data_count_width=10
# END Parameters
GENERATE
# CRC: 2418f0c5


次は、user_logic.vhd とDisp_Controller_Top.vhd を接続する。

  1. 2011年09月11日 05:12 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示12(ディスプレイ回路のシミュレーション)

Spartan-3A Starter KitでEDKを使ってカメラ表示11(ディスプレイ回路を作り始める)”の続きです。

Disp_Controller_Top.vhd、Disp_Controller_Top_tb.vhd を作って、シミュレーションしてみました。シミュレーションがうまく行ったら、Disp_Controller_Top.vhdをuser_logic.vhdに接続します。
Disp_Controller_Top.vhdを下に示す。

-- Disp_Controller_Top.vhd
-- VGA_Display_Controller.v のトップ
-- DDR2 SDRAM 64MBの内の真ん中から1MBを使用する。データバス幅は32ビット

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

library unisim;
use unisim.vcomponents.all;

entity Disp_Controller_Top is
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    port(
        red_out        : out std_logic_vector(3 downto 0);
        green_out    : out std_logic_vector(3 downto 0);
        blue_out    : out std_logic_vector(3 downto 0);
        hsyncx        : out std_logic;
        vsyncx        : out std_logic;
        
        Bus2IP_Clk                     : in  std_logic;
        Bus2IP_Reset                   : in  std_logic;
        IP2Bus_MstRd_Req               : out std_logic;
        IP2Bus_MstWr_Req               : out std_logic;
        IP2Bus_Mst_Addr                : out std_logic_vector(0 to C_MST_AWIDTH-1);
        IP2Bus_Mst_BE                  : out std_logic_vector(0 to C_MST_DWIDTH/8-1);
        IP2Bus_Mst_Length              : out std_logic_vector(0 to 11);
        IP2Bus_Mst_Type                : out std_logic;
        IP2Bus_Mst_Lock                : out std_logic;
        IP2Bus_Mst_Reset               : out std_logic;
        Bus2IP_Mst_CmdAck              : in  std_logic;
        Bus2IP_Mst_Cmplt               : in  std_logic;
        Bus2IP_Mst_Error               : in  std_logic;
        Bus2IP_Mst_Rearbitrate         : in  std_logic;
        Bus2IP_Mst_Cmd_Timeout         : in  std_logic;

        Bus2IP_MstRd_d                 : in  std_logic_vector(0 to C_MST_DWIDTH-1);
        Bus2IP_MstRd_rem               : in  std_logic_vector(0 to C_MST_DWIDTH/8-1);
        Bus2IP_MstRd_sof_n             : in  std_logic;
        Bus2IP_MstRd_eof_n             : in  std_logic;
        Bus2IP_MstRd_src_rdy_n         : in  std_logic;
        Bus2IP_MstRd_src_dsc_n         : in  std_logic;
        IP2Bus_MstRd_dst_rdy_n         : out std_logic;
        IP2Bus_MstRd_dst_dsc_n         : out std_logic;
        
        IP2Bus_MstWr_d                 : out std_logic_vector(0 to C_MST_DWIDTH-1);
        IP2Bus_MstWr_rem               : out std_logic_vector(0 to C_MST_DWIDTH/8-1);
        IP2Bus_MstWr_sof_n             : out std_logic;
        IP2Bus_MstWr_eof_n             : out std_logic;
        IP2Bus_MstWr_src_rdy_n         : out std_logic;
        IP2Bus_MstWr_src_dsc_n         : out std_logic;
        
        -- for test output
        afifo_overflow    : out std_logic;
        afifo_underflow    : out std_logic;
        addr_is_zero    : out std_logic;
        h_v_is_zero        : out std_logic
    );
end Disp_Controller_Top;

architecture RTL of Disp_Controller_Top is
constant    DDR2_SDRAM_ADDR_START    : std_logic_vector(31 downto 0) := x"46000000"; -- 32MB目から1MBを使用する。
constant    TRANSFER_LENGTH            : integer := 128;

component VGA_Display_Controller generic (
        AFIFO_FULL_VAL            : integer    := TRANSFER_LENGTH*2;
        AFIFO_HALF_FULL_VAL    : integer    := TRANSFER_LENGTH
    );
    port(
        clk_disp            : in std_logic;
        clk_ddr2        : in std_logic;
        reset_disp        : in std_logic;
        reset_ddr2        : in std_logic;
        request            : out std_logic;
        grant            : in std_logic;
        address            : out std_logic_vector(18 downto 0);
        req_we            : out std_logic;
        addr_fifo_full    : in std_logic;
        data_in            : in std_logic_vector(31 downto 0);
        data_valid        : in std_logic;
        red_out            : out std_logic_vector(7 downto 0);
        green_out         : out std_logic_vector(7 downto 0);
        blue_out        : out std_logic_vector(7 downto 0);
        hsyncx            : out std_logic;
        vsyncx            : out std_logic;
        afifo_overflow    : out std_logic;
        afifo_underflow    : out std_logic;
        addr_is_zero    : out std_logic;
        h_v_is_zero        : out std_logic
    );
end component;

component dcm_DISP_clk
    port(
        sysclk            : in std_logic;
        reset            : in std_logic;
        clk_disp            : out std_logic;
        dcm_locked_out    : out std_logic
    );
end component;

signal clk_disp : std_logic;
signal reset_disp : std_logic;
signal reset_disp_node : std_logic;
signal reset_disp_srl, reset_disp_srl_1d, reset_disp_srl_2d : std_logic;
signal Bus2IP_MstRd_src_rdy : std_logic;
signal hsyncx_node, vsyncx_node : std_logic;
signal dcm_locked : std_logic;
signal request, grant : std_logic;
signal req_we : std_logic;
type DISP_RD_STATE is (IDLE_DISP_RD, DISP_RD_COUNT_SET, MST_RD_CONTINUED);
signal cs_disp_rd : DISP_RD_STATE;
signal disp_rd_count : std_logic_vector(7 downto 0);
type RD_STATE is (IDLE_RD, TRANS_COUNT_SET, MPMC_RD_ST);
signal cs_rd : RD_STATE;
type CMD_STATE is (IDLE_CMD, CMD_ASSORT, WAIT_TRANSACTION);
signal cs_cmd : CMD_STATE;
signal trans_count : std_logic_vector(4 downto 0);
signal addr_cnt, mst_addr : std_logic_vector(C_MST_AWIDTH-1 downto 0);
signal red, green, blue : std_logic_vector(7 downto 0);
signal rd_dst_rdy : std_logic;

begin
    IP2Bus_Mst_Lock        <= '0';
    IP2Bus_Mst_Reset    <= '0';
    -- Master Write 信号の処理
    IP2Bus_MstWr_Req    <= '0';
    IP2Bus_MstWr_d        <= (others => '0');
    IP2Bus_MstWr_rem    <= (others => '0');
    IP2Bus_MstWr_sof_n    <= '1';
    IP2Bus_MstWr_eof_n    <= '1';
    IP2Bus_MstWr_src_rdy_n    <= '1';
    IP2Bus_MstWr_src_dsc_n    <= '1';
    
    dcm_DISP_clk_inst : dcm_DISP_clk port map(
        sysclk            => Bus2IP_Clk,
        reset             => Bus2IP_Reset,
        clk_disp         => clk_disp,
        dcm_locked_out    => dcm_locked
    );
    reset_disp_node <= not dcm_locked;
    
    -- reset_disp を16クロック遅延される。クロックが出始めてすぐ、dcm_lockedが1になるため同期リセットFFがリセットされない。
    SRL16E_SDA_ena : SRL16E generic map(
        INIT => X"0000")
    port map(
        Q => reset_disp_srl,
        A0 => '1',
        A1 => '1',
        A2 => '1',
        A3 => '1',
        CE => '1',
        CLK => Bus2IP_Clk,
        D => reset_disp_node
    ); 
    
    -- clk_disp で同期化
    process(clk_disp) begin
        if clk_disp'event and clk_disp='1' then
            reset_disp_srl_1d <= reset_disp_srl;
            reset_disp_srl_2d <= reset_disp_srl_1d;
        end if;
    end process;
    reset_disp <= reset_disp_srl_2d;
    
    Bus2IP_MstRd_src_rdy <= not Bus2IP_MstRd_src_rdy_n;
    VGA_Disp_Cont_inst : VGA_Display_Controller generic map(
        AFIFO_FULL_VAL        => TRANSFER_LENGTH*2,
        AFIFO_HALF_FULL_VAL    => TRANSFER_LENGTH
    ) port map (
        clk_disp        => clk_disp,
        clk_ddr2        => Bus2IP_Clk,
        reset_disp        => reset_disp,
        reset_ddr2        => Bus2IP_Reset,
        request            => request,
        grant            => grant,
        address            => open,
        req_we            => req_we,
        addr_fifo_full    => '0',
        data_in            => Bus2IP_MstRd_d,
        data_valid        => Bus2IP_MstRd_src_rdy,
        red_out            => red,
        green_out        => green,
        blue_out        => blue,
        hsyncx            => hsyncx_node,
        vsyncx            => vsyncx_node,
        afifo_overflow    => afifo_overflow,
        afifo_underflow    => afifo_underflow,
        addr_is_zero    => addr_is_zero,
        h_v_is_zero        => h_v_is_zero
    );
    red_out        <= red(7 downto 4);
    green_out    <= green(7 downto 4);
    blue_out    <= blue(7 downto 4);
    hsyncx <= hsyncx_node;
    vsyncx <= vsyncx_node;
    
    -- ディスプレイ回路のrequest の処理。128ワード必要なので、16バーストを8回行う
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_disp_rd <= IDLE_DISP_RD;
                grant <= '0';
            else
                case cs_disp_rd is
                    when IDLE_DISP_RD =>
                        if request='1' then
                            cs_disp_rd <= DISP_RD_COUNT_SET;
                        end if;
                    when DISP_RD_COUNT_SET =>
                        cs_disp_rd <= MST_RD_CONTINUED;
                        grant <= '1';
                    when MST_RD_CONTINUED =>
                        if disp_rd_count=1 and Bus2IP_MstRd_src_rdy='1' then
                            cs_disp_rd <= IDLE_DISP_RD;
                            grant <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    -- disp_rd_count の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                disp_rd_count <= (others => '0');
            else
                if cs_disp_rd=DISP_RD_COUNT_SET then
                    disp_rd_count <= CONV_STD_LOGIC_VECTOR(TRANSFER_LENGTH, 8);
                elsif cs_rd=MPMC_RD_ST and Bus2IP_MstRd_src_rdy_n='0' then
                    disp_rd_count <= disp_rd_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- マスタRead用ステートマシン, 16バースト転送
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_rd <= IDLE_RD;
                rd_dst_rdy <= '0';
            else
                case cs_rd is
                    when IDLE_RD =>
                        if cs_disp_rd=MST_RD_CONTINUED and cs_cmd=IDLE_CMD then
                            cs_rd <= TRANS_COUNT_SET;
                            rd_dst_rdy <= '0';
                        end if;
                    when TRANS_COUNT_SET =>
                        cs_rd <= MPMC_RD_ST;
                        rd_dst_rdy <= '1';
                    when MPMC_RD_ST =>
                        if trans_count=1 and Bus2IP_MstRd_src_rdy='1' then
                            cs_rd <= IDLE_RD;
                            rd_dst_rdy <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    IP2Bus_MstRd_dst_rdy_n <= not rd_dst_rdy;
    
    IP2Bus_Mst_BE <= (others => '1');
    IP2Bus_MstRd_dst_dsc_n <= '1';
    
    -- コマンド用ステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd <= IDLE_CMD;
                IP2Bus_MstRd_Req <= '0';
                IP2Bus_Mst_Type <= '0';
            else
                case cs_cmd is
                    when IDLE_CMD =>
                        if cs_rd=TRANS_COUNT_SET then
                            cs_cmd <= CMD_ASSORT;
                            IP2Bus_MstRd_Req <= '1';
                            IP2Bus_Mst_Type <= '1';
                        end if;
                    when CMD_ASSORT =>
                        if Bus2IP_Mst_CmdAck='1' then
                            cs_cmd <= WAIT_TRANSACTION;
                            IP2Bus_MstRd_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                    when WAIT_TRANSACTION =>
                        if Bus2IP_Mst_Cmplt='1' then
                            cs_cmd <= IDLE_CMD;
                            IP2Bus_MstRd_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    -- trans_countの処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                trans_count <= (others => '0');
                IP2Bus_Mst_Length <= CONV_STD_LOGIC_VECTOR(64, 12); -- 128バイト、32ビット幅、16バースト
            else
                if cs_rd=TRANS_COUNT_SET then
                    if disp_rd_count>=16 then
                        trans_count <= CONV_STD_LOGIC_VECTOR(16,5);
                        IP2Bus_Mst_Length <= CONV_STD_LOGIC_VECTOR(64, 12); -- 128バイト、32ビット幅、16バースト
                    else -- 転送の残りが16以下
                        trans_count <= disp_rd_count(4 downto 0);
                        IP2Bus_Mst_Length <= "0000000" & disp_rd_count(4 downto 0);
                    end if;
                elsif cs_rd=MPMC_RD_ST and Bus2IP_MstRd_src_rdy_n='0' then
                    trans_count <= trans_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- addr_cnt の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                addr_cnt <= DDR2_SDRAM_ADDR_START;
            else
                if vsyncx_node='0' then
                    addr_cnt <= DDR2_SDRAM_ADDR_START;
                elsif rd_dst_rdy='1' and Bus2IP_MstRd_src_rdy_n='0' then
                    addr_cnt <= addr_cnt + 4;
                end if;
            end if;
        end if;
    end process;
    
    -- mst_addr の処理、コマンド転送の初めにaddr_cnt をmst_addr にコピーする
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_addr <= DDR2_SDRAM_ADDR_START;
            else
                if cs_rd=TRANS_COUNT_SET then
                    mst_addr <= addr_cnt;
                end if;
            end if;
        end if;
    end process;
    
    IP2Bus_Mst_Addr <= mst_addr;

end RTL;


次に、Disp_Controller_Top_tb.vhdを下に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY Disp_Controller_Top_tb IS
END Disp_Controller_Top_tb;
 
ARCHITECTURE behavior OF Disp_Controller_Top_tb IS 
    constant C_MST_DWIDTH : integer := 32;

    -- wait を入れるバースト位置、バーストの最初と最後でwaitすることはできない。0を入れるとwaitはなしになる
    constant    RDY_WAIT_VAL1    : integer := 10;
    constant    RDY_WAIT_VAL2    : integer := 5;
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT Disp_Controller_Top
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    PORT(
         red_out : OUT  std_logic_vector(3 downto 0);
         green_out : OUT  std_logic_vector(3 downto 0);
         blue_out : OUT  std_logic_vector(3 downto 0);
         hsyncx : OUT  std_logic;
         vsyncx : OUT  std_logic;
         Bus2IP_Clk : IN  std_logic;
         Bus2IP_Reset : IN  std_logic;
         IP2Bus_MstRd_Req : OUT  std_logic;
         IP2Bus_MstWr_Req : OUT  std_logic;
         IP2Bus_Mst_Addr : OUT  std_logic_vector(0 to 31);
         IP2Bus_Mst_BE : OUT  std_logic_vector(0 to 3);
         IP2Bus_Mst_Length : OUT  std_logic_vector(0 to 11);
         IP2Bus_Mst_Type : OUT  std_logic;
         IP2Bus_Mst_Lock : OUT  std_logic;
         IP2Bus_Mst_Reset : OUT  std_logic;
         Bus2IP_Mst_CmdAck : IN  std_logic;
         Bus2IP_Mst_Cmplt : IN  std_logic;
         Bus2IP_Mst_Error : IN  std_logic;
         Bus2IP_Mst_Rearbitrate : IN  std_logic;
         Bus2IP_Mst_Cmd_Timeout : IN  std_logic;
         Bus2IP_MstRd_d : IN  std_logic_vector(0 to 31);
         Bus2IP_MstRd_rem : IN  std_logic_vector(0 to 3);
         Bus2IP_MstRd_sof_n : IN  std_logic;
         Bus2IP_MstRd_eof_n : IN  std_logic;
         Bus2IP_MstRd_src_rdy_n : IN  std_logic;
         Bus2IP_MstRd_src_dsc_n : IN  std_logic;
         IP2Bus_MstRd_dst_rdy_n : OUT  std_logic;
         IP2Bus_MstRd_dst_dsc_n : OUT  std_logic;
         IP2Bus_MstWr_d : OUT  std_logic_vector(0 to 31);
         IP2Bus_MstWr_rem : OUT  std_logic_vector(0 to 3);
         IP2Bus_MstWr_sof_n : OUT  std_logic;
         IP2Bus_MstWr_eof_n : OUT  std_logic;
         IP2Bus_MstWr_src_rdy_n : OUT  std_logic;
         IP2Bus_MstWr_src_dsc_n : OUT  std_logic;
         afifo_overflow : OUT  std_logic;
         afifo_underflow : OUT  std_logic;
         addr_is_zero : OUT  std_logic;
         h_v_is_zero : OUT  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal Bus2IP_Clk : std_logic := '0';
   signal Bus2IP_Reset : std_logic := '0';
   signal Bus2IP_Mst_CmdAck : std_logic := '0';
   signal Bus2IP_Mst_Cmplt : std_logic := '0';
   signal Bus2IP_Mst_Error : std_logic := '0';
   signal Bus2IP_Mst_Rearbitrate : std_logic := '0';
   signal Bus2IP_Mst_Cmd_Timeout : std_logic := '0';
   signal Bus2IP_MstRd_d : std_logic_vector(0 to 31) := (others => '0');
   signal Bus2IP_MstRd_rem : std_logic_vector(0 to 3) := (others => '0');
   signal Bus2IP_MstRd_sof_n : std_logic := '1';
   signal Bus2IP_MstRd_eof_n : std_logic := '1';
   signal Bus2IP_MstRd_src_rdy_n : std_logic := '1';
   signal Bus2IP_MstRd_src_dsc_n : std_logic := '1';

     --Outputs
   signal red_out : std_logic_vector(3 downto 0);
   signal green_out : std_logic_vector(3 downto 0);
   signal blue_out : std_logic_vector(3 downto 0);
   signal hsyncx : std_logic;
   signal vsyncx : std_logic;
   signal IP2Bus_MstRd_Req : std_logic;
   signal IP2Bus_MstWr_Req : std_logic;
   signal IP2Bus_Mst_Addr : std_logic_vector(0 to 31);
   signal IP2Bus_Mst_BE : std_logic_vector(0 to 3);
   signal IP2Bus_Mst_Length : std_logic_vector(0 to 11);
   signal IP2Bus_Mst_Type : std_logic;
   signal IP2Bus_Mst_Lock : std_logic;
   signal IP2Bus_Mst_Reset : std_logic;
   signal IP2Bus_MstRd_dst_rdy_n : std_logic;
   signal IP2Bus_MstRd_dst_dsc_n : std_logic;
   signal IP2Bus_MstWr_d : std_logic_vector(0 to 31);
   signal IP2Bus_MstWr_rem : std_logic_vector(0 to 3);
   signal IP2Bus_MstWr_sof_n : std_logic;
   signal IP2Bus_MstWr_eof_n : std_logic;
   signal IP2Bus_MstWr_src_rdy_n : std_logic;
   signal IP2Bus_MstWr_src_dsc_n : std_logic;
   signal afifo_overflow : std_logic;
   signal afifo_underflow : std_logic;
   signal addr_is_zero : std_logic;
   signal h_v_is_zero : std_logic;

   type CMD_ACK_STATE is (IDLE_CMD_ACK, CMD_TRANS_1, CMD_TRANS_2, CMD_TRANS_3, CMD_TRANS_4, CMD_ACK_ST);
   signal cs_cmd_ack : CMD_ACK_STATE;
   signal cmd_ack : std_logic;
   type DATA_RD_STATE is (IDLE_DATA_RD, SOF_ASSORT, RD_DATA_OUT, EOF_ASSORT, RD_DATA_COMPLT);
   signal cs_data_rd : DATA_RD_STATE;
   signal trans_count : std_logic_vector(4 downto 0);
   signal data : std_logic_vector(31 downto 0);
   signal mst_rd_rdy, mst_rd_rdy_1d : std_logic;
   
   -- Clock period definitions
   constant Bus2IP_Clk_period : time := 16 ns; -- 62.5MHz
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Disp_Controller_Top
        generic map(
            C_MST_AWIDTH => 32,
            C_MST_DWIDTH => C_MST_DWIDTH
        )PORT MAP (
          red_out => red_out,
          green_out => green_out,
          blue_out => blue_out,
          hsyncx => hsyncx,
          vsyncx => vsyncx,
          Bus2IP_Clk => Bus2IP_Clk,
          Bus2IP_Reset => Bus2IP_Reset,
          IP2Bus_MstRd_Req => IP2Bus_MstRd_Req,
          IP2Bus_MstWr_Req => IP2Bus_MstWr_Req,
          IP2Bus_Mst_Addr => IP2Bus_Mst_Addr,
          IP2Bus_Mst_BE => IP2Bus_Mst_BE,
          IP2Bus_Mst_Length => IP2Bus_Mst_Length,
          IP2Bus_Mst_Type => IP2Bus_Mst_Type,
          IP2Bus_Mst_Lock => IP2Bus_Mst_Lock,
          IP2Bus_Mst_Reset => IP2Bus_Mst_Reset,
          Bus2IP_Mst_CmdAck => Bus2IP_Mst_CmdAck,
          Bus2IP_Mst_Cmplt => Bus2IP_Mst_Cmplt,
          Bus2IP_Mst_Error => Bus2IP_Mst_Error,
          Bus2IP_Mst_Rearbitrate => Bus2IP_Mst_Rearbitrate,
          Bus2IP_Mst_Cmd_Timeout => Bus2IP_Mst_Cmd_Timeout,
          Bus2IP_MstRd_d => Bus2IP_MstRd_d,
          Bus2IP_MstRd_rem => Bus2IP_MstRd_rem,
          Bus2IP_MstRd_sof_n => Bus2IP_MstRd_sof_n,
          Bus2IP_MstRd_eof_n => Bus2IP_MstRd_eof_n,
          Bus2IP_MstRd_src_rdy_n => Bus2IP_MstRd_src_rdy_n,
          Bus2IP_MstRd_src_dsc_n => Bus2IP_MstRd_src_dsc_n,
          IP2Bus_MstRd_dst_rdy_n => IP2Bus_MstRd_dst_rdy_n,
          IP2Bus_MstRd_dst_dsc_n => IP2Bus_MstRd_dst_dsc_n,
          IP2Bus_MstWr_d => IP2Bus_MstWr_d,
          IP2Bus_MstWr_rem => IP2Bus_MstWr_rem,
          IP2Bus_MstWr_sof_n => IP2Bus_MstWr_sof_n,
          IP2Bus_MstWr_eof_n => IP2Bus_MstWr_eof_n,
          IP2Bus_MstWr_src_rdy_n => IP2Bus_MstWr_src_rdy_n,
          IP2Bus_MstWr_src_dsc_n => IP2Bus_MstWr_src_dsc_n,
          afifo_overflow => afifo_overflow,
          afifo_underflow => afifo_underflow,
          addr_is_zero => addr_is_zero,
          h_v_is_zero => h_v_is_zero
        );
    Bus2IP_Mst_Error <= '0';
    Bus2IP_Mst_Rearbitrate <= '0';
    Bus2IP_Mst_Cmd_Timeout <= '0';
    IP2Bus_MstWr_rem <= (others => '0');
    Bus2IP_MstRd_src_dsc_n <= '1';
    
   -- Clock process definitions
   Bus2IP_Clk_process :process
   begin
        Bus2IP_Clk <= '0';
        wait for Bus2IP_Clk_period/2;
        Bus2IP_Clk <= '1';
        wait for Bus2IP_Clk_period/2;
   end process;

   -- IPIC のマスタRead, Writeの対応をするモジュール、バースト対応のみ  
   -- まず、コマンド転送に応答して、Bus2IP_Mst_CmdAck を返す
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd_ack <= IDLE_CMD_ACK;
                cmd_ack <= '0';
            else
                case cs_cmd_ack is
                    when IDLE_CMD_ACK =>
                        if IP2Bus_MstRd_Req='1' or IP2Bus_MstWr_Req='1' then
                            cs_cmd_ack <= CMD_TRANS_1;
                        end if;
                    when CMD_TRANS_1 =>
                        cs_cmd_ack <= CMD_TRANS_2;
                    when CMD_TRANS_2 =>
                        cs_cmd_ack <= CMD_TRANS_3;
                    when CMD_TRANS_3 =>
                        cs_cmd_ack <= CMD_TRANS_4;
                    when CMD_TRANS_4 =>
                        cs_cmd_ack <= CMD_ACK_ST;
                        cmd_ack <= '1';
                    when CMD_ACK_ST =>
                        cs_cmd_ack <= IDLE_CMD_ACK;
                        cmd_ack <= '0';
                end case;
            end if;
        end if;
    end process;
    Bus2IP_Mst_CmdAck <= cmd_ack;

    -- Readデータを出力するステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_data_rd <= IDLE_DATA_RD;
                Bus2IP_MstRd_sof_n <= '1';
                Bus2IP_MstRd_eof_n <= '1';
                Bus2IP_Mst_Cmplt <= '0';
            else
                case cs_data_rd is
                    when IDLE_DATA_RD =>
                        if cmd_ack='1' then
                            cs_data_rd <= SOF_ASSORT;
                            Bus2IP_MstRd_sof_n <= '0';
                        end if;
                    when SOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            cs_data_rd <= RD_DATA_OUT;
                            Bus2IP_MstRd_sof_n <= '1';
                        end if;
                    when RD_DATA_OUT =>
                        if trans_count=2 and mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            cs_data_rd <= EOF_ASSORT;
                            Bus2IP_MstRd_eof_n <= '0';
                        end if;
                    when EOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            cs_data_rd <= RD_DATA_COMPLT;
                            Bus2IP_MstRd_eof_n <= '1';
                            Bus2IP_Mst_Cmplt <= '1';
                        end if;
                    when RD_DATA_COMPLT =>
                        cs_data_rd <= IDLE_DATA_RD;
                        Bus2IP_Mst_Cmplt <= '0';
                end case;
            end if;
        end if;
    end process;
    
    -- trans_count の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                trans_count <= CONV_STD_LOGIC_VECTOR(16,5);
            else
                case cs_data_rd is
                    when IDLE_DATA_RD =>
                        trans_count <= CONV_STD_LOGIC_VECTOR(16,5);
                    when SOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            trans_count <= trans_count - 1;
                        end if;
                    when RD_DATA_OUT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            trans_count <= trans_count - 1;
                        end if;
                    when EOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            trans_count <= trans_count - 1;
                        end if;
                    when others =>
                end case;
            end if;
        end if;
    end process;
    
    -- data の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                data <= (others => '0');
            else
                if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                    data <= data + 1;
                end if;
            end if;
        end if;
    end process;
    Bus2IP_MstRd_d <= data;
    
    -- Bus2IP_MstRd_src_rdy_n の処理
    process(Bus2IP_Clk) begin
        case cs_data_rd is
            when IDLE_DATA_RD =>
                mst_rd_rdy <= '0';
            when SOF_ASSORT =>
                mst_rd_rdy <= '1';
            when RD_DATA_OUT =>
                if mst_rd_rdy_1d='1' and trans_count=RDY_WAIT_VAL1 then
                    mst_rd_rdy <= '0';
                elsif mst_rd_rdy_1d='1' and trans_count=RDY_WAIT_VAL2 then
                    mst_rd_rdy <= '0';
                else
                    mst_rd_rdy <= '1';
                end if;
            when EOF_ASSORT =>
                mst_rd_rdy <= '1';
            when others =>
                mst_rd_rdy <= '0';
        end case;
    end process;
    Bus2IP_MstRd_src_rdy_n <= not mst_rd_rdy;
    
    -- mst_rd_rdy_1d の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_rd_rdy_1d <= '0';
            else
                mst_rd_rdy_1d <= mst_rd_rdy;
            end if;
        end if;
    end process;
    
  -- Stimulus process
   stim_proc: process
   begin    
      Bus2IP_Reset <= '1';
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      wait for Bus2IP_Clk_period*10;
      Bus2IP_Reset <= '0';

      -- insert stimulus here 

      wait;
   end process;

END behavior;


これでシミュレーションすると、1つにIPIC転送は以下のようになった。
Spa3A_SKit_OV7670_66_110910.png

これは最大の16バーストしている状態だ。Bus2IP_MstRd_src_rdy_nをデータ転送10回目と5回目にわざとディアサートしている。IP2Bus_MstRd_Reqが1になってから、Readデータが受け終わるまでに400nsec掛かっている。これは、前に述べたように2クロックWaitが入っているので、Waitが無いと、600nsec - 16nsec X 2 = 568nsec となる。

VGA_Display_Controller.v のFIFOの容量が半分を切って、requestを1にアサートする場合は、1度に128ワード(32ビット幅)のデータを要求する。IPICのバーストの単位は最大16バーストのため、バースト転送を8回行う(16X8=128)。それを下のシミュレーションに示す。
Spa3A_SKit_OV7670_67_110910.png

この間が3.424usec なので、この間に16バーストを8回行う。よって、16*8/3.424E-6 ≒ 37.4MW/sec (32bit幅)。
バイトに直すと、37.4 * 4 ≒ 150MBytes/sec となった。62.5MHz、32ビット幅の最大スルーレートは250Bytes/sec なので、約60%の帯域があることになる。案外、帯域が取れるもんだ?
(注:あくまで、現在のところの試算です。MIGのレイテンシやスループットによって変動します)

後は、次のブログで下のモジュールのHDLソースを貼ります。
  1. 2011年09月10日 20:41 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

2011年9月8日の日記

現在、ディスプレイ回路のカスタムIPを書いています。PLBバスのラッパーのIPICへのラッパー回路、Disp_Controller_Top.vhd はだいたい書き終わりました。
signal宣言を書きながら、VHDLコードを書いていると、思考が途切れるので、VHDLコードを書いてしまいます。現在は、VHDLコードは書き終わって、signal宣言を書いているところです。見直していると、細かい修正点が見えてきて、修正したりしています。

Verification Engineerの戯言さんの”Impulse C本、レビュー、いや、内容紹介”を見て、”C言語による実践的FPGAプログラミング”を読んでみたくなったのですが、アマゾンでは売り切れでした。ツイッターでVengineerさんとt3840さんに、セブンネットショッピングにあると教えて頂いて購入しました。来るのが楽しみです。
お二方とは、いろいろ意見交換させて頂いて楽しかったです。またよろしくお願いします。

このところ、花粉症だと思うのですが、鼻の奥がチリチリ、頭が痛くなります。特に職場の夕方がひどいです。台風来た辺りからだと思うのですが、どうも調子悪いです。ヨモギとかに反応するので、そろそろだとは思っていましたが。。。春と秋に花粉症が出てしまうので、まともなのは冬と夏なのですが、夏冬でもエアコンのカビや冷気などにも反応してしまうので、困りものです。
  1. 2011年09月08日 05:47 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示11(ディスプレイ回路を作り始める)

Spartan-3A Starter KitでEDKを使ってカメラ表示10(カメラ回路のIPを登録)”でカメラ回路IPの作成が終了した。

次は、ディスプレイ回路IPの作成を始めた。カメラ回路と同様にデータバス32ビット幅で作成したdisplay_controller_v1_00_aを使用することにした。なぜ64ビット幅を使わないかというとFIFO用のBRAMの数が足りないからだ。Spartan-3シリーズでは、BRAMの最大幅が32ビット幅(正確に言うと36ビット幅)なので、64ビット幅では、どんなに深度が浅くてもBRAMを2つ使用する。BRAMは1個にしないと数が足りないので、32ビット幅とした。

カメラ回路はマスタとしてWriteのみ使用したが、今度のディスプレイ回路はマスタとしてReadのみ使用する。カメラ回路のVHDLをかなり使い回し出来ると思うので、今回のほうが楽できるはず???
Disp_Controller_Top.vhd を、VGA_Display_Controller.v のトップとして作成することにした。Disp_Controller_Top.vhdは、VGA_Display_Controller.v とIPIC間のインタフェースである。
今回も、dcm_DISP_clk.v を使用して、クロックを表示クロックに変換する。カメラとDCMを別にしたのはXGAに拡張する場合も考慮しているからだ。

しかし、Verilogファイルの上の階層が、VHDLファイルというのは面倒だ。component文を書かなくちゃならない。VHDL同士だと、下のVHDLを作って、entityをコピーして書き換えれば良いのだが、下がVerilogだとそうは行かない。

書き換えるまで、VHDL書きを頑張ります。。。

  1. 2011年09月06日 05:19 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

中尊寺に行ってきました2

中尊寺に行ってきました1”の続きです。

本堂に向かって、左手の方に金色堂への順路がありました。門をくぐります。
tyusonji_12_110905.jpg

途中にも、お堂があります。不動堂がありました。
tyusonji_13_110905.jpg

讃衡蔵で入場券を買いました。大人1人800円でした。金色堂に向かいました。下が金色堂がまるまる収められている建物です。
tyusonji_14_110905.jpg

建物内は撮影禁止だったので、金色堂は撮影できませんでしたが、金ぴかでした。金ピカの建物の造作は甘い感じがしました。中の仏像やまわりの螺鈿などはほんとうに見事でした。屋根は、なんか丸太でもふかれている感じがしました。腐らないんでしょうか?今は腐らないでしょうが、建立当時はどうだったんでしょう?

またまたお堂があって、松尾芭蕉の碑とかもありました。
tyusonji_15_110905.jpg

その内に、神輿の音が聞こえてきました。
tyusonji_16_110905.jpg

神輿のところに行ってみると、横棒が丸太です。縦棒も外側が丸太でした。びっくり。丸太のところを担ぐと肩が痛そうです。
tyusonji_17_110905.jpg

びっくりしたのは、中尊寺の境内に白山神社があったことです。神輿は下に降りた様子がなかったので、ここの神社にしまわれたのでしょうか?神輿というと普通は神様の乗り物ですよね?うちの地区では神主さんに来て頂いて、神輿を担ぐ前には、御神入れをしていただきます。
tyusonji_18_110905.jpg

この後、3000点を超える国宝、重要文化財を収蔵しているという讃衡蔵を見てきました。これも撮影禁止でしたが、とても良かったです。普段見れないものが見られて満足です。平安時代の枕とかがあります。曼荼羅とかも、古い収蔵品は一度は見てみたいものです。(なんでも鑑定団が大好きです)

この辺で中尊寺の境内から出て、ご飯を食べました。最初は牛たんのつくねです。わさびで食べます。あまり味がついていないので、牛たんの旨みで食べる感じです。柔らかいんだけど、少し噛みごたえがある感じで美味しかったです。やはりタレは付けないで、肉の味を楽しむのが良いですね。
tyusonji_19_110905.jpg

昼ごはんは、前沢牛入りハンバーグ定食でした。どのくらい前沢牛が入っているかはわかりませんが、美味しかったです。ハンバーグは肉味十分でした。味噌汁が岩のり入りで、こっちの方の味噌汁は岩のり入りなんですか?と聞いたら、そんなことはない、当店オリジナルだそうです。
tyusonji_20_110905.jpg

食事も終了し、午後1時30分頃ころ中尊寺を出ました。一関インターから東北道に乗って、今度は磐越道を通って、常磐道にのり、千代田石岡で降りて帰ってきました。だいたい家についたのが、午後7時です。

途中、磐越道では、急に大雨が降りだしてくることがありました。疲れましたが、初めて中尊寺に行って来られたので、楽しかったです。わが愛車も本当に頑張ってくれました。ありがとう。調子良かったです。往復の総キロ数は820キロでした。

  1. 2011年09月05日 21:05 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:2

中尊寺に行ってきました1

今日は、うちの娘と奥さんで、午前5時20分頃、車で出発して仙台を目指しました。台風が心配でしたが、影響が少なくて良かったです。
矢板で東北自動車道に乗ったのですが、とても空いていて走りやすかったです。矢板までも早朝なので、道が空いていました。
途中、渋滞にあうこともなく順調で、仙台には9時50分に着きました。そこで、娘のアパートにコメや食料品をおいてきて、今度はまた東北道を北に走って岩手県の一関で降りました。
一関で降りてから、中尊寺を目指して走ります。中尊寺に着いたのが、午前11時30分で、仙台から約1時間かかりました。
中尊寺に着いてみると、何か祭太鼓がなって、お祭りをやっています。水かけ神輿だそうです。(予定外でした)(9月4日、水かけ神輿が行われました!その19月4日、水かけ神輿が行われました!その2
tyusonji_1_110904.jpg

太鼓の動画です。手ぶれしています。


子供神輿が中尊寺の参道を登ってきます。
tyusonji_2_110904.jpg

子供たちはずぶ濡れで、水かけ神輿そのものでした。
tyusonji_3_110904.jpg

後から、大人の水かけ神輿も来ていました。

さて、中尊寺内にはいろいろなお堂がありました。これは、参道にあった弁慶堂です。
tyusonji_4_110904.jpg

立て看板にはその由来が書いてありました。
tyusonji_5_110904.jpg

参道からの眺めが最高な所がありました。
tyusonji_6_110904.jpg

参道はとう言うと、ものすごく太い杉の木がたくさんあります。春のシーズンは来られなそうです。(花粉症で。。。)
tyusonji_7_110904.jpg

本当にお堂がたくさんあります。(薬師堂)
tyusonji_8_110904.jpg

やっと本堂前まで来ました。右手の階段を登ると本堂です。
tyusonji_9_110904.jpg

中尊寺の門をくぐると本堂?(たぶん)です。
tyusonji_10_110904.jpg

大きかったです。反対側に鐘つき堂もありました。
tyusonji_11_110904.jpg

中尊寺に行ってきました2”に続きます。
  1. 2011年09月04日 22:21 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示10(カメラ回路のIPを登録)

Spartan-3A Starter KitでEDKを使ってカメラ表示9(カメラ回路のシミュレーション)”の続き。

前回はカメラ回路とIPICのインターフェース部分を作り、テストベンチも作ってシミュレーションを行った。今回は、user_logic.vhd にCam_Controller_Top.vhd のインスタンスを接続して、カスタムIPとして登録する。

最初に、user_logic.vhd にCam_Controller_Topのインスタンスを接続した。その一部を下に示す。

    -- Master Write (Cam_Controller_Top.vhd)
    Cam_Controller_Top : Cam_Cont_Top generic map (
        C_SLV_DWIDTH => C_SLV_DWIDTH,
        C_MST_AWIDTH => C_MST_AWIDTH,
        C_MST_DWIDTH => C_MST_DWIDTH,
        C_NUM_REG => C_NUM_REG
    ) port map (
        cam_href => cam_href,
        cam_vsync => cam_vsync,
        cam_pclk => cam_pclk,
        cam_data => cam_data,
        cam_clk => cam_clk,
        Bus2IP_Clk => Bus2IP_Clk,
        Bus2IP_Reset => Bus2IP_Reset,
        IP2Bus_MstRd_Req => IP2Bus_MstRd_Req,
        IP2Bus_MstWr_Req => IP2Bus_MstWr_Req,
        IP2Bus_Mst_Addr => IP2Bus_Mst_Addr,
        IP2Bus_Mst_BE => IP2Bus_Mst_BE,
        IP2Bus_Mst_Length => IP2Bus_Mst_Length,
        IP2Bus_Mst_Type => IP2Bus_Mst_Type,
        IP2Bus_Mst_Lock => IP2Bus_Mst_Lock,
        IP2Bus_Mst_Reset => IP2Bus_Mst_Reset,
        Bus2IP_Mst_CmdAck => Bus2IP_Mst_CmdAck,
        Bus2IP_Mst_Cmplt => Bus2IP_Mst_Cmplt,
        Bus2IP_Mst_Error => Bus2IP_Mst_Error,
        Bus2IP_Mst_Rearbitrate => Bus2IP_Mst_Rearbitrate,
        Bus2IP_Mst_Cmd_Timeout => Bus2IP_Mst_Cmd_Timeout,
        IP2Bus_MstWr_d => IP2Bus_MstWr_d,
        IP2Bus_MstWr_rem => IP2Bus_MstWr_rem,
        IP2Bus_MstWr_sof_n => IP2Bus_MstWr_sof_n,
        IP2Bus_MstWr_eof_n => IP2Bus_MstWr_eof_n,
        IP2Bus_MstWr_src_rdy_n => IP2Bus_MstWr_src_rdy_n,
        IP2Bus_MstWr_src_dsc_n => IP2Bus_MstWr_src_dsc_n,
        Bus2IP_MstWr_dst_rdy_n => Bus2IP_MstWr_dst_rdy_n,
        Bus2IP_MstWr_dst_dsc_n => Bus2IP_MstWr_dst_dsc_n,
        IP2Bus_MstRd_dst_rdy_n => IP2Bus_MstRd_dst_rdy_n,
        IP2Bus_MstRd_dst_dsc_n => IP2Bus_MstRd_dst_dsc_n,
        afifo_overflow => afifo_overflow,
        afifo_underflow => afifo_underflow
    );


次に、”XPSのカスタムIPにCore Generatorで生成したIPのネットリストを追加する”を参考にして、XPSのカスタムIPに自分で作った回路や、Core Generatorで生成したIPのネットリストを追加する。

・MPDファイルに”OPTION STYLE = MIX”を追加した。

BEGIN camera_controller

## Peripheral Options
OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION HDL = VHDL
OPTION IP_GROUP = MICROBLAZE:PPC:USER
OPTION DESC = CAMERA_CONTROLLER
OPTION ARCH_SUPPORT_MAP = (others=DEVELOPMENT)
OPTION STYLE = MIX


・CamDisp_EDK_OV7670\system\pcores\camera_controller_v1_00_a\dataフォルダの下に、camera_controller_v2_1_0.bbdを作った。ファイルの内容を下に示す。

FILES
cam_cont_afifo.ngc


Spa3A_SKit_OV7670_64_110903.png

・CamDisp_EDK_OV7670\system\pcores\camera_controller_v1_00_aフォルダの下に netlist フォルダを作って、その中に、cam_cont_afifo.ngc をコピーした。
Spa3A_SKit_OV7670_65_110903.png

・CamDisp_EDK_OV7670\system\pcores\camera_controller_v1_00_a\dataフォルダのcamera_controller_v2_1_0.pao ファイルを以下のように書き換えた。

##############################################################################
## Filename: H:/HDL/FndtnISEWork/Spartan3A_starter_kit/CamDisp_EDK_OV7670/system/pcores/camera_controller_v1_00_a/data/camera_controller_v2_1_0.pao
## Description: Peripheral Analysis Order
## Date: Sun Aug 21 17:39:47 2011 (by Create and Import Peripheral Wizard)
##############################################################################

lib proc_common_v3_00_a all
lib plbv46_slave_single_v1_01_a all
lib plbv46_master_burst_v1_01_a all
lib camera_controller_v1_00_a user_logic vhdl
lib camera_controller_v1_00_a camera_controller vhdl
lib camera_controller_v1_00_a Cam_Controller_Top vhdl
lib camera_controller_v1_00_a Camera_Cntrler verilog
lib camera_controller_v1_00_a dcm_CAM_clk verilog
lib camera_controller_v1_00_a synchronizer verilog
lib camera_controller_v1_00_a cam_cont_afifo vhdl


(2011/9/17:追記)XSTでcam_cont_afifoがないとエラーが出るので、cam_cont_afifo.vhdをVHDLフォルダに入れて、.paoファイルに追加した。

・CamDisp_EDK_OV7670\system\pcores\camera_controller_v1_00_a\hdl\verilogフォルダを作成して、Camera_Cntrler.v、dcm_CAM_clk.v、synchronizer.v をコピーした。

・CamDisp_EDK_OV7670\system\pcores\camera_controller_v1_00_a\hdl\vhdlフォルダに、Cam_Controller_Top.vhd をコピーした。

これで、カメラ回路のIPは終了。

(2011/9/15:追記)
user_logic.vhdの上のcamera_controller.vhd にポートの定義、ポートの接続をするのを忘れていたので、追加する。
camera_controller.vhdのentityのport定義部分を示す。

entity camera_controller is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_BASEADDR                     : std_logic_vector     := X"FFFFFFFF";
    C_HIGHADDR                     : std_logic_vector     := X"00000000";
    C_SPLB_AWIDTH                  : integer              := 32;
    C_SPLB_DWIDTH                  : integer              := 128;
    C_SPLB_NUM_MASTERS             : integer              := 8;
    C_SPLB_MID_WIDTH               : integer              := 3;
    C_SPLB_NATIVE_DWIDTH           : integer              := 32;
    C_SPLB_P2P                     : integer              := 0;
    C_SPLB_SUPPORT_BURSTS          : integer              := 0;
    C_SPLB_SMALLEST_MASTER         : integer              := 32;
    C_SPLB_CLK_PERIOD_PS           : integer              := 10000;
    C_INCLUDE_DPHASE_TIMER         : integer              := 1;
    C_FAMILY                       : string               := "virtex6";
    C_MPLB_AWIDTH                  : integer              := 32;
    C_MPLB_DWIDTH                  : integer              := 128;
    C_MPLB_NATIVE_DWIDTH           : integer              := 32;
    C_MPLB_P2P                     : integer              := 0;
    C_MPLB_SMALLEST_SLAVE          : integer              := 32;
    C_MPLB_CLK_PERIOD_PS           : integer              := 10000
    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
    -- ADD USER PORTS ABOVE THIS LINE ------------------
    cam_href    : in std_logic;    -- CMOSカメラからのHREF
    cam_vsync     : in std_logic;    -- CMOSカメラからのVSYNC
    cam_pclk    : in std_logic;    -- CMOSカメラからのpclk
    cam_data    : in std_logic_vector(7 downto 0);    -- CMOSカメラからのデータ
    cam_clk        : out std_logic;
    
    afifo_overflow                    : out std_logic;
    afifo_underflow                    : out std_logic

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol ports, do not add to or delete
    SPLB_Clk                       : in  std_logic;
    SPLB_Rst                       : in  std_logic;
    PLB_ABus                       : in  std_logic_vector(0 to 31);


次に、camera_controller.vhdのポートの接続部分を示す。

  USER_LOGIC_I : entity camera_controller_v1_00_a.user_logic
    generic map
    (
      -- MAP USER GENERICS BELOW THIS LINE ---------------
      --USER generics mapped here
      -- MAP USER GENERICS ABOVE THIS LINE ---------------

      C_SLV_DWIDTH                   => USER_SLV_DWIDTH,
      C_MST_AWIDTH                   => USER_MST_AWIDTH,
      C_MST_DWIDTH                   => USER_MST_DWIDTH,
      C_NUM_REG                      => USER_NUM_REG
    )
    port map
    (
      -- MAP USER PORTS BELOW THIS LINE ------------------
      --USER ports mapped here
      cam_href                         => cam_href,
      cam_vsync                        => cam_vsync,
      cam_pclk                        => cam_pclk,
      cam_data                        => cam_data,
      cam_clk                        => cam_clk,
      afifo_overflow                => afifo_overflow,
      afifo_underflow                => afifo_underflow,
      
      -- MAP USER PORTS ABOVE THIS LINE ------------------

      Bus2IP_Clk                     => ipif_Bus2IP_Clk,
      Bus2IP_Reset                   => ipif_Bus2IP_Reset,


(2011/9/15:追記)ここまで。


Camera_Cntrler.vを下に示す。

// CAMERA_CONTROLLER
// カメラデータを書き込むためのDDR2 SDRAMアドレスを出力する
// YデータとUVデータを出力する。フォーマットはUYVY
// 2001/07/24:cam_cont_afifoに2つ以上のデータがあることを示すためにrd_data_countを出力ポートに追加する

`default_nettype none

module Camera_Cntrler (
    input    wire    clk_cam,    // 25MHzのCMOSカメラ用クロック
    input    wire    clk_ddr2,    // 133.33MHzのDDR2 SDRAM用クロック
    input    wire    reset_cam,    // clk_cam 用リセット
    input    wire    reset_ddr2,    // clk_ddr2 用リセット
    input    wire    cam_href_2d,     // CMOSカメラからのHREFのラッチ出力(2クロック遅延)
    input    wire    cam_vsync_2d,    // CMOSカメラからのVSYNCのラッチ出力(2クロック遅延)
    input    wire    master_sync,     // 同期信号
    input    wire    [7:0]    cam_data_2d,    // CMOSカメラからの輝度データ
    output    reg        [18:0]    address,    // アドレス
    output    wire    [31:0]    data_out,    // VYUY8ビットフォーマットの画像データ出力
    input    wire    addr_enable,    // アドレス・イネーブル
    input    wire    data_enable,    // データ・イネーブル
    input    wire    capture_ena,    // CMOSカメラデータ書き込みイネーブル
    output    wire    afifo_empty,    // cam_cont_afifo はempty 
    output    wire    [7:0]    afifo_rd_data_count,     // cam_cont_afifoのread data count
    output    wire    afifo_overflow, // cam_cont_afifo はoverflow
    output    wire    afifo_underflow    // cam_cont_afifo はunderflow
);
    
    reg [7:0] uv_ff;
    wire afifo_wr_en;
    wire [15:0] afifo_din;
    reg y_pos;
    wire afifo_full;
    
    parameter    UV_state =    1'b0,
                Y_state =    1'b1;
    reg YUV_state;
    
    reg    [15:0] count;
    reg [8:0] href_count;
    reg [9:0] h_count;
    reg cam_href_3d;
    reg msync_ddr2_d1, msync_ddr2_d2, msync_ddr2_d3, msync_ddr2_d4;
    reg start_flag;
    
    parameter    HOLD_STATE=        1'b0,
                CAPTURE_STATE=    1'b1;
    reg capt_state;
    reg capt_ena;
    
    
    // 非同期FIFO Write(16ビット幅、32深度)、Read(32ビット幅、16深度)
    cam_cont_afifo cam_cont_afifo_inst (
        .wr_clk(clk_cam),
        .wr_rst(reset_cam),
        .rd_clk(clk_ddr2),
        .rd_rst(reset_ddr2),
        .din(afifo_din), // Bus [15 : 0] 
        .wr_en(afifo_wr_en),
        .rd_en(data_enable),
        .dout(data_out), // Bus [31 : 0] 
        .full(afifo_full),
        .overflow(afifo_overflow),
        .empty(afifo_empty),
        .underflow(afifo_underflow),
        .rd_data_count(afifo_rd_data_count) // Bus [7 : 0] 
    );
    
    // 最初のmaster_sync までは、YUVデータを出さないようにする
    always @(posedge clk_cam) begin
        if (reset_cam)
            start_flag <= 1'b0;
        else
            if (master_sync)
                start_flag <= 1'b1;
    end
    
    // UまたはVを保存しておくFF、UYVYで出てくるので、UまたはVを保存しておいてYが出てきた時点でcam_cont_afifoに書き込む
    always @(posedge clk_cam) begin
        if (reset_cam)
            uv_ff <= 0;
        else
            uv_ff <= cam_data_2d;
    end
    
    // U,VとYを表すステートマシン
    always @(posedge clk_cam) begin
        if (reset_cam)
            YUV_state <= UV_state;
        else begin
            case (YUV_state)
                UV_state :
                    if (cam_href_2d && start_flag)
                        YUV_state <= Y_state;
                    else
                        YUV_state <= UV_state;
                Y_state :
                    YUV_state <= UV_state;
            endcase
        end
    end
    
    // afifo_din はuv_ff とcam_data_2d を連結
    assign afifo_din = {uv_ff, cam_data_2d};
    // cam_cont_afifo のwr_en はYUV_state がY_state の時
    assign afifo_wr_en = (YUV_state==Y_state && capt_ena) ? 1'b1 : 1'b0;
    
    // master_sync をclk_ddr2 に同期させる
    always @(posedge clk_ddr2) begin
        if (reset_ddr2) begin
            msync_ddr2_d1 <= 1'b0;
            msync_ddr2_d2 <= 1'b0;
            msync_ddr2_d3 <= 1'b0;
            msync_ddr2_d4 <= 1'b0;
        end else begin
            msync_ddr2_d1 <= master_sync;
            msync_ddr2_d2 <= msync_ddr2_d1;
            msync_ddr2_d3 <= msync_ddr2_d2;
            msync_ddr2_d4 <= msync_ddr2_d3;
        end
    end
    
    // アドレス用カウンタ 640*480 = 307,200(hex 4b000)をカウントする
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            address <= 0;
        else begin    
            if (msync_ddr2_d3==1'b1 && msync_ddr2_d4==1'b0) // 1フレーム終了したので0に戻す
                address <= 0;
            else if (addr_enable && start_flag)
                    address <= address + 19'd4; // DDR2 SDRAMは1回の書き込みで4つの16ビットデータを書き込むため
        end
    end
    
    // CMOSカメラデータのキャプチャ状態
    always @(posedge clk_cam) begin
        if (reset_cam) begin
            capt_state <= HOLD_STATE;
            capt_ena <= 1'b0;
        end else begin
            case (capt_state)
                HOLD_STATE :
                    if (capture_ena && master_sync) begin
                        capt_state <= CAPTURE_STATE;
                        capt_ena <= 1'b1;
                    end
                CAPTURE_STATE :
                    if (~capture_ena && master_sync) begin
                        capt_state <= HOLD_STATE;
                        capt_ena <= 1'b0;
                    end
            endcase
        end
    end
                    
endmodule

`default_nettype wire


dcm_CAM_clk.vを下に示す。

// DCM module
// 62.5MHzを入力して、50MHzのカメラ用のclkを生成する。

`default_nettype none
`timescale 1ns / 1ps

(* KEEP_HIERARCHY = "TRUE" *)module dcm_CAM_clk (sysclk, reset, clk_cam, dcm_locked_out);
    input    wire    sysclk;
    input    wire    reset;
    output    wire    clk_cam;
    output    wire    dcm_locked_out;
    
    wire clk_bufg, clk_node, dcm1_locked;
    wire clk_cam_node, clk_cam_bufg;
        
    DCM dcm_DDR2_clk_dcm (
        .CLKIN(sysclk),
        .CLKFB(clk_bufg),
        .DSSEN(1'b0),
        .PSINCDEC(1'b0),
        .PSEN(1'b0),
        .PSCLK(1'b0),
        .RST(reset),     // 前段のDCMがロックするまでリセット
        .CLK0(clk_node),
        .CLK90(),
        .CLK180(),
        .CLK270(),
        .CLK2X(),
        .CLK2X180(),
        .CLKDV(),
        .CLKFX(clk_cam_node),
        .CLKFX180(),
        .LOCKED(dcm1_locked),
        .PSDONE(),
        .STATUS()
    );
    defparam dcm_DDR2_clk_dcm.CLKIN_PERIOD = 16.0;
    defparam dcm_DDR2_clk_dcm.DLL_FREQUENCY_MODE = "LOW";
    defparam dcm_DDR2_clk_dcm.DUTY_CYCLE_CORRECTION = "TRUE";
    defparam dcm_DDR2_clk_dcm.CLKDV_DIVIDE = 2.0;
    defparam dcm_DDR2_clk_dcm.PHASE_SHIFT = 0;
    defparam dcm_DDR2_clk_dcm.CLKOUT_PHASE_SHIFT = "NONE";
    defparam dcm_DDR2_clk_dcm.STARTUP_WAIT = "FALSE";
    defparam dcm_DDR2_clk_dcm.CLKFX_DIVIDE = 5;
    defparam dcm_DDR2_clk_dcm.CLKFX_MULTIPLY = 2;
    
    BUFG CLK_BUFG_INST (
        .I(clk_node),
        .O(clk_bufg)
    );
    
    BUFG CLK_CAM_BUFG_INST (
        .I(clk_cam_node),
        .O(clk_cam_bufg)
    );
    assign dcm_locked_out = dcm1_locked;
    assign clk_cam = clk_cam_bufg;
endmodule


synchronizer.vを下に示す。

// synchronizer
// synchronizerが使用するのは、FPGAに入力されたcam_hrefやcam_vsyncからIOBのFFを通り1クロックディレイした信号。その他のモジュールは2クロック遅延した信号を用いる
// cam_vsync_1d が1から0になった後の最初の cam_href_1d の立ち上がりで同期信号(master_sync)を出力する
// 同時に出力するR_W信号を1(Read)にする

`default_nettype none

module synchronizer (
    input    wire    clk,
    input    wire    reset,
    input    wire    cam_vsync_1d,
    input    wire    cam_href_1d,
    output    wire    master_sync
);

    parameter    [3:0]    Idle_Sync =            4'b0001,
                        Vsync_Assert =        4'b0010,
                        Vsync_Deassert =    4'b0100,
                        Sync_Active =        4'b1000;
    reg        [3:0]    cs_sync;
    reg        msync;
    
    // master_sync を出力するステートマシン
    always @(posedge clk) begin
        if (reset) begin
            cs_sync <= Idle_Sync;
            msync <= 1'b0;
        end else begin
            case (cs_sync)
                Idle_Sync : begin
                    msync <= 1'b0;
                    if (cam_vsync_1d)
                        cs_sync <= Vsync_Assert;
                end
                Vsync_Assert :
                    if (~cam_vsync_1d)
                        cs_sync <= Vsync_Deassert;
                Vsync_Deassert :
                    if (cam_href_1d) begin
                        cs_sync <= Sync_Active;
                        msync <= 1'b1;
                    end
                Sync_Active : begin
                    msync <= 1'b0;
                    cs_sync <= Idle_Sync;
                end
            endcase
        end
    end
    assign master_sync = (cs_sync==Vsync_Deassert && cam_href_1d) ? 1'b1 : 1'b0;
    
endmodule

`default_nettype wire


最後に、cam_cont_afifo.xco を以下に示す。

##############################################################
#
# Xilinx Core Generator version 13.2
# Date: Wed Aug 31 19:15:38 2011
#
##############################################################
#
# This file contains the customisation parameters for a
# Xilinx CORE Generator IP GUI. It is strongly recommended
# that you do not manually alter this file as it may cause
# unexpected and unsupported behavior.
#
##############################################################
#
# Generated from component: xilinx.com:ip:fifo_generator:8.2
#
##############################################################
#
# BEGIN Project Options
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = VHDL
SET device = xc3s700a
SET devicefamily = spartan3a
SET flowvendor = Other
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = fg484
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -4
SET verilogsim = false
SET vhdlsim = true
# END Project Options
# BEGIN Select
SELECT Fifo_Generator xilinx.com:ip:fifo_generator:8.2
# END Select
# BEGIN Parameters
CSET add_ngc_constraint_axi=false
CSET almost_empty_flag=false
CSET almost_full_flag=false
CSET aruser_width=1
CSET awuser_width=1
CSET axi_address_width=32
CSET axi_data_width=64
CSET axi_type=AXI4_Stream
CSET axis_type=FIFO
CSET buser_width=1
CSET clock_enable_type=Slave_Interface_Clock_Enable
CSET clock_type_axi=Common_Clock
CSET component_name=cam_cont_afifo
CSET data_count=false
CSET data_count_width=8
CSET disable_timing_violations=false
CSET disable_timing_violations_axi=false
CSET dout_reset_value=0
CSET empty_threshold_assert_value=4
CSET empty_threshold_assert_value_axis=1022
CSET empty_threshold_assert_value_rach=1022
CSET empty_threshold_assert_value_rdch=1022
CSET empty_threshold_assert_value_wach=1022
CSET empty_threshold_assert_value_wdch=1022
CSET empty_threshold_assert_value_wrch=1022
CSET empty_threshold_negate_value=5
CSET enable_aruser=false
CSET enable_awuser=false
CSET enable_buser=false
CSET enable_common_overflow=false
CSET enable_common_underflow=false
CSET enable_data_counts_axis=false
CSET enable_data_counts_rach=false
CSET enable_data_counts_rdch=false
CSET enable_data_counts_wach=false
CSET enable_data_counts_wdch=false
CSET enable_data_counts_wrch=false
CSET enable_ecc=false
CSET enable_ecc_axis=false
CSET enable_ecc_rach=false
CSET enable_ecc_rdch=false
CSET enable_ecc_wach=false
CSET enable_ecc_wdch=false
CSET enable_ecc_wrch=false
CSET enable_handshake_flag_options_axis=false
CSET enable_handshake_flag_options_rach=false
CSET enable_handshake_flag_options_rdch=false
CSET enable_handshake_flag_options_wach=false
CSET enable_handshake_flag_options_wdch=false
CSET enable_handshake_flag_options_wrch=false
CSET enable_read_channel=false
CSET enable_read_pointer_increment_by2=false
CSET enable_reset_synchronization=false
CSET enable_ruser=false
CSET enable_tdata=false
CSET enable_tdest=false
CSET enable_tid=false
CSET enable_tkeep=false
CSET enable_tlast=false
CSET enable_tready=true
CSET enable_tstrobe=false
CSET enable_tuser=false
CSET enable_write_channel=false
CSET enable_wuser=false
CSET fifo_application_type_axis=Data_FIFO
CSET fifo_application_type_rach=Data_FIFO
CSET fifo_application_type_rdch=Data_FIFO
CSET fifo_application_type_wach=Data_FIFO
CSET fifo_application_type_wdch=Data_FIFO
CSET fifo_application_type_wrch=Data_FIFO
CSET fifo_implementation=Independent_Clocks_Block_RAM
CSET fifo_implementation_axis=Common_Clock_Block_RAM
CSET fifo_implementation_rach=Common_Clock_Block_RAM
CSET fifo_implementation_rdch=Common_Clock_Block_RAM
CSET fifo_implementation_wach=Common_Clock_Block_RAM
CSET fifo_implementation_wdch=Common_Clock_Block_RAM
CSET fifo_implementation_wrch=Common_Clock_Block_RAM
CSET full_flags_reset_value=1
CSET full_threshold_assert_value=255
CSET full_threshold_assert_value_axis=1023
CSET full_threshold_assert_value_rach=1023
CSET full_threshold_assert_value_rdch=1023
CSET full_threshold_assert_value_wach=1023
CSET full_threshold_assert_value_wdch=1023
CSET full_threshold_assert_value_wrch=1023
CSET full_threshold_negate_value=254
CSET id_width=4
CSET inject_dbit_error=false
CSET inject_dbit_error_axis=false
CSET inject_dbit_error_rach=false
CSET inject_dbit_error_rdch=false
CSET inject_dbit_error_wach=false
CSET inject_dbit_error_wdch=false
CSET inject_dbit_error_wrch=false
CSET inject_sbit_error=false
CSET inject_sbit_error_axis=false
CSET inject_sbit_error_rach=false
CSET inject_sbit_error_rdch=false
CSET inject_sbit_error_wach=false
CSET inject_sbit_error_wdch=false
CSET inject_sbit_error_wrch=false
CSET input_data_width=16
CSET input_depth=256
CSET input_depth_axis=1024
CSET input_depth_rach=16
CSET input_depth_rdch=1024
CSET input_depth_wach=16
CSET input_depth_wdch=1024
CSET input_depth_wrch=16
CSET interface_type=Native
CSET output_data_width=32
CSET output_depth=128
CSET overflow_flag=true
CSET overflow_flag_axi=false
CSET overflow_sense=Active_High
CSET overflow_sense_axi=Active_High
CSET performance_options=First_Word_Fall_Through
CSET programmable_empty_type=No_Programmable_Empty_Threshold
CSET programmable_empty_type_axis=Empty
CSET programmable_empty_type_rach=Empty
CSET programmable_empty_type_rdch=Empty
CSET programmable_empty_type_wach=Empty
CSET programmable_empty_type_wdch=Empty
CSET programmable_empty_type_wrch=Empty
CSET programmable_full_type=No_Programmable_Full_Threshold
CSET programmable_full_type_axis=Full
CSET programmable_full_type_rach=Full
CSET programmable_full_type_rdch=Full
CSET programmable_full_type_wach=Full
CSET programmable_full_type_wdch=Full
CSET programmable_full_type_wrch=Full
CSET rach_type=FIFO
CSET rdch_type=FIFO
CSET read_clock_frequency=1
CSET read_data_count=true
CSET read_data_count_width=8
CSET register_slice_mode_axis=Fully_Registered
CSET register_slice_mode_rach=Fully_Registered
CSET register_slice_mode_rdch=Fully_Registered
CSET register_slice_mode_wach=Fully_Registered
CSET register_slice_mode_wdch=Fully_Registered
CSET register_slice_mode_wrch=Fully_Registered
CSET reset_pin=true
CSET reset_type=Asynchronous_Reset
CSET ruser_width=1
CSET tdata_width=64
CSET tdest_width=4
CSET tid_width=8
CSET tkeep_width=4
CSET tstrb_width=4
CSET tuser_width=4
CSET underflow_flag=true
CSET underflow_flag_axi=false
CSET underflow_sense=Active_High
CSET underflow_sense_axi=Active_High
CSET use_clock_enable=false
CSET use_dout_reset=true
CSET use_embedded_registers=false
CSET use_extra_logic=true
CSET valid_flag=false
CSET valid_sense=Active_High
CSET wach_type=FIFO
CSET wdch_type=FIFO
CSET wrch_type=FIFO
CSET write_acknowledge_flag=false
CSET write_acknowledge_sense=Active_High
CSET write_clock_frequency=1
CSET write_data_count=false
CSET write_data_count_width=9
CSET wuser_width=1
# END Parameters
# BEGIN Extra information
MISC pkg_timestamp=2011-03-14T07:12:32.000Z
# END Extra information
GENERATE
# CRC: 9d4027c5

  1. 2011年09月03日 19:13 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋の2011年8月のアクセス数

FPGAの部屋の2011年8月のアクセス数は、39,936アクセスでした。皆さん、見て頂いてありがとうございます。
FPGA_room_access_8_2_110903.png

8月中にFPGAの部屋の記事にヒットした検索語は下のようになりました。
FPGA_room_access_8_110903.png

やはり、8月なので、自由研究での検索が多かったです。それにDE0人気ですね。また、始めようかな?
realteck pcie gbe family controller は私のパソコンで使っているギガビット・イーサネットのコントローラで、検索が多いみたいです。うちのパソコンのギガビット・イーサネットのコントローラはおかしいので使っていません。今は、USB-LAN変換ケーブルで接続しています。

ちなみに7月の検索語は下です。
FPGA_room_access_7_110903.png

DE0やはり人気ですね。
ここでも、realteck pcie gbe family controller入ってます。isim 使い方などが入ってきて、まっとうな気がします。
xスプリットとは、何でヒットしているんでしょうか?
検索してみると、ニコ生のXSplitというソフトのことのようです。なぜ、FPGAの部屋の検索後に当たるかというと、”FPGAの部屋 PCI-Xスプリット完了”という記事に当たってしまうようです。全く内容が違うんですが、よくわからないでクリックしてしまう人が多いんでしょうね?
  1. 2011年09月03日 05:20 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

XPSのカスタムIPにCore Generatorで生成したIPのネットリストを追加する

カスタムIPに自分で作ったVHDLやVerilogのファイルを追加する方法は、ame_feb4さんに教えて頂いて、”AXIバスのEDKでキャラクタ・ディスプレイ・コントローラのカスタムIPを作る2”で行うことができた。

どうやったか?をもう一度おさらいすると、自分で作ったファイルを、system\pcores\[カスタムIP名]\data\[カスタムIP名].paoファイルに追加で登録した。
前回は、CharDispCtrler_SP605.vの下のHDLファイル名を、pcores -> chardispc_v1_00_a -> data -> chardispc_v2_1_0.pao に追加した。下に、chardispc_v2_1_0.paoの内容を示す。

##############################################################################
## Filename: H:/HDL/FndtnISEWork/Spartan6/SP605_AXI_CharDispCtrler/system/pcores/chardispc_v1_00_a/data/chardispc_v2_1_0.pao
## Description: Peripheral Analysis Order
## Date: Sat Jul 30 05:47:37 2011 (by Create and Import Peripheral Wizard)
##############################################################################

lib proc_common_v3_00_a all
lib axi_lite_ipif_v1_01_a all
lib chardispc_v1_00_a user_logic vhdl
lib chardispc_v1_00_a chardispc vhdl
lib chardispc_v1_00_a char_gen_rom.v verilog
lib chardispc_v1_00_a CharDispCtrler.v verilog
lib chardispc_v1_00_a CharDispCtrler_SP605.v verilog
lib chardispc_v1_00_a dcm_inst.vhd vhdl
lib chardispc_v1_00_a disp_timing.v verilog
lib chardispc_v1_00_a frame_buffer.v verilog
lib chardispc_v1_00_a freqdiv.vhd vhdl
lib chardispc_v1_00_a One_Transaction_SCCB.vhd vhdl
lib chardispc_v1_00_a SCCB_Reg_Controller.vhd vhdl
lib chardispc_v1_00_a SCCB_reg_values_ROM.vhd vhdl


VHDLファイルはpcores -> chardispc_v1_00_a -> hdl -> vhdlフォルダに追加した。Verilogファイルはpcores -> chardispc_v1_00_a -> hdl -> verilogフォルダを作成して、そこに入れた。

次に、今回は、Core Generatorで生成したIPも使用する。それをカスタムIPにどうやって入れるのかを調べた。”Xilinx IP wizard help”が検索できた。(これは記述が間違っていたことがあとで分かった。MDDファイルでなくてMPDファイルだった)

やり方をまたame_feb4さんに教えていただいた。(いつもありがとうございます)
それは、”9.1i EDK - What should I do to instantiate a netlist core in my custom peripheral?”だった。
これによると、

1.MPDファイルに”OPTION STYLE = MIX”と宣言する。

OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION HDL = VHDL
OPTION IP_GROUP = MICROBLAZE:PPC:USER
OPTION CORE_STATE = DEVELOPMENT
OPTION STYLE = MIX


2.system\pcores\[カスタムIP名]に、netlistフォルダを作る。

3.system\pcores\[カスタムIP名]\dataフォルダに、[カスタムIP名].bbdを新規作成する。

4.[カスタムIP名].bbdファイルに、使用するネットリストファイルのリストを入力する。

FILES
cam_cont_afifo.ngc, cam_data_fifo.ngc, disp_netlist.edn


5.カスタムIPに含めるネットリストファイルをすべて、system\pcores\[カスタムIP名]\netlistフォルダに入れる。

(注)
これだけでは論理合成でエラーになってしまう。.ngc ファイルのVerilog かVHDLファイルをフォルダ(Verilog またはVHDL) に追加して、.pao ファイルにそのHDLファイルのエントリを追加する必要がある。



だそうだ。

実際にCORE GeneratorでIPを作成すると、ngcも作られる。CORE Generatorで生成されたIPは[プロジェクトフォルダ]\ipcore_dirフォルダにある。cam_cont_afifoを生成した時の、ipcore_dirフォルダを下に示す。
Spa3A_SKit_OV7670_62_110902.png

Project Navigatorに通常は、cam_cont_afifo.xcoがプロジェクトに入っていて、インプリメントもシミュレーションもできるが、インプリメント時にはcam_cont_afifo.ngcをプロジェクトに入れることができる。
Spa3A_SKit_OV7670_63_110902.png

これで、CORE Generatorで生成されたIPを、XPSのカスタムIPの一部として使用することができる。
  1. 2011年09月02日 05:04 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでEDKを使ってカメラ表示9(カメラ回路のシミュレーション)

Spartan-3A Starter KitでEDKを使ってカメラ表示8(HDLを書く)”の続き。

今回は、やっとVHDLを書き終えたので、シミュレーションをしてみた。

user_logic.vhdの下位モジュールとして、IPICとインターフェースするためのCam_Controller_Top.vhd を作成した。これは、CMOSカメラのコントロール用の回路(Camera_Cntrler.v) とIPIC (IP Interconnect) をインターフェースする回路だ。IPICはPLB4.6に変換されて、XPSのバスに接続される。カメラ回路ではマスタとしては、WriteのみでReadはない。よって、マスタWriteのみ実装している。
下に、Cam_Controller_Top.vhd を示す。VHDLなんでちょっと長いのだけれど、雰囲気を感じてもらえば良いと思う。
(2011/09/01 20:25 : VHDLコードを修正しました。ip2bus_mstwr_reqが1の間、ip2bus_mst_addrの値を固定しました, addr_cntを追加)

-- Cam_Controller_Top.vhd
-- Camera_Cntrler.v とsynchronizer.v のトップ
-- DDR2 SDRAM 64MBの内の真ん中から1MBを使用する。データバス幅は32ビット

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

library unisim;
use unisim.vcomponents.all;

entity Cam_Controller_Top is
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    port(
        cam_href    : in std_logic;    -- CMOSカメラからのHREF
        cam_vsync     : in std_logic;    -- CMOSカメラからのVSYNC
        cam_pclk    : in std_logic;    -- CMOSカメラからのpclk
        cam_data    : in std_logic_vector(7 downto 0);    -- CMOSカメラからのデータ
        cam_clk        : out std_logic;
        
        Bus2IP_Clk                     : in  std_logic;
        Bus2IP_Reset                   : in  std_logic;
        IP2Bus_MstRd_Req               : out std_logic;
        IP2Bus_MstWr_Req               : out std_logic;
        IP2Bus_Mst_Addr                : out std_logic_vector(0 to C_MST_AWIDTH-1);
        IP2Bus_Mst_BE                  : out std_logic_vector(0 to C_MST_DWIDTH/8-1);
        IP2Bus_Mst_Length              : out std_logic_vector(0 to 11);
        IP2Bus_Mst_Type                : out std_logic;
        IP2Bus_Mst_Lock                : out std_logic;
        IP2Bus_Mst_Reset               : out std_logic;
        Bus2IP_Mst_CmdAck              : in  std_logic;
        Bus2IP_Mst_Cmplt               : in  std_logic;
        Bus2IP_Mst_Error               : in  std_logic;
        Bus2IP_Mst_Rearbitrate         : in  std_logic;
        Bus2IP_Mst_Cmd_Timeout         : in  std_logic;
        
        IP2Bus_MstWr_d                 : out std_logic_vector(0 to C_MST_DWIDTH-1);
        IP2Bus_MstWr_rem               : out std_logic_vector(0 to C_MST_DWIDTH/8-1);
        IP2Bus_MstWr_sof_n             : out std_logic;
        IP2Bus_MstWr_eof_n             : out std_logic;
        IP2Bus_MstWr_src_rdy_n         : out std_logic;
        IP2Bus_MstWr_src_dsc_n         : out std_logic;
        Bus2IP_MstWr_dst_rdy_n         : in  std_logic;
        Bus2IP_MstWr_dst_dsc_n         : in  std_logic;

        IP2Bus_MstRd_dst_rdy_n         : out std_logic;
        IP2Bus_MstRd_dst_dsc_n         : out std_logic;
        
        afifo_overflow                    : out std_logic;
        afifo_underflow                    : out std_logic
    );
end Cam_Controller_Top;

architecture RTL of Cam_Controller_Top is
constant    DDR2_SDRAM_ADDR_START    : std_logic_vector(31 downto 0) := x"46000000"; -- 32MB目から1MBを使用する。

component Camera_Cntrler
    port(
        clk_cam        : in std_logic;
        clk_ddr2    : in std_logic;
        reset_cam    : in std_logic;
        reset_ddr2    : in std_logic;
        cam_href_2d    : in std_logic;
        cam_vsync_2d    : in std_logic;
        master_sync    : in std_logic;
        cam_data_2d    : in std_logic_vector(7 downto 0);
        address        : out std_logic_vector(18 downto 0);
        data_out    : out std_logic_vector(31 downto 0);
        addr_enable    : in std_logic;
        data_enable    : in std_logic;
        capture_ena    : in std_logic;
        afifo_empty    : out std_logic;
        afifo_rd_data_count    : out std_logic_vector(7 downto 0);
        afifo_overflow    : out std_logic;
        afifo_underflow    : out std_logic
    );
end component;
component synchronizer
    port(
        clk            : in std_logic;
        reset        : in std_logic;
        cam_vsync_1d    : in std_logic;
        cam_href_1d        : in std_logic;
        master_sync        : out std_logic
    );
end component;
component dcm_CAM_clk
    port(
        sysclk        : in std_logic;
        reset        : in std_logic;
        clk_cam        : out std_logic;
        dcm_locked_out    : out std_logic
    );
end component;

signal cam_href_1d, cam_href_2d : std_logic;
signal cam_vsync_1d, cam_vsync_2d : std_logic;
signal cam_data_1d, cam_data_2d : std_logic_vector(7 downto 0);
signal addr_ena, data_ena : std_logic;
signal master_sync : std_logic;
signal dcm_locked : std_logic;
signal clk_cam : std_logic;
signal reset_cam_node, reset_cam : std_logic;
signal reset_cam_srl : std_logic;
signal reset_cam_srl_1d, reset_cam_srl_2d : std_logic;
signal camc_addr : std_logic_vector(18 downto 0);
signal camc_data : std_logic_vector(31 downto 0);
signal afifo_empty : std_logic;
signal afifo_rd_data_count : std_logic_vector(7 downto 0);
type MST_TRANS_STATE is (IDLE_WR, COUNTER_SET, MPMC_WRITE_ST);
signal cs_wr : MST_TRANS_STATE;
type MST_CMD_STATE is (IDLE_CMD, CMD_ASSORT, WAIT_TRANSACTION);
signal cs_cmd : MST_CMD_STATE;
signal trans_count, trans_val : std_logic_vector(4 downto 0);
type MST_SOF_STATE is (IDLE_SOF, SOF_ASSORT, SOF_HOLD);
signal cs_wr_sof : MST_SOF_STATE;
signal wr_sof : std_logic;
signal wr_eof : std_logic;
signal wr_src_rdy : std_logic;
signal mst_addr, addr_cnt : std_logic_vector(31 downto 0);

begin
    IP2Bus_MstRd_Req <= '0';
    IP2Bus_Mst_Lock <= '0';
    IP2Bus_Mst_Reset <= '0';
    IP2Bus_MstRd_dst_rdy_n <= '1';
    IP2Bus_MstRd_dst_dsc_n <= '1';
    
    dcm_CAM_clk_inst : dcm_CAM_clk port map(
        sysclk => Bus2IP_Clk,
        reset => Bus2IP_Reset,
        clk_cam => clk_cam,
        dcm_locked_out => dcm_locked
    );
    reset_cam_node <= not dcm_locked;
    
    -- reset_cam を16クロック遅延される。クロックが出始めてすぐ、dcm_lockedが1になるため同期リセットFFがリセットされない。
    SRL16E_SDA_ena : SRL16E generic map(
        INIT => X"0000")
    port map(
        Q => reset_cam_srl,
        A0 => '1',
        A1 => '1',
        A2 => '1',
        A3 => '1',
        CE => '1',
        CLK => Bus2IP_Clk,
        D => reset_cam_node
    ); 
    
    -- clk_cam で同期化
    process(clk_cam) begin
        if clk_cam'event and clk_cam='1' then
            reset_cam_srl_1d <= reset_cam_srl;
            reset_cam_srl_2d <= reset_cam_srl_1d;
        end if;
    end process;
    reset_cam <= reset_cam_srl_2d;
    
    cam_clk <= clk_cam;
    
    process(clk_cam) begin
        if clk_cam'event and clk_cam='1' then
            if (reset_cam='1') then
                cam_vsync_1d <= '0';
                cam_vsync_2d <= '0';
                cam_href_1d <= '0';
                cam_href_2d <= '0';
                cam_data_1d <= (others => '0');
                cam_data_2d <= (others => '0');
            else
                cam_vsync_1d <= cam_vsync;
                cam_vsync_2d <= cam_vsync_1d;
                cam_href_1d <= cam_href;
                cam_href_2d <= cam_href_1d;
                cam_data_1d <= cam_data;
                cam_data_2d <= cam_data_1d;
            end if;
        end if;
    end process;
    
    Camera_Cntrler_inst : Camera_Cntrler port map(
        clk_cam => clk_cam,
        clk_ddr2 => Bus2IP_Clk,
        reset_cam => reset_cam,
        reset_ddr2 => Bus2IP_Reset,
        cam_href_2d => cam_href_2d,
        cam_vsync_2d => cam_vsync_2d,
        master_sync => master_sync,
        cam_data_2d => cam_data_2d,
        address => camc_addr,
        data_out => camc_data,
        addr_enable => addr_ena,
        data_enable => data_ena,
        capture_ena => '1',
        afifo_empty => afifo_empty,
        afifo_rd_data_count => afifo_rd_data_count,
        afifo_overflow => afifo_overflow,
        afifo_underflow => afifo_underflow
    );
    addr_ena <= '0';
    
    synchronizer_inst : synchronizer port map(
        clk => clk_cam,
        reset => reset_cam,
        cam_vsync_1d => cam_vsync_1d,
        cam_href_1d => cam_href_1d,
        master_sync => master_sync
    );
    
    -- afifo_rd_data_count が16以上になったらMPMCへWrite
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_wr <= IDLE_WR;
            else
                case cs_wr is
                    when IDLE_WR =>
                        if afifo_rd_data_count(7 downto 4)/=0 then -- 16以上
                            cs_wr <= COUNTER_SET;
                        end if;
                    when COUNTER_SET =>
                        cs_wr <= MPMC_WRITE_ST;
                    when MPMC_WRITE_ST =>
                        if trans_count=0 then
                            cs_wr <= IDLE_WR;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    IP2Bus_Mst_BE <= (others => '1');
    IP2Bus_Mst_Length <= CONV_STD_LOGIC_VECTOR(64, 12); -- 128バイト、32ビット幅、16バースト
    IP2Bus_MstWr_src_dsc_n <= '1';
    IP2Bus_MstWr_rem <= (others => '0');
    
    -- コマンド用ステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd <= IDLE_CMD;
                IP2Bus_MstWr_Req <= '0';
                IP2Bus_Mst_Type <= '0';
            else
                case cs_cmd is
                    when IDLE_CMD =>
                        if cs_wr=COUNTER_SET then
                            cs_cmd <= CMD_ASSORT;
                            IP2Bus_MstWr_Req <= '1';
                            IP2Bus_Mst_Type <= '1';
                        end if;
                    when CMD_ASSORT =>
                        if Bus2IP_Mst_CmdAck='1' then
                            cs_cmd <= WAIT_TRANSACTION;
                            IP2Bus_MstWr_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                    when WAIT_TRANSACTION =>
                        if Bus2IP_Mst_Cmplt='1' then
                            cs_cmd <= IDLE_CMD;
                            IP2Bus_MstWr_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;

    -- trans_count の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                trans_count <= (others => '0');
                trans_val <= (others => '0');
            else 
                if cs_wr=COUNTER_SET then
                    trans_count <= "10000";
                    trans_val <= "10000";
                elsif cs_wr=MPMC_WRITE_ST and trans_count/=0 and Bus2IP_MstWr_dst_rdy_n='0' then
                    trans_count <= trans_count - 1;
                elsif cs_wr=IDLE_WR then
                    trans_val <= (others => '0');
                end if;
            end if;
        end if;
    end process;
    
    -- IP2Bus_MstWr_sof_n のアサート
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_wr_sof <= IDLE_SOF;
                wr_sof <= '0';
            else
                case cs_wr_sof is
                    when IDLE_SOF =>
                        if cs_wr=COUNTER_SET then
                            cs_wr_sof <= SOF_ASSORT;
                            wr_sof <= '1';
                        end if;
                    when SOF_ASSORT =>
                        if cs_wr=MPMC_WRITE_ST and trans_val=trans_count and Bus2IP_MstWr_dst_rdy_n='0' then
                            cs_wr_sof <= SOF_HOLD;
                            wr_sof <= '0';
                        end if;
                    when SOF_HOLD =>
                        if cs_wr=MPMC_WRITE_ST and trans_count=0 then
                            cs_wr_sof <= IDLE_SOF;
                            wr_sof <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    IP2Bus_MstWr_sof_n <= not wr_sof;
    
    -- IP2Bus_MstWr_eof_n のアサート
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                wr_eof <= '0';
            elsif trans_count=2 and Bus2IP_MstWr_dst_rdy_n='0' then
                wr_eof <= '1';
            elsif trans_count=1 and Bus2IP_MstWr_dst_rdy_n='0' then
                wr_eof <= '0';
            end if;
        end if;
    end process;
    IP2Bus_MstWr_eof_n <= not wr_eof;
    
    -- IP2Bus_MstWr_src_rdy_n のアサート
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                wr_src_rdy <= '0';
            elsif cs_wr=COUNTER_SET then
                wr_src_rdy <= '1';
            elsif trans_count=1 and Bus2IP_MstWr_dst_rdy_n='0' then
                wr_src_rdy <= '0';
            end if;
        end if;
    end process;
    IP2Bus_MstWr_src_rdy_n <= not wr_src_rdy;
    
    IP2Bus_MstWr_d <= camc_data;
    
    -- addr_cnt の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                addr_cnt <= DDR2_SDRAM_ADDR_START;
            else
                if cam_vsync_1d='1' then
                    addr_cnt <= DDR2_SDRAM_ADDR_START;
                elsif wr_src_rdy='1' and Bus2IP_MstWr_dst_rdy_n='0' then
                    addr_cnt <= addr_cnt + 4;
                end if;
            end if;
        end if;
    end process;
    
    -- mst_addr の処理、コマンド転送の初めにaddr_cnt をmst_addr にコピーする
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_addr <= DDR2_SDRAM_ADDR_START;
            else
                if cs_wr=COUNTER_SET then
                    mst_addr <= addr_cnt;
                end if;
            end if;
        end if;
    end process;
    
    IP2Bus_Mst_Addr <= mst_addr;
    
    data_ena <= '1' when wr_src_rdy='1' and Bus2IP_MstWr_dst_rdy_n='0' else '0';

end RTL;


これのテストベンチとして、Cam_Controller_Top_tb.vhd を作った。ここには、IPICのインターフェースを組み込んであって、Cam_Controller_Top.vhd の相手をするようになっている。更に、CMOSカメラのモデル(OV7670_Model.v)をつないでいる。Cam_Controller_Top_tb.vhd を下に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY Cam_Controller_Top_tb IS
END Cam_Controller_Top_tb;
 
ARCHITECTURE behavior OF Cam_Controller_Top_tb IS 
    constant C_MST_DWIDTH : integer := 32;

    -- wait を入れるバースト位置、バーストの最初でwaitすることはできない。0を入れるとwaitはなしになる
    constant    RDY_WAIT_VAL1    : integer := 10;
    constant    RDY_WAIT_VAL2    : integer := 5;
    
    -- Component Declaration for the Unit Under Test (UUT)
    
    COMPONENT Cam_Controller_Top
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    PORT(
         cam_href : IN  std_logic;
         cam_vsync : IN  std_logic;
         cam_pclk : IN  std_logic;
         cam_data : IN  std_logic_vector(7 downto 0);
         cam_clk : OUT  std_logic;
         Bus2IP_Clk : IN  std_logic;
         Bus2IP_Reset : IN  std_logic;
         IP2Bus_MstRd_Req : OUT  std_logic;
         IP2Bus_MstWr_Req : OUT  std_logic;
         IP2Bus_Mst_Addr : OUT  std_logic_vector(0 to 31);
         IP2Bus_Mst_BE : OUT  std_logic_vector(0 to C_MST_DWIDTH/8-1);
         IP2Bus_Mst_Length : OUT  std_logic_vector(0 to 11);
         IP2Bus_Mst_Type : OUT  std_logic;
         IP2Bus_Mst_Lock : OUT  std_logic;
         IP2Bus_Mst_Reset : OUT  std_logic;
         Bus2IP_Mst_CmdAck : IN  std_logic;
         Bus2IP_Mst_Cmplt : IN  std_logic;
         Bus2IP_Mst_Error : IN  std_logic;
         Bus2IP_Mst_Rearbitrate : IN  std_logic;
         Bus2IP_Mst_Cmd_Timeout : IN  std_logic;
         IP2Bus_MstWr_d : OUT  std_logic_vector(0 to C_MST_DWIDTH-1);
         IP2Bus_MstWr_rem : OUT  std_logic_vector(0 to C_MST_DWIDTH/8-1);
         IP2Bus_MstWr_sof_n : OUT  std_logic;
         IP2Bus_MstWr_eof_n : OUT  std_logic;
         IP2Bus_MstWr_src_rdy_n : OUT  std_logic;
         IP2Bus_MstWr_src_dsc_n : OUT  std_logic;
         Bus2IP_MstWr_dst_rdy_n : IN  std_logic;
         Bus2IP_MstWr_dst_dsc_n : IN  std_logic;
         IP2Bus_MstRd_dst_rdy_n : OUT  std_logic;
         IP2Bus_MstRd_dst_dsc_n : OUT  std_logic;
         afifo_overflow : OUT  std_logic;
         afifo_underflow : OUT  std_logic
        );
    END COMPONENT;
    
    component OV7670_Model
        port(
            clk : in std_logic;
            resetx : in std_logic;
            vsync : out std_logic;
            href : out std_logic;
            pclk : out std_logic;
            ydata : out std_logic_vector(7 downto 0)
        );
    end component;
    
   --Inputs
   signal cam_href : std_logic := '0';
   signal cam_vsync : std_logic := '0';
   signal cam_pclk : std_logic := '0';
   signal cam_data : std_logic_vector(7 downto 0) := (others => '0');
   signal Bus2IP_Clk : std_logic := '0';
   signal Bus2IP_Reset : std_logic := '0';
   signal Bus2IP_Mst_CmdAck : std_logic := '0';
   signal Bus2IP_Mst_Cmplt : std_logic := '0';
   signal Bus2IP_Mst_Error : std_logic := '0';
   signal Bus2IP_Mst_Rearbitrate : std_logic := '0';
   signal Bus2IP_Mst_Cmd_Timeout : std_logic := '0';
   signal Bus2IP_MstWr_dst_rdy_n : std_logic := '1';
   signal Bus2IP_MstWr_dst_dsc_n : std_logic := '1';

     --Outputs
   signal cam_clk : std_logic;
   signal IP2Bus_MstRd_Req : std_logic;
   signal IP2Bus_MstWr_Req : std_logic;
   signal IP2Bus_Mst_Addr : std_logic_vector(0 to 31);
   signal IP2Bus_Mst_BE : std_logic_vector(0 to 3);
   signal IP2Bus_Mst_Length : std_logic_vector(0 to 11);
   signal IP2Bus_Mst_Type : std_logic;
   signal IP2Bus_Mst_Lock : std_logic;
   signal IP2Bus_Mst_Reset : std_logic;
   signal IP2Bus_MstWr_d : std_logic_vector(0 to 31);
   signal IP2Bus_MstWr_rem : std_logic_vector(0 to 3);
   signal IP2Bus_MstWr_sof_n : std_logic;
   signal IP2Bus_MstWr_eof_n : std_logic;
   signal IP2Bus_MstWr_src_rdy_n : std_logic;
   signal IP2Bus_MstWr_src_dsc_n : std_logic;
   signal IP2Bus_MstRd_dst_rdy_n : std_logic;
   signal IP2Bus_MstRd_dst_dsc_n : std_logic;
   signal afifo_overflow : std_logic;
   signal afifo_underflow : std_logic;
   
   type CMD_ACK_STATE is (IDLE_CMD_ACK, CMD_TRANS_1, CMD_TRANS_2, CMD_TRANS_3, CMD_TRANS_4, CMD_ACK_ST);
   signal cs_cmd_ack : CMD_ACK_STATE;
   signal cmd_ack : std_logic;
   type MST_WR_TRANS_STATE is (IDLE_MST_D, LOAD_COUNT_MST_D, MST_WR_TRANS_ST, COMPLETE_MST_D);
   signal cs_mst_d : MST_WR_TRANS_STATE;
   signal mst_wr_cnt, mst_length : std_logic_vector(11 downto 0);
    signal cam_resetx : std_logic;

   -- Clock period definitions
   constant Bus2IP_Clk_period : time := 16 ns; -- 62.5MHz
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Cam_Controller_Top 
        generic map(
            C_MST_AWIDTH => 32,
            C_MST_DWIDTH => C_MST_DWIDTH
        ) PORT MAP (
          cam_href => cam_href,
          cam_vsync => cam_vsync,
          cam_pclk => cam_pclk,
          cam_data => cam_data,
          cam_clk => cam_clk,
          Bus2IP_Clk => Bus2IP_Clk,
          Bus2IP_Reset => Bus2IP_Reset,
          IP2Bus_MstRd_Req => IP2Bus_MstRd_Req,
          IP2Bus_MstWr_Req => IP2Bus_MstWr_Req,
          IP2Bus_Mst_Addr => IP2Bus_Mst_Addr,
          IP2Bus_Mst_BE => IP2Bus_Mst_BE,
          IP2Bus_Mst_Length => IP2Bus_Mst_Length,
          IP2Bus_Mst_Type => IP2Bus_Mst_Type,
          IP2Bus_Mst_Lock => IP2Bus_Mst_Lock,
          IP2Bus_Mst_Reset => IP2Bus_Mst_Reset,
          Bus2IP_Mst_CmdAck => Bus2IP_Mst_CmdAck,
          Bus2IP_Mst_Cmplt => Bus2IP_Mst_Cmplt,
          Bus2IP_Mst_Error => Bus2IP_Mst_Error,
          Bus2IP_Mst_Rearbitrate => Bus2IP_Mst_Rearbitrate,
          Bus2IP_Mst_Cmd_Timeout => Bus2IP_Mst_Cmd_Timeout,
          IP2Bus_MstWr_d => IP2Bus_MstWr_d,
          IP2Bus_MstWr_rem => IP2Bus_MstWr_rem,
          IP2Bus_MstWr_sof_n => IP2Bus_MstWr_sof_n,
          IP2Bus_MstWr_eof_n => IP2Bus_MstWr_eof_n,
          IP2Bus_MstWr_src_rdy_n => IP2Bus_MstWr_src_rdy_n,
          IP2Bus_MstWr_src_dsc_n => IP2Bus_MstWr_src_dsc_n,
          Bus2IP_MstWr_dst_rdy_n => Bus2IP_MstWr_dst_rdy_n,
          Bus2IP_MstWr_dst_dsc_n => Bus2IP_MstWr_dst_dsc_n,
          IP2Bus_MstRd_dst_rdy_n => IP2Bus_MstRd_dst_rdy_n,
          IP2Bus_MstRd_dst_dsc_n => IP2Bus_MstRd_dst_dsc_n,
          afifo_overflow => afifo_overflow,
          afifo_underflow => afifo_underflow
        );

   -- Clock process definitions
   Bus2IP_Clk_process :process
   begin
        Bus2IP_Clk <= '0';
        wait for Bus2IP_Clk_period/2;
        Bus2IP_Clk <= '1';
        wait for Bus2IP_Clk_period/2;
   end process;

   -- IPIC のマスタRead, Writeの対応をするモジュール、バースト対応のみ  
   -- まず、コマンド転送に応答して、Bus2IP_Mst_CmdAck を返す
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd_ack <= IDLE_CMD_ACK;
                cmd_ack <= '0';
            else
                case cs_cmd_ack is
                    when IDLE_CMD_ACK =>
                        if IP2Bus_MstRd_Req='1' or IP2Bus_MstWr_Req='1' then
                            cs_cmd_ack <= CMD_TRANS_1;
                        end if;
                    when CMD_TRANS_1 =>
                        cs_cmd_ack <= CMD_TRANS_2;
                    when CMD_TRANS_2 =>
                        cs_cmd_ack <= CMD_TRANS_3;
                    when CMD_TRANS_3 =>
                        cs_cmd_ack <= CMD_TRANS_4;
                    when CMD_TRANS_4 =>
                        cs_cmd_ack <= CMD_ACK_ST;
                        cmd_ack <= '1';
                    when CMD_ACK_ST =>
                        cs_cmd_ack <= IDLE_CMD_ACK;
                        cmd_ack <= '0';
                end case;
            end if;
        end if;
    end process;
    Bus2IP_Mst_CmdAck <= cmd_ack;
    
    -- バーストWriteを受ける
    -- IP2Bus_Mst_Lengthはバイト単位なので、C_MST_DWIDTH/8 で割ってバースト長を計算する
    -- データ転送の状態を表すステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_mst_d <= IDLE_MST_D;
                Bus2IP_Mst_Cmplt <= '0';
            else
                case cs_mst_d is
                    when IDLE_MST_D =>
                        Bus2IP_Mst_Cmplt <= '0';
                        if IP2Bus_MstWr_Req='1' then
                            cs_mst_d <= LOAD_COUNT_MST_D;
                        end if;
                    when LOAD_COUNT_MST_D =>
                        cs_mst_d <= MST_WR_TRANS_ST;
                    when MST_WR_TRANS_ST =>
                        if mst_wr_cnt=(C_MST_DWIDTH/8) and IP2Bus_MstWr_src_rdy_n='0' and Bus2IP_MstWr_dst_rdy_n='0' then
                            cs_mst_d <= COMPLETE_MST_D;
                            Bus2IP_Mst_Cmplt <= '1';
                        end if;
                    when COMPLETE_MST_D =>
                        cs_mst_d <= IDLE_MST_D;
                        Bus2IP_Mst_Cmplt <= '0';
                end case;
            end if;
        end if;
    end process;
    
    -- mst_wr_cnt の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_wr_cnt <= (others => '0');
                mst_length <= (others => '0');
                Bus2IP_MstWr_dst_rdy_n <= '1';
            else
                if cs_mst_d=LOAD_COUNT_MST_D then
                    mst_wr_cnt <= IP2Bus_Mst_Length;
                    mst_length <= IP2Bus_Mst_Length;
                    Bus2IP_MstWr_dst_rdy_n <= '0';
                elsif cs_mst_d=MST_WR_TRANS_ST then
                    if Bus2IP_MstWr_dst_rdy_n='0' then
                        mst_wr_cnt <= mst_wr_cnt - (C_MST_DWIDTH/8);
                    end if;

                    if mst_wr_cnt=((RDY_WAIT_VAL1+1)*(C_MST_DWIDTH/8)) and Bus2IP_MstWr_dst_rdy_n='0' then -- 1度wait
                        Bus2IP_MstWr_dst_rdy_n <= '1';
                    elsif mst_wr_cnt=((RDY_WAIT_VAL2+1)*(C_MST_DWIDTH/8)) and Bus2IP_MstWr_dst_rdy_n='0' then -- 1度wait
                        Bus2IP_MstWr_dst_rdy_n <= '1';
                    elsif mst_wr_cnt=(C_MST_DWIDTH/8) and IP2Bus_MstWr_src_rdy_n='0' and Bus2IP_MstWr_dst_rdy_n='0' then -- 最後なので、レディを1にする
                        Bus2IP_MstWr_dst_rdy_n <= '1';
                    else
                        Bus2IP_MstWr_dst_rdy_n <= '0';
                    end if;
                else
                    Bus2IP_MstWr_dst_rdy_n <= '1';
                end if;
            end if;
        end if;
    end process;
    
    Bus2IP_MstWr_dst_dsc_n <= '1';
    Bus2IP_Mst_Error <= '0';
    Bus2IP_Mst_Rearbitrate <= '0';
    Bus2IP_Mst_Cmd_Timeout <= '0';
    
    
    -- OV7670_Model のインスタンス
    cam_resetx <= not Bus2IP_Reset;
    OV7670_Model_inst : OV7670_Model port map(
        clk => cam_clk,
        resetx => cam_resetx,
        vsync => cam_vsync,
        href => cam_href,
        pclk => cam_pclk,
        ydata => cam_data
    );
        
    
  -- Stimulus process
   stim_proc: process
   begin    
      Bus2IP_Reset <= '1';
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      wait for Bus2IP_Clk_period*10;
      Bus2IP_Reset <= '0';

      -- insert stimulus here 

      wait;
   end process;

END;


すべてのファイルは貼れないので、この辺でProject Navigatorでプロジェクトを作って、VHDLファイルのデバックをするためにシミュレーションを行った。
Spa3A_SKit_OV7670_61_110901.png

dcm_CAM_clk.v はBus2IP_Clkの62.5MHzをピクセル・クロックの25MHzに変換するDCMモジュールだ。synchronizer.v はカメラのピクセル・データのはじめにmaster_sync信号を出力する回路となっている。
さて、これでSimulate Behavioral Model をダブルクリックしてISimでシミュレーションを行った結果を下に示す。
Spa3A_SKit_OV7670_59_110831.png

(ip2bus_mst_addrがip2bus_mstwr_reqが1の間に変化しています。これではまずいので、後で修正します)
(2011/09/01 20:25 : 画像を修正しました。ip2bus_mstwr_reqが1の間、ip2bus_mst_addrの値を固定しました)

これは、マスタWrite(カメラ回路なので)を行っているところだ。ここでは、テストベンチで7番目と12番目にわざとBus2IP_MstWr_dst_rdy_n を非アクティブにして、処理を遅延させている。Bus2IP_MstWr_dst_rdy_n を非アクティブにする位置はconstant値で設定することができる。
カメラ回路から入力されたデータは、1データ16ビットで、非同期FIFO(cam_cont_afifo)に入力されて、32個(32ビット幅で16個)たまったら32ビット幅で16個バーストで出力される。もう少し時間を縮めると、その様子がよくわかる。その図を下に示す。
Spa3A_SKit_OV7670_60_110831.png

(2011/09/01 20:25 : 画像を修正しました。ip2bus_mstwr_reqが1の間、ip2bus_mst_addrの値を固定しました)

その時間間隔は2.56usec となった。
64バイトを2.56usecごとに転送しているので、スループットは64Bytes / 2.54usec = 25MBytes/secとなる。
最大スループットは、4Bytes x 62.5MHz = 250MBytes/sec で、ちょうど最大スループットの1/10となっている。

ちなみに、Spartan-3A Starter Kit の EDK 使用時のDDR2 SDRAMの最大スループットは、125MHz x 2(DDR) x 2Bytes(16ビット幅) = 496MBytes/sec だ。

  1. 2011年09月01日 05:16 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0