テストの考え方と流れ
- テストには従来から想定している、プロトコルを使用します。しかしながら今回は、バスプロトコルのマスターモジュールの記述を少し変更してテストを行います(後述)。
- トップモジュールのインターフェースとしては、クロック/リセット入力、DDR3 I/F、LED出力のみです。基本的には、電源投入直後から自動的にDDRへの連続ライト→DDRからの連続リード→データ比較→エラーがあればエラー表示の流れを繰り返します。
- DDRの初期化操作に関しては今回は動作周波数を考慮し、データシートに沿ってDDR3としては低速の400MHz動作でのパラメータを予めセットするようにします。
- マスターモジュールでは、アドレスとデータの「インクリメンタルデータ」を作成し、同じくインクリメンタルデータで作成した期待値とリードデータの比較を行います[1]。
- 実際の評価システムでは、基板上の8つのLEDで動作状況を確認します(下図参照)。いちばん左側のLEDは初期化完了を表し、初期化中は消灯、完了後点灯します。いちばん右側のLEDはエラー状態を表し、比較データ相違が発生した場合点灯します。真中の4つのLEDはデータカウントに合わせて実行中に順番にローテーションします。
OK時 | NG時 |
 |
 |
- エラーが発生した場合には、XilinxのChipScope Proツールを使用して問題点を解析します。
masterモジュールサンプル(RTL)
- 上記で説明したテストの考え方と流れに沿って記述したmasterモジュールのサンプルコードを以下に示します。
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2012, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// ***************************** MODULE HEADER *********************************
module master (
req, gnt, rxw, addr,
wrStrb, wrAck, wrFlush, wrData, wrMask,
rdStrb, rdAck, rdFlush, rdData,
omit, exec, error,
reset, clk
);
// ************************ PARAMETER DECLARATIONS *****************************
// topモジュールで再設定可能
parameter PAM = 32'hffffffff;
// バスの語長とバースト長、topモジュールで再設定可能
parameter NLR = 2; // Word Length Radix
parameter BLR = 2; // Burst Length Radix
parameter NL = 1<<NLR;
parameter NBL = 8<<NLR;
// ***************************** I/O DECLARATIONS ******************************
// Requestパス
output req;
input gnt;
output rxw;
output [31:0] addr;
// Write Dataパス
output wrStrb;
input wrAck;
input wrFlush;
output [NBL-1:0] wrData;
output [NL-1:0] wrMask;
// Read Dataパス
output rdStrb;
input rdAck;
input rdFlush;
input [NBL-1:0] rdData;
input omit;
input reset;
input clk;
// 実行動作中およびエラーを表示するLED出力
output [5:0] exec; // execution LED
output error; // diff error LED
// ************************** LOCAL DECLARATIONS *******************************
reg req;
reg rxw;
reg [31:0] addr;
// データマスクなし
reg [NBL-1:0] wrData;
wire [NL-1:0] wrMask = {NL{1'b0}};
// ライトストローブは常時有効
wire wrStrb = 1'b1;
wire wrAlloc = wrStrb & wrAck;
// リードストローブも常時有効
wire rdStrb = 1'b1;
wire rdAlloc = rdStrb & rdAck;
wire alloc = req & gnt;
reg [NBL-1:0] rdExp;
wire diff;
reg [16:0] rdCount;
reg [5:0] exec;
reg error;
// ******************************** MODULE BODY ********************************
// -----------------------------------------------------------------------------
// Req
always @(posedge clk)
if (reset)
req <= #1 1'b0;
else req <= #1 !omit & (addr <= PAM);
// アドレスインクリメント
always @(posedge clk)
if (reset)
addr <= #1 32'd0;
else if (alloc)
addr <= #1 (addr + (1<<BLR+NLR)) & PAM;
// アドレス上限までのライト/リード繰り返し
always @(posedge clk)
if (reset)
rxw <= #1 1'b0;
else if (gnt & (addr[31:BLR+NLR] == PAM[31:BLR+NLR]))
rxw <= #1 !rxw;
// -----------------------------------------------------------------------------
// Write Data Generate
// デバイスのデータバス幅に応じたライトインクリメントデータ作成
always @(posedge clk)
if (reset)
wrData <= #1 {NBL{1'b0}};
else if (wrAlloc)
wrData <= #1 wrData + {{NBL-1{1'b0}},1'b1};
// データマスクなし
/*
// Write Mask Generate
always @(posedge clk)
if (reset)
wrMask <= #1 {NL{1'b0}};
else if (wrAlloc)
wrMask <= #1 wrMask + {{NL-1{1'b0}},1'b1};
*/
// -----------------------------------------------------------------------------
// Read Expect Data Generate
// デバイスのデータバス幅に応じた期待値インクリメントデータ作成
always @(posedge clk)
if (reset)
rdExp <= #1 {NBL{1'b0}};
else if (rdAlloc)
rdExp <= #1 rdExp + {{NBL-1{1'b0}},1'b1};
// -----------------------------------------------------------------------------
// Read Check
// リードデータと期待値データの相違時error LED出力点灯
always @(posedge clk)
if (!reset)
error <= #1 1'b0;
else if (diff)
error <= #1 1'b1; // diff error
// Read Count (1Gbit DDR3 device)
always @(posedge clk)
if (reset)
rdCount <= #1 17'd0;
else if (rdData[7:0] == 8'hfe)
rdCount <= #1 rdCount + {16'b0,1'b1};
// 実行動作中、LED出力ローテーション点灯
// Execution Check
always @(posedge clk)
if (reset)
exec <= #1 6'd0;
else begin
casex (rdCount[16:15])
2'b00: exec <= #1 6'b000010;
2'b01: exec <= #1 6'b000100;
2'b10: exec <= #1 6'b001000;
2'b11: exec <= #1 6'b010000;
endcase
end
// リードデータと期待値データを比較
assign diff = rdAlloc & !omit & (rdData != rdExp);
endmodule
// *****************************************************************************
DDRの初期化とリフレッシュ
- 使うDDRのモデルのデータシートに沿って、トップモジュール内のファンクション処理により初期化を行います。具体的にはpAddrがDDRの端子をダイレクトにアサートすることで実施されます。もちろんこの期間、DDRにR/Wアクセスしてはいけません。今回使用するDDR3用の初期化フローを右図に示します。具体的な手順の内容と時間パラメータの詳細に関しては、実機で使用している1Gbit DDR3デバイスの資料を参照して下さい。
- 右に記載する初期化手順の中で、黄色い網掛けをしている項目のμオーダーの待機時間は設定ファンクションの簡略化のため、今回短い時間で割り切って制御を行っています。なお、現状の設定で初期化後の機能動作について問題ないことは実機上で確認できています。
- 今回はシステムの動作周波数を考慮して、DDR3では低速の400MHz両エッジ動作(1サイクル2.5ns)を前提に主要なパラメータを設定します。1Gbit DDR3デバイスでの概要は以下の通りですが、min条件ぎりぎりに設定していますので、400MHzより低速で動作させる場合は基本的にスペックを十分に満たしていると判断できます。
- AL(Aditive Latency) = 3
- CL(CAS Latecy) = 5
- WR(Write Recovery) = 6
- tRP(Pre-charge Command Period) = 5(12.5ns)
- tRRD(Active one Bank to Active other Bank Command Period) = 4(10ns)
- tRFC(Auto-refresh to Active/Auto-refresh Command Time) = 44(110ns)
- tRAS(Active to Pre-charge Delay) = 15(37.5ns)
- tRC(Active to Active Command Time) = 20(50ns)
- tWTR(Write to Read Turn-around Time) = 4(10ns)
- tFAW(Four Active Window) = 20(50ns)
- 上記の値から各パラメータを割り出しますが、その手法もDDR制御(論理)編で述べた考え方(DDRインターフェイス)を参照して下さい。
- DDRのリフレッシュはAuto-refreshを使用します。実際は、DDR制御側からACタイミング以内にAuto-refreshコマンドを発行しなければいけません。今回は、初期化終了後リフレッシュインターバルとリフレッシュコマンド発行を繰り返すファンクションで制御します。なお、リフレッシュインターバル(サイクル)のACタイミングについては今回の前提では28000(70us)となりますが、動作周波数が400MHzと異なる場合は28000×(動作周波数)/400で計算される値になる点に注意して下さい。
テストの開始と検証手順
- sdcCntlモジュールとsdcトップモジュールとその他、前述したマスターモジュール、および動作検証2で記述するテストモジュールサンプルを揃えます。またucfファイルも使用します。
- 動作周波数に関しては、デバッグ初期段階では論理確認を最優先に100MHz程度の低周波数から動作検証を始めます。周波数を変更する場合は、下図クロックコア設計過程画面[2]でOutput Clockパラメータ変更を行うことと、動作検証2に示す周波数に関するパラメータについて都度修正が必要です。
- あとはISE設計ツールでコンパイルを行いプログラム用データを作成、iMPACTプログラミングツールで実機にプログラムデータをダウンロードしたら、自動的に初期化とメモリライト/リードテストを行いエラーがあればLEDに表示されます。
- Readエラーがなければ動作周波数を上げていって動作限界周波数を見極めます。見極めの過程でエラーが発生した場合は、ISE設計ツールにてChipScopeデバッグツール用波形観測ファイル[3]を作成、DQS入力遅延パラメータの調整を行いながらエラー状況を確認、改善していきます。
テスト結果と測定波形
- まず最初に下記波形は、テストベンチモジュールを使用してISimシミュレーションツールで電源投入直後からリセット、初期化処理を表している波形(信号はピックアップ)です。リセットについては今回前述したようにACタイミングは暫定的に短く(全体で約15us)していますが、reset_n信号とcke信号の制御手順は仕様通りとなっています。また初期化コマンド投入後、req信号がアクティブになって通常のメモリライト処理を開始していることがわかります。
- この図は、上記のテストでリフレッシュを行っている期間の波形です。連続ライトアクセスの途中でAuto-refreshコマンドを発行している状況です。コマンド発行後はtRFCサイクル期間アクセスを行いません。
- この図は、reqアサート後の先頭のライトアクセス波形です。Write Latencyが設定通り8、バーストサイズが8、インクリメントデータが32bitで0x00000000〜0x00000003ライトされていることが分かります。
- ISimシミュレーションツールではリードアクセスでのDDR3からのDQS入力、リードデータ入力を定義したシミュレーションは今回行いません[4]ので、リードサイクルはエラー検証を含めてChipScopeデバッグツールを使用して確認します。この図は、masterモジュール内のリードデータと期待値データを比較してエラー判定を行った結果、データのbitエラーが検出された波形です。本来、0x00df0002がリードされるべきところで0x00df0003となっています。またsdcモジュールに入るところから0x00df0003となっていますので、PHY部での取り込みがうまくいっていないということが分かります。
- この図は、上記状態からPHY部のDQS入力遅延パラメータの調整を行ってエラーが発生しなくなった状態での先頭のリードアクセス波形です。これをクリアしたら動作周波数を上げていき、エラーが出たら調整を繰り返すという手順で動作限界周波数を見極めます。
- 動作限界周波数の見極めについては実装にあたってで述べた通り、DDRからのDQS入力と内部クロックのエッジタイミングに大きく依存します。今回の場合のその詳細についてはタイミング調整で記述します。またタイミング調整を行って最適化を行った最終のテストモジュールサンプルコードを動作検証2に示しています。
回路デザイン > 設計例 [DDR制御(実装)] > 動作検証1 次のページ(動作検証2) このページのTOP ▲