2013年7月14日日曜日

LatticeECP3用DDR3 SDRAMCの作成 10

デジタルオシロに続いて、もう一つだけ測定器を入手した。プログラマブルDC電源である。アナログ回路の実験等をやる場合に一つ欲しいなぁーと思っていたのだが、今回、デジタルオシロを購入したのとは違う中古測定器販売サイトで格安のものを発見し購入した。購入したのはAgilentのE3631Aという80W 3出力のプログラマブルDC電源だ。この機種は現在も製造・販売されており、新品はRSコンポーネンツ等からも購入可能なようだ。私が購入したのは中古品なので定価の1/5程度の値段だった。1ケ月の保証付きだった。このお店は校正機関への取り次ぎは行っておらず、したければ自分で何とかしてねっというスタイルのお店だった。


さて、DDR3 SDRAMCだが、これまではUSB-UART経由でメモリのリード/ライトチェックだったのでどうしてもアクセス間隔が開いてしまうので、LFSR、所謂M系列乱数発生器を用いたリード/ライトチェックモジュールを作成し、これによるチェックを行おうとしている。 私がLFSRというのを知ったのは、昔々、工学社のI/Oというパソコン系月刊誌(この月刊誌は今も発刊されているようである。)の別冊本でLFSRを使ったM系列乱数発生器の製作記事を読んだ時だ。シフトレジスタの途中の値をExORを介して初段に戻す回路を見て、へぇー、こんなに簡単にできるんだーっと思った。今回のモジュールを作成するにあたり、帰還多項式についてはwikipediaの記事を参考にした。

回路の概略動作は、まず、LFSRでリードライトする領域の開始アドレスと長さを得る。次にその領域に対してLFSRで発生させたパターンをライトし、次に、その領域をリードしてライトしたパターンが正しくリード出来ることをチェックする。データが全て一致したら pass countを+1し、不一致があった場合は fail countを+1する。この処理を繰り返し行う。また、チェックモジュールは2つ実装し、両モジュールによる競合試験もできるようにした。但し、同じ領域へのアクセスの競合を許すと、#1のモジュールがライトした後に#2のモジュールのライトが割り込んで、その領域を別の値で書き換えてしまい、その結果、その後の#1のリードチェックチェックでエラーとなってしまうため、領域は分けるようにしている。具体的には、メモリ領域は2分割しそれぞれを個別に担当させるようにした。

LFSRモジュールは以下のような感じで作成した。これはアドレス用の24bit LFSRである。初期値はパラメータ INIT とし、インスタンス毎に定義できるようにした。また、動的な値のロードもできるようにした。


全体の動作はステートマシンで制御している。

ST_IDLEは初期ステートであり、do_chkが1になると動作を開始する。ST_RANDはST_IDLEまたはST_STALL2からST_RAND遷移のタイミングで生成された乱数をそれぞれのレジスタにラッチさせるためのステートである。ST_WR_REQはDRAMCのMPIFポートに対してライト要求を行うステートでこれが受け入れられると次にST_SND_DATAに遷移し、ライトデータの転送を行う。これが完了するとST_STALL1に遷移し、しばらく待つ。この待ち時間の値もLFSRで生成している。当初は8bitで最大256サイクルまで待つようにしていたが、大きすぎるので8bitの下位4bitのみを使うこととし、最大16サイクルまでとした。ST_STALL1での待ちが完了するとST_RD_REQに遷移しMPIFに対して先ほどライトした領域のリード要求を行う。これが受け入れられると、ST_RCV_DATAに遷移してリードデータを受信する。書き込んだ数分のデータ受信が完了したらST_STALL2に遷移し、ここで再びストールする。この時の待ち時間はST_STALL1の時間と同一とした(特に意味は無い)。 ST_STALL2での待ちが完了すると、再びST_RANDに遷移し処理を繰り返す。

アドレスとデータ数についてはいっぱい-いっぱいのビット幅で生成しているので、アクセス範囲が担当領域を越える事も想定される。そこで、アクセス範囲が領域を越えるか否かをチェックし、越える場合は範囲を修正するという処理を行うようにした。


リードデータの照合は以下のようにしている。

ライトデータの初期値を保持しておき、これを期待値生成ようLFSRに初期値として設定し、リードデータが到着する度にパターンを生成させてこれとリードデータとを比較する。一致しない場合はフラグ f_fail が1になる。このフラグは1になると、そのリードサイクルが完了するまでは1を保持する。リードサイクル完了時に、pass_cntとfail_cntはf_failを参照し、その値に応じて各々を更新する。

以下はシミュレーション波形である。



以下のUART経由のアクセスと比べると、UART経由のアクセス密度が如何に低いかが判る。


次に実機で動作させた。
制御プログラムは以下のようになっており、RWCHK_CTRLに書き込む値によって、1モジュール単独動作または2モジュール同時動作を設定(起動)し、以降はそれぞれのpass count値とfail count値をリードし表示し続ける。


これで2モジュールを同時に動作させた。結果、頻度は低いがfailが発生するようだ。

1モジュール単独では1時間以上動作させてもfailは発生しない。

#1のみの場合

#2のみの場合


現在、DDR3は500MHz (1Gbps)で動作させているが、これを400MHz (800Mbps)に落としても同様であった。もしかすると、DRAMCよりも上位のMPIF周辺に問題があるのかも知れない。。。

うーむ。。。

0 件のコメント:

コメントを投稿

自作CPUで遊ぶ 25

まだ制御ソフトが完成していないので今まではスピンドルを移動するために一々簡単なプログラムを書いて移動させていたのだが、非常に面倒なのでCNCペンダント的なものを作ることにした。 右側の縦に2つ並んでいるスイッチ...