FC2カウンター FPGAの部屋 FFをIOBに入れるためのVHDLの書き方(Synplify Pro編)
FC2ブログ

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

FPGAの部屋

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

FFをIOBに入れるためのVHDLの書き方(Synplify Pro編)

以前、PCI-Xバスへの出力信号のHDL記述で、わかりやすくVHDLコードを書く方法を模索したが、もっと賢いというか、確実なやり方がわかったので紹介する。
FRAME#とREQ64#は、64ビットアクセスしかしない場合は、同じ波形でよい。でも、FRAME#をREQ64#につないでしまうとIOBにFFが入らない。そこでFRAME#をREQ64#を同じに書いてある。
でもこれだと、論理合成の段階でFRAME#をREQ64#につながれてしまって、クロックからの出力時間を満足できない。
ソースはこれ。(Xilinx ISE 9.103i, Synplify Pro 8.5)

    -- FRAME#, REQ64#
    process(reset, clk) begin
        if reset='1' then
            framex <= 'Z';
            req64x <= 'Z';
        elsif clk'event and clk='1' then
            case mcs is
                when idle =>
                    if request='1' and gntx_1d='0' and framex_1d/='0' and irdyx_1d/='0' then -- requestされて、GNT#がアサートされて、バスがアイドルの時にスタート
                        framex <= '0';
                        req64x <= '0';
                    end if;
                when addr_cmd_assert =>
                    framex <= '0';
                    req64x <= '0';
                when attribute_phase =>
                    framex <= '0';
                    req64x <= '0';
                when wait_transaction =>
                    framex <= '0';
                    req64x <= '0';
                when m_trans_data =>
                    if (trans_complete='1') or (latency_timer_disconnect='1') then -- トランザクションが終了したか、もしくは、レイテンシ・タイマーがタイムアウトして、GNT#がアサートされていない状態でADBの境界のときは終了
                        framex <= '1'; -- 正常な状態
                        req64x <= '1';
                    elsif devsel_timeout='1' then -- DEVSEL#のデコードタイミングがタイムアウト
                        framex <= '1';
                        req64x <= '1';
                    elsif devselx_1d='1' and stopx_1d='0' then -- Target Abort(TRDY#='1'), Single Data Phase Disconnect(TRDY#='0')
                        framex <= '1';
                        req64x <= '1';
                    end if;
                when turn_around => -- 正常終了
                    if request='1' and gntx_1d='0' then -- 正常終了後にリクエストが来ているので、もう1度
                        framex <= '0';
                        req64x <= '0';
                    else
                        framex <= 'Z';
                        req64x <= 'Z';
                    end if;
                when stop_target => -- 異常終了
                    framex <= 'Z';
                    req64x <= 'Z';
                when drive_bus => -- バス・パーキング
                    framex <= 'Z';
                    req64x <= 'Z';
            end case;
        end if;
    end process;
    framex_out <= framex;
    req64x_out <= req64x;


こうするとSynplify Pro 8.5で論理合成した後のRTL図は下のようになる。
framx_req64x_synp_RTL_070806.png

ISE9.103iでインプリメントしてFRAME#とREQ64#を見るとこうなる。
framx_req64x_FPGA_Editor_1_070806.png

1つのロジックエレメントから2つの入出力パッドに出ているので、これではタイミングを満足しない。実際のタイミング解析の結果はこれ。

* COMP "pcix_req64_b" OFFSET = OUT 3.8 ns A | MAXDELAY| -1.014ns| 4.814ns| 1| 1014
FTER COMP "pcix_clk" | | | | |
------------------------------------------------------------------------------------------------------
* COMP "pcix_frame_b" OFFSET = OUT 3.8 ns A | MAXDELAY| -0.825ns| 4.625ns| 1| 825
FTER COMP "pcix_clk" | | | |


syn_keep や syn_preserve, syn_maxfan も試してみたがだめだった。
FRAME#とREQ64#の論理が同じなので、いろいろ試してみたが、フィードバックループができてしまった。IOBのFFにはフィードバックのパスがないので、フィードバックがあるとIOBに入れることができない。これは論理合成で対処しなくてだめなようだ。
Synplifyのマニュアルを見ていたら syn_useioff というそのもののディレクテブがあったので、これを使用して、IOB出力用FF記述とIOBトライステート・バッファ・イネーブル用FFの記述に分けてみた。(分けないとだめだった)(たぶんXSTにもあると思う)

XSTではIOB制約だそうだ。
attribute iob: string;
attribute iob of {component_name|entity_name|label_name}:{component|entity|label} is "(true|false|auto)";


ソースは下。


attribute syn_useioff : boolean;
attribute syn_useioff of framex : signal is true;
attribute syn_useioff of req64x : signal is true;
attribute syn_useioff of framex_enable : signal is true;
attribute syn_useioff of req64x_enable : signal is true;

......

    -- FRAME#, REQ64#
    process(reset, clk) begin
        if reset='1' then
            framex <= '-';
            req64x <= '-';
        elsif clk'event and clk='1' then
            case mcs is
                when idle =>
                    if request='1' and gntx_1d='0' and framex_1d/='0' and irdyx_1d/='0' then -- requestされて、GNT#がアサートされて、バスがアイドルの時にスタート
                        framex <= '0';
                        req64x <= '0';
                    end if;
                when addr_cmd_assert =>
                    framex <= '0';
                    req64x <= '0';
                when attribute_phase =>
                    framex <= '0';
                    req64x <= '0';
                when wait_transaction =>
                    framex <= '0';
                    req64x <= '0';
                when m_trans_data =>
                    if (trans_complete='1') or (latency_timer_disconnect='1') then -- トランザクションが終了したか、もしくは、レイテンシ・タイマーがタイムアウトして、GNT#がアサートされていない状態でADBの境界のときは終了
                        framex <= '1'; -- 正常な状態
                        req64x <= '1';
                    elsif devsel_timeout='1' then -- DEVSEL#のデコードタイミングがタイムアウト
                        framex <= '1';
                        req64x <= '1';
                    elsif devselx_1d='1' and stopx_1d='0' then -- Target Abort(TRDY#='1'), Single Data Phase Disconnect(TRDY#='0')
                        framex <= '1';
                        req64x <= '1';
                    end if;
                when turn_around => -- 正常終了
                    if request='1' and gntx_1d='0' then -- 正常終了後にリクエストが来ているので、もう1度
                        framex <= '0';
                        req64x <= '0';
                    else
                        framex <= '-';
                        req64x <= '-';
                    end if;
                when stop_target => -- 異常終了
                    framex <= '-';
                    req64x <= '-';
                when drive_bus => -- バス・パーキング
                    framex <= '-';
                    req64x <= '-';
            end case;
        end if;
    end process;
    
    process(reset, clk) begin
        if reset='1' then
            framex_enable <= '0';
            req64x_enable <= '0';
        elsif clk'event and clk='1' then
            case mcs is
                when idle =>
                    if request='1' and gntx_1d='0' and framex_1d/='0' and irdyx_1d/='0' then -- requestされて、GNT#がアサートされて、バスがアイドルの時にスタート
                        framex_enable <= '1';
                        req64x_enable <= '1';
                    end if;
                when addr_cmd_assert =>
                    framex_enable <= '1';
                    req64x_enable <= '1';
                when attribute_phase =>
                    framex_enable <= '1';
                    req64x_enable <= '1';
                when wait_transaction =>
                    framex_enable <= '1';
                    req64x_enable <= '1';
                when m_trans_data =>
                    if (trans_complete='1') or (latency_timer_disconnect='1') then -- トランザクションが終了したか、もしくは、レイテンシ・タイマーがタイムアウトして、GNT#がアサートされていない状態でADBの境界のときは終了
                        framex_enable <= '1'; -- 正常な状態
                        req64x_enable <= '1';
                    elsif devsel_timeout='1' then -- DEVSEL#のデコードタイミングがタイムアウト
                        framex_enable <= '1';
                        req64x_enable <= '1';
                    elsif devselx_1d='1' and stopx_1d='0' then -- Target Abort(TRDY#='1'), Single Data Phase Disconnect(TRDY#='0')
                        framex_enable <= '1';
                        req64x_enable <= '1';
                    end if;
                when turn_around => -- 正常終了
                    if request='1' and gntx_1d='0' then -- 正常終了後にリクエストが来ているので、もう1度
                        framex_enable <= '1';
                        req64x_enable <= '1';
                    else
                        framex_enable <= '0';
                        req64x_enable <= '0';
                    end if;
                when stop_target => -- 異常終了
                    framex_enable <= '0';
                    req64x_enable <= '0';
                when drive_bus => -- バス・パーキング
                    framex_enable <= '0';
                    req64x_enable <= '0';
            end case;
        end if;
    end process;
    framex_out <= framex when framex_enable='1' else 'Z';
    req64x_out <= req64x when req64x_enable='1' else 'Z';


こうするとSynplify Pro 8.5で論理合成してRTL図を見ると下のようになった。
framx_req64x_synp_RTL_2_070806.png

これでインプリメントすると下のようにタイミング制約の範囲に入った。

COMP "pcix_frame_b" OFFSET = OUT 3.8 ns A | MAXDELAY| 0.725ns| 3.075ns| 0| 0
FTER COMP "pcix_clk" | | | | |
------------------------------------------------------------------------------------------------------
COMP "pcix_req64_b" OFFSET = OUT 3.8 ns A | MAXDELAY| 0.752ns| 3.048ns| 0| 0
FTER COMP "pcix_clk" | | | | |


更にFPGA EditorでFRAME#のパッドを見ると、IOBにFFがしっかり入っている。
framx_req64x_FPGA_Editor_2_070806.png

これでOKとなったが、まだ他の入出力で最終段のFFがIOBに入っていないものがある。今のところ原因は不明だ。
  1. 2007年08月07日 17:38 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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