はじめに
本記事は、「はじめてのトランシーバーAgilex™ 5 / Agilex™ 3 編」の基礎編② となり、基礎編 1で作成したデザイン、テストベンチをもとに論理シミュレーションを実行する内容です。論理シミュレーターは Questa を使用しています。
使用するテストベンチのブロック図は以下になります。
基礎編 1 のデザイン作成 をおこなわずに、本記事から作業する場合は、基礎編 1 の末尾に添付されているファイルをご使用ください。また、本記事で作成するテストベンチ、およびシミュレーション結果 (wlf) は本記事の末尾に添付していますので参考にしてください。
1. テストベンチの準備
1-1. 使用するテストベンチ
基礎編 1 で生成したテストベンチは以下に生成されています。本記事では、これを変更して使用します。
1-2. 変更後のテストベンチの全体像
もとのテストベンチから変更する箇所は、おもに以下の 5 点です
(1) 生成されたクロック、リセットの信号をコメントアウト(名称変更するため)
(2) 使用する信号を宣言を追加
(3) BFM (Bus Functional Model) のクロック周波数を追記
(4) 各ポートを接続
(5) ユーザー側の動作等を追加
1-3. 使用する信号の宣言を追加
今回テストベンチで使用する信号を宣言します。以下のように追記してください。なお、クロック、リセット信号は、そのままでもよいですが、今回はわかりやすくするため名称を変更しておきます。そのため、元のクロック、リセット信号名の部分はコメントアウトします。
上記で追加した信号は以下になります。
wire clk_100m_clk;
wire clk_156m_clk;
wire reset_reset;
wire ninit_done;
wire xcvr_tx_ready;
wire xcvr_rx_ready;
wire o_tx_serial_data;
wire o_tx_serial_data_n;
wire i_rx_serial_data;
wire i_rx_serial_data_n;
wire[79:0] i_tx_parallel_data;
wire[79:0] o_rx_parallel_data;
wire rx_clkout_clk;
wire tx_clkout_clk;
reg [1:0] s_xcvr_tx_ready_2r;
reg [9:0] s_cnt_10b;
wire rcvd_data_valid;
wire[31:0] rcvd_data_32b_hi;
wire[31:0] rcvd_data_32b_lo;
1-4. BFM のクロック周波数を追記、信号名変更
生成されたクロックの BFM に出力する周波数を追記します。以下のように CLOCK_RATE パラメーターを追記してください。また、クロック、リセットの信号名も変更します。
上記のように追記したテキストは以下になります。
xcvr_sample_inst_clk_100m_bfm_ip #(.CLOCK_RATE(100000000)) xcvr_sample_inst_clk_100m_bfm (
.clk (clk_100m_clk) // output, width = 1, clk.clk
);
xcvr_sample_inst_clk_156m_bfm_ip #(.CLOCK_RATE(156250000)) xcvr_sample_inst_clk_156m_bfm (
.clk (clk_156m_clk) // output, width = 1, clk.clk
);
xcvr_sample_inst_reset_bfm_ip xcvr_sample_inst_reset_bfm (
.reset (reset_reset), // output, width = 1, reset.reset
.clk (clk_100m_clk) // input, width = 1, clk.clk
);
1-5. xcvr_sample の各ポートの接続
xcvr_sample のポート接続をします。以下のように記述してください。
追記するテキストは以下になります。
xcvr_sample xcvr_sample_inst (
.clk_100m_clk (clk_100m_clk),
.clk_156m_clk (clk_156m_clk),
.phy_i_tx_reset_tx_reset (ninit_done),
.phy_i_rx_reset_rx_reset (ninit_done),
.phy_o_tx_reset_ack_tx_reset_ack (),
.phy_o_rx_reset_ack_rx_reset_ack (),
.phy_o_tx_ready_tx_ready (xcvr_tx_ready),
.phy_o_rx_ready_rx_ready (xcvr_rx_ready),
.phy_o_tx_serial_data_o_tx_serial_data (o_tx_serial_data),
.phy_o_tx_serial_data_n_o_tx_serial_data_n (o_tx_serial_data_n),
.phy_i_rx_serial_data_i_rx_serial_data (i_rx_serial_data),
.phy_i_rx_serial_data_n_i_rx_serial_data_n (i_rx_serial_data_n),
.phy_o_tx_pll_locked_o_tx_pll_locked (),
.phy_o_rx_is_lockedtodata_o_rx_is_lockedtodata (),
.phy_o_rx_is_lockedtoref_o_rx_is_lockedtoref (),
.phy_i_tx_parallel_data_i_tx_parallel_data (i_tx_parallel_data),
.phy_o_rx_parallel_data_o_rx_parallel_data (o_rx_parallel_data),
.reset_reset (reset_reset),
.reset_release_ninit_done_ninit_done (ninit_done),
.rx_clkout_clk (rx_clkout_clk),
.tx_clkout_clk (tx_clkout_clk)
);
1-6. ユーザー側の動作等を追加
まず、シリアル信号をループバックさせるため、tx_serial_data と rx_serial_data を接続します。
続いて送信データについて記述します。 10bit カウンターを並列に接続することとします。今回は、パラレルデータの有効データ幅(PMA width)は32bit で、それを ダブル幅(Enable double width transfer) を有効にしていますので、合計 64 bit がユーザー側から入力できるデータ幅となります。これに対して、10 bit カウンタを 6 個と、最上位に 4 bit カウンターを 1 個接続するような入力パターンとなります。
最後に、受信データについて記述します。今回は記述を最小限にしたいので、アライメントせずにそのまま確認することとします。そのため、ビット位置が送信データとずれている状態となっています。
それぞれ 32bit を以下のように接続します。(※ ビット配置の詳細は GTS Transceiver User Guide をご参照ください)
追記するテキストは以下になります。
///////////////////////////////////////////////////////////////////
//// loopback ////
assign i_rx_serial_data = o_tx_serial_data;
assign i_rx_serial_data_n = o_tx_serial_data_n;
///////////////////////////////////////////////////////////////////
//// tx parallel data ////
always@(posedge tx_clkout_clk or posedge reset_reset) begin
if (reset_reset)
s_xcvr_tx_ready_2r <= 2'h0 ;
else
s_xcvr_tx_ready_2r <= {s_xcvr_tx_ready_2r[0], xcvr_tx_ready} ;
end
assign s_xcvr_tx_ready = s_xcvr_tx_ready_2r[1];
always@(posedge tx_clkout_clk or negedge s_xcvr_tx_ready) begin
if (~s_xcvr_tx_ready)
s_cnt_10b <= 10'h000 ;
else
s_cnt_10b <= s_cnt_10b + 10'h001 ;
end
//// assign tx parallel data ////
assign i_tx_parallel_data[79:72] = 8'h80;
assign i_tx_parallel_data[71:40] = {s_cnt_10b[3:0], s_cnt_10b, s_cnt_10b, s_cnt_10b[9:2]};
assign i_tx_parallel_data[39:32] = 8'h40;
assign i_tx_parallel_data[31: 0] = {s_cnt_10b[1:0], s_cnt_10b, s_cnt_10b, s_cnt_10b};
///////////////////////////////////////////////////////////////////
//// rx parallel data ////
assign rcvd_data_valid = o_rx_parallel_data[38];
assign rcvd_data_32b_hi = o_rx_parallel_data[71:40];
assign rcvd_data_32b_lo = o_rx_parallel_data[31:0];
2. シミュレーション実行
1 章で準備したテストベンチを使用して論理シミュレーションを実行します。今回は Questa を使用する手順を紹介します。
2-1. Change Directory
Questa を起動後、Change Directory をおこないます。 File ー> Change Directory で実行します。以下の mentor フォルダーに移動してください。
(プロジェクト・フォルダー)\xcvr_sample_tb\xcvr_sample_tb\sim\mentor
2-2. シミュレーション実行
フォルダー移動後、トランスクリプト・ウィンドウに以下を入力します。
do msim_setup.tcl
ld
参考:コマンド入力はタブで予測変換されます。
参考:ld の代わりに ld_debug と入力する手順もあります。
これにより、以下の画面が表示されます(表示されるまで時間がかかります)
シミュレーションを実行する前に wave 画面に確認する信号を追加します。今回は、テストベンチ(xcvr_sample_tb) の信号をすべて表示させることとします。
xcvr_sample_tb を右クリックし、 Add Wave を選択します。ドラッグ&ドロップで Wave 画面に追加することもできます。
トランスクリプト・ウィンドウで、run 50 us と入力します。シミュレーションが 50 us 実行されて、以下のような波形が表示されます。
参考:wave 画面の表示設定は、Windows Preference で設定できます(Tools -> Windows Preference)。以下のように、信号名の階層の表示数、表示する時間の単位などを設定できます。
受信データとして、rcvd_data_32b_hi、rcvd_data_32b_lo を確認します。これは、rx_parallel_data から有効データの部分を抽出した信号です。アライメントはしていないので、ビットの位置はずれる可能性がありますが、ここでは 10 bit カウンターと 4 bit カウンターが確認できればよいかと思います。
参考:送信データは 64 bit で、10 bit カウンターを 6 個と 4 bit カウンターを 1 個配置しています。それを tx_parallel_data の 80bit に組み込んで送信しています。一方、受信データは rx_parallel_data (80 bit) から 64 bit データを抽出しますが(rcvd_data_32b_hi、rcvd_data_32b_lo)、今回はアライメントをおこなっていないので、64bit のビット0の位置がずれています。以下は受信データの一例です。
おわりに
本記事は、以上となります。引き続き、以下の実機動作確認を実施してください。
はじめてのトランシーバー Agilex™ 5 / Agilex™ 3 編
おすすめ記事:Altera FPGA の開発フロー
添付ファイル
本記事で作成するテストベンチ、およびシミュレーション結果 (wlf) のサンプルです。