|
|
このページでは、当社で開発したIPやトランスレータを使ってVHDLコアをVerilogに翻訳したもの、OpencoresのVerilog等を紹介していきます。
とりあえず、既存の設計例を通して、CPUアーキテクチャ、HDLコーディング技法の研究にお役になれば幸いです。
1.ベンチマークテスト
同じCソースプログラムをシミュレータ上で動かして総クロック数を評価してみます。Cソースプログラムは、リードソロモン(5インターリーブ、3重訂正)です。下記オープンソースコアについて行いました。
駆動周波数の比較ではなくCPIの比較であることと、オリジナルとの比較ではなく、Opencores上での比較であることに注意してください。
注意:コンパチブルコアは、オリジナルと命令の実行ステート数が異なります。あくまでオープンソースコア上の実行時間比較であることに注意してください。
この評価の観点としては、同じクロック周波数で駆動していますので(RTLシミュレーション、仮想50MHz)、時間=クロック数でよいと思います。Cコンパイラも含めたCPIの評価に近いことになります。
また、8ビット演算が主体なので、8ビットCPUにとって不利にはならない(8ビットCPUが得意なはずの)ベンチマークになっています。
面白いのは、大体設計時代順に並んでいることです。
H8300Hは、筆者による設計Versionですが、オリジナルより30%以上CPIを高速化しているためAVRより速い結果になっていますが、オリジナルの実行ステート数ではAVRと同等ではないかと推察します。
さらに、AVRは比較的最近の石でかつゲート数もH8300Hよりはかなり少ないと見られます。CISCからRISCの流れ、アーキテクチャの進歩がこのグラフから読みとれると思います。
そんな流れの中で、RISCの草分け的存在であるMIPSは80年代の設計です。
MIPSの先見性を物語っていますね。オリジナルCPUを設計するにあたってどれを規範にするべきか参考になるのではないでしょうか?
なお、YACCは筆者による設計でやはりPLASMAと同じMIPSアーキテクチャを規範にしています。
詳細は、YACCプロジェクトのページをご参照ください。
また、オリジナルCPUを作っている方を見つけました。YACCと比較していただいています。なんと200MHzオーバというから驚きです。しかも、DMIPS/MHzが1を超える事を狙っているというから驚き2倍です。
(シングルで1を超えるのは、かなりの最適化コンパイラがないと、きつい感じがします。)
でも、アイデアが浮かんで、CPUを作ってしまう。。この乗りは、私も好きで見ていても楽しいです。アーキテクチャから自作するのは、本当に楽しいものです。
MAX2で動く、オリジナルCPUを製作してみました。僅か240セルで動作します。CPU設計の入門編という感じですが、16ビット演算でパターン生成もでき、実用性も追求しています。
。また、VPIで作成した強力なVisualデバッガも付属しており、CPUの動作原理の理解に役立つと思います。
<Z80について>
PC8001で有名なFZ80コアを追加しました。
FZ80が、WB_Z80を抜いて最速のCPI、Z80コアとなりました。4本のZ80コアがそろいました。同じ機能を実現するものでありながら、そのCoding方法の違いを見ると面白いでしょう。T80やTV80は、Behaviorで書いています。
一方、WB_Z80/FZ80はゲートレベルに近い書き方をしています。合成器の差が出やすいのは、抽象度の高いBehaivorで、狙った性能とゲート数で見通しがよいのは、
ゲートレベルに近い(回路図に近い)書き方をしている方でしょう。FZ80は、コンパイラの貧弱性を補って8051に迫る凄いものがあります。しかし、そのコアも、Version1.04以前では、このベンチが走りませんでした。
公開=>実際に使われる=>Feedbackというサイクルの図式があるように思います。この流れにうまく乗ると自然と完成度が上がっていくのでは?と思いました。
このほかに6502を使ったコアもあるのですが、適当がCコンパイラが見つからず、留保状態になっています。
CPUアーキテクチャの研究には、MIPSアーキテクチャからはいることをお勧めしています。
Z80よりはるかにシンプルなデコーダは、入門として最も適していると思います。Simple is bestの設計思想が貫かれたアーキテクチャになっています。たとえば、H8のALU記述とYACCのALU記述、デコーダを比較してみてください。
デコーダの比較は、YACCが5段パイプラインかつ、合成後の速度最速を意識徹底した書き方になっているので単純な比較はできないのですが、ソースを見ていただければそのシンプルさがお分かりでしょう。
また、有名なヘネパタ本のモデルCPU DLXは、MIPSアーキテクチャの原点になっています。(DLXのコンパイラを探すより現役のGCCがあります。)
加えて、NiosU(アーキテクチャが変更されました。)、MicroBlaze共、MIPSアーキテクチャに酷似していることにお気づきでしょうか?
ハードウェアがシンプル=>合成後の速度が上げやすい=>駆動周波数UP=>DMIPSの向上、という図式になっています。上図は、CPIでの比較ですが、合成後の速度(DMIPS)では、さらに差が開くことになります。
SH2もRISCはRISCなのですが、16ビットに命令を収める機構とCISC的な命令があったりして、MIPSアーキテクチャよりデコーダの負担は、重いはずです。
Openriscが振るわないのは、1ポートRAMで駆動していることもありますが、キャッシュやMMUを積むとその分のオーバヘッドが大きくなるせいでしょう。(PLASMAは、1ポートRAM駆動で、それとの比較です。
条件:DATA /Instruction共8KBキャッシュ)DIV演算をNativeでサポートしていないこともあって、コードサイズが肥大化するのも気になりました。それにしても、もう少し頑張れるはずなのですが。。
鳴り物入りで、登場しただけにちょっと寂しい気がします。
これを設計したのは、opencoresを主催する、Damjan Lampretという人で、当時スロベニア、リュブリャナ大学の一学生というのは、驚嘆に値します。今後、Opencoresがどのような位置を占めるのか興味深いです。
2. AESコア(終了)
CQ出版社のデザインウェーブコンテスト2004に応募した設計レポートです(加筆修正していません)。
AESは次世代のDESに代わる暗号コアです。課題は、AESに使われるSUBBYTESという部品を設計するものでしたが、それだけでは、実用的ではないので、AESそのものを設計してしまいました。
結構気合を入れて設計したのですが、惜しくも努力賞という結果に終わりました。
とはいえ、LUT2500程度(LUTだけなら雑誌付録についてくるFPGAに入ります。)で、CLOCK200MHz超、スループット2.7Gbpsは、FPGAとして世界最速ではないかと思います。
本コアは、TOP階層でパイプライン部とFIFOをインスタンス化しているので、容易に拡張できるようにしています。理論的には、インスタンス数を10にすれば、10倍のスループットになる筈ですが、合成するとがっかりするような結果になります。
これはFPGAで、限界に近い使い方をすると配線遅延がボトルネックとなるためです。何でもない論理が5nsを超えてしまうことに唖然としてしまいます。FPGAでも大規模なロジックはきちんとフローアプランをしないといけないということでしょう。
3.H8互換CPUの設計(Under Development Jul.28.2004 Update)
オープンコアで未だ誰も先鞭をつけていないもの、比較的メジャー、GCCが動くものということで、H8300Hを設計してみます。
とりあえず、仕様は、主要な命令を取り込んだサブセット仕様とします。
時代物のCPUなので、オリジナルCPU設計為のリファレンスにはなり得ませんが、基本的な設計手法は、マイクロプロセッサの仕組みを理解する上で参考になると思います。
シミュレータ上でドライストーンベンチを計測しました。
H8 BASICをなんとアセンブラで書いている方をみつけました。そのうち遊んでみたいと思います。
ご要望もいただいていますが、いかんせんYACCと比べるとDMIPS/リソース比が1/20くらいになってしまうので、モチベーションが低いです。
CPI重視を捨てて、完全なマイクロコード化を(ROM化)した方が、リソースを少なくでき、FPGA向きかな、と思います。
3Eのスタータでは、32MBのRAMが実装されているようなので、
UCLINUXのよいプラットフォームになる可能性があります。
なんと、H8で、TCP/IPを書いている方を見つけました。これは、面白いです。もし、H8プロジェクトで動くようにしたら、C言語と、FPGAと、
CPUとアセンブラとイーサネットとTCP/IPとVerilog-2001が一緒に勉強できる(遊べる)、ごった煮のような凄いプロジェクトになることでしょう?!
(3Eは、LANのPHYもついているようです。)
開発Snapshot
なにも変わっていませんが、RTLソースとVeritak Projectです。ツールのソースもどこから持ってきたか忘れてしまいました。
HEXファイルは、例の特製ベンチマークになっています。(メモリは、Alteraライブラリを使用していますが、アーカイブは、含んでいません。
別途、altera_mf.v をCOPY、set してください。)
4.YACCプロジェクト(Yet Another CPU CPUの略??です。 Opencoresのページです。)
=>
次のような質問がありましたので、少しまともな割り込みコントローラを記述してみたいと思います。
Hi Tak-san,
Couple of months ago I successfully interfaced Yacc with a dsp hardware
blocked. I was able to program hardware blocks configuration registers
and share its RAMS.
Now I want to interface interrupts generated by the hardware block to YACC.
The main idea is that when once the hardware block has finished its job
it raises the interrupt.
This interrupt causes the yacc to jump to a interrupt service routine which
inspects some registers, sets up the next task and returns to normal execution.
また、マルチタスクスイッチャや、VCMによるデジタルサーボコントローラを記述し、サーボシミュレーションして遊んでみましょう。。
<マルチタスクスイッチャ>
OSが必要なレベルではないけれどもタスクは分けたい、そんな組み込み用途にびったりです。各タスクは、
task_switch();
を呼ぶことで切り替わります。 例えば、UARTの出力をやりながら、コマンドを受け取って解析したり。。これらのタスクは、自分の仕事がひと段落したら、次の
タスクにスイッチします。順番がやってきたら、また自分がすることして次に渡します。タスクが順番に回るだけですが、各タスクは、専用のスタックをもっているので、
自分の仕事に専心できます。MIPSの場合32個もレジスタがあるので、タスク切り替えのオーバヘッドが大きいのですが、ここはよしとしましょう。
サーボは、一定時間毎の処理が必要なので、上記とは別にTimer割り込みによる最優先処理になります。
とりあえず、
・割り込みコントローラの仕様決め。
・HDL記述
・割り込みルーチンの雛形記述
・タスクスイッチの記述
・デモサーボの仕様決め
・サーボコントローラの記述
..
結構ありますね。。
最終的には、シミュレータ上で、CPUが動いてサーボが外乱にめげずに目標に追従する様子を見てみたいと思います。
YACCについては、外部パスに接続可能なCPUの設計ということでこちらで再設計中です。
DWMデザインコンテスト2006上級課題を解く
システム(アルゴリズム・アーキテクチャ)設計に始まり、RTL コーディング、ゲートシミュレーションと、落としていくまとまった記述というのは、
企業や・研究室の奥底にあるもので、あまり公開されていないように思います。Verilog HDLで画期的だったのは、まがりなりにも単一の言語で全てを記述できることです。
この、
- システム(アルゴリズム・アーキテクチャ)設計
- RTL
- ゲートレベル
という段階を踏むやり方は、いわゆるトップダウン手法でもあります。実体は、一つなのですが、それは、抽象から具体へ展開され、置き換えられていく過程でもあります。
コンテストという共通の題材を借りて、一つの(実用的な)IPを作成することを楽しんでいますが、少しでも参考になる記述が見つかれば幸いです。
恒例のコンテストの季節になりました。符号理論がらみの出題が多いのですが、今年の問題は、難問ではないでしょうか?
この積符号のデコーダは、ターボ符号やLDPCといった最近の符号理論の成果のエッセンスに迫るものです。
このように、受信値のアナログ値を使って訂正確率を向上させる方式を軟判定(Soft
Decision)と呼んでいます。
1.準備
システムのシミュレーションをVerilog HDLで行おうとするとAWG(additive white
Gaussian ) Noiseを生成する必要があります。Verilog 2001では、
$dist_normal関数で、AWGNを生成できるのですが、残念なことに仕様上、入力・出力パラメータ共、integerになっていて、量子化誤差が
つまないところで入ってしまいます。(どうして、このような仕様になったか全く意味不明です。) 理想値との比較検証する上でも、最初の
検討は、量子化誤差の入らないreal(c言語でのdouble)精度で簡単に行いたいですね。そこで、Veritakでは、real版の$normal_vtakをVPIで作成してみました。(1.83からビルトインしています。)
これで、Cで書かなくとも、最終のHard回路の検証まで、Verilog HDL上で自由に記述することができます。
1.1 $dist_normalの使い方
サンプルです。
//Oct.11.2005
//random_sn.v
module random_sn;
parameter integer No=10;
real sd,mean;
real a;
integer seed1;
integer i;
real sdf_array[0:No-1] ;
real sum,avg,sd2;
real expected_mean=-10;
real expected_sd=2.0;
integer result;
initial begin
#10;
seed1=0;
sum=0;
for (i=0;i<No;i=i+1) begin
`ifdef Veritak
a=$normal_vtak(seed1,expected_mean,expected_sd);
`else
result=$dist_normal(seed1,$rtoi(expected_mean),$rtoi(expected_sd));
a=$itor(result);
`endif
sdf_array[i]=a;
sum=sum+a;
$display(" a=%f seed=%d",a,seed1);
end
avg=sum/No;
sum=0;
for (i=0;i<No;i=i+1) begin
a=sdf_array[i]-avg;
sum=sum+a*a;
end
sd2=sum/No;
`ifdef Veritak
sd=$sqrt(sd2);
$display("Total %d ",No);
$display("Expected Avg=%f SD=%f ",expected_mean,expected_sd);
$display("Results Avg=%f SD=%f SD2=%f",avg,sd,sd2);
$display("Difference Avg=%f SD=%f",$fabs(expected_mean-avg),$fabs(expected_sd-sd));
`else
$display("Total %d ",No);
$display("Expected Avg=%f SD2=%f ",expected_mean,expected_sd*expected_sd);
$display("Results Avg=%f SD2=%f",avg,sd2);
`endif
end
endmodule
Veritakの実行結果です。このプログラムでは、平均(mean)=-10.0, 標準偏差=2.0狙いで生成しています。
F:\regression_test\complex\random_sn.v(3)::random_sn
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
a=-9.107809 seed= 1082744015
a=-9.710610 seed= -958425333
a=-9.057617 seed=-2032678137
a=-7.126455 seed=-1634874387
a=-12.131116 seed= 1427361855
a=-9.270853 seed= 1735824513
a=-11.797993 seed= 1657425015
a=-7.087418 seed= 1586374365
a=-12.799056 seed=-2056026887
a=-13.158670 seed=-1872486481
Total 10
Expected Avg=-10.000000 SD=2.000000
Results Avg=-10.124760 SD=2.108805 SD2=4.447058
Difference Avg=0.124760 SD=0.108805
ModelSimの実行結果です。
# Loading work.random_sn
run -all
# a=-9.000000 seed= 1082744015
# a=-10.000000 seed= -958425333
# a=-9.000000 seed=-2032678137
# a=-7.000000 seed=-1634874387
# a=-12.000000 seed= 1427361855
# a=-9.000000 seed= 1735824513
# a=-12.000000 seed= 1657425015
# a=-7.000000 seed= 1586374365
# a=-13.000000 seed=-2056026887
# a=-13.000000 seed=-1872486481
# Total 10
# Expected Avg=-10.000000 SD2=4.000000
# Results Avg=-10.100000 SD2=4.690000
seed は、randomの種、でこれがrandomのSEQを決めています。Verilog 2001では、生成互換なので、同じseedを与えれば、
シミュレータに依存せず、同じ生成SEQになります。$dist_normalを呼ぶと、seed&で呼んだみたいに次のseed値が返ってきます。
次回呼び出しでは、この返ってきた値で呼ぶことで、AWGNになります。$dist_normalでは、整数で返ってきてしまい狙いSDからの誤差も
大きくなってしまいます。
そこで、これ以降は、Veritak独自システムタスクを使うことにします。
少し、サーベイしてみました。課題は、水平垂直パリティコードをSum-Productアルゴリズムで解いています。パリティ方程式が違うので
LDPCではありませんが復号法は、LDPCそのものです。
とりあえず、硬判定でも1ビットの誤り訂正はできます。Hamming Codeは、符号長7ビットで、1ビット訂正できますから、それだけを見ると、
効率はよくありません。BP(Belief Propagation)復号法が真価を発揮するのは、このような短い符号長ではなく
ある程度長い符号長です。ただし、今回の符号は、LDGMというパリティの作り方になっていて、LDPCに比べて特性差が知られています。
硬判定のストラテジの検討
下表で、y0-y3がデータ、ro-r1が、行パリティ、c0-c1が列パリティで、y0-y3-r0-r1-c0-c1の順で送ります。
単純にパリティマトリクスを式に書き下すと、
y0+y1 +r0 =0
-(1)
y2+y3+ r1 =0 -(2)
y0+ y2+ +c0 =0 -(3)
y1+ y3 +c1=0
-(4)
になります。 ここで、一個だけエラーが発生したと仮定します。
<パリティビットに発生した場合>
この場合は、各バリティは、(1)-(4)まで、独立した式になっています。したがって、(1)-(4)までのどれか、一式だけが、満たさないケースは、
パリティビットのエラーと考えることができ、データビット(y0-y3)の訂正は必要ありません。
<データビットに1個のデータエラーが発生した場合>
仮にy0にエラー量e0が生じたとします。そうすると、式を満たさないのは、(1)、(3)だけになります。
同様にして以下のようにまとめることができます。
1個のエラー |
パリティエラーとなる式 |
訂正 |
y0 |
(1),(3) |
y0^=1; |
y1 |
(1),(4) |
y1^=1; |
y2 |
(2),(3) |
y2^=1; |
y3 |
(2),(4) |
y3^=1; |
r0 |
(1) |
必要ない |
r1 |
(2) |
必要ない |
c0 |
(3) |
必要ない |
c1 |
(4) |
必要ない |
データの訂正は、データビットを反転させてやれば、よいです。回路にするのも、簡単ですね。
2個エラーが発生した場合は、どうでしょうか?単純には、行かないですね。たとえば、y0,y1にエラーが生じたことと、c0,c1にエラーが生じたことを
区別できません。エラーが生じたことは、検出できそうですが、訂正までは、できません。さらに、3個エラーすると、1個のエラーと区別できなくなり、
誤訂正の可能性があります。4個エラーしたとすると、エラーがあったことすら検出できなる可能性があります。
(一般に、訂正と誤訂正は、確率の違いでしかありません。訂正するシステムは、必ず誤訂正確率について考察する必要があります。)
元のデータは、4ビットですから、符号の種類は、高々16個しかありません。しかしパリティをいれると8ビットすなわち256種類の
Data受信の可能性があります。受信した、256種類のデータ(アナログで考えると無限にありますが)は、元の16個の
どれに一番近いでしょうか?という問題です。 一番近いデータを復号すれば、最もエラー確率を小さくできるような気がしますね。
では、一番近いということをどう表現できるでしょうか?それが距離という概念です。
ハミング距離とユークリッド距離
今回の課題では、LDGMのBPという解答の他にユークリッド距離を比較する答案もあるだろうと思います。
それでは、ハミング距離について見ていきましょう。
次のプログラムでは、符号の全ワードを出力しています。
//課題の符号を全部列挙する
//Brute Forceに最小距離を調べる
module dwm1_test;
reg [3:0] data;//Encodeする元DataのWORK
reg [7:0] code_array[0:15];//全コードワードを格納する
reg [7:0] work,a,b,c,d;
wire [7:0] encoded_data;//encoder からの出力を受け取る
integer i,j,flag,m,k,n;
encoder en1(data,encoded_data);
initial begin
//符号の列挙
for (i=0;i<16;i=i+1) begin//
data=i[3:0];
#10;
code_array[i]=encoded_data;//配列に格納
$display("Code [%d]=%b",i,encoded_data);
end
//CODE Wordのビットの任意1ビットを変化させて別符号語に一致するかを見る。
flag=0;
$display("1ビットエラーをチェックしています。");
for (i=0;i<16;i=i+1) begin//
work=code_array[i];//元のDataに
for ( j=0;j<8;j=j+1) begin
a=work ^ (1 <<j);//1bit エラーを乗せて
for (m=0; m<16;m=m+1) begin//同じ符号語があるかどうかをチェック
if (a==code_array[m]) flag=1;//同じ符号語が見つかったら フラグON
end
end
end
if (!flag) $display( "1ビットエラーで、他の符号語になることはありませんでした。最小距離は、1より大きいです。\n");
//CODE Wordのビットの任意2ビットを変化させて別符号に一致するかを見る。
flag=0;
$display("2ビットエラーをチェックしています。");
for (i=0;i<16;i=i+1) begin//
work=code_array[i];//元のDataに
for ( j=0;j<8;j=j+1) begin
a=work ^ (1 <<j);//1bit エラーを乗せて
for (k=0;k<8;k=k+1) begin
b=a ^(1<< k);//もう1ビットエラーを乗せて
if (work !=b) begin//同じ符号は除いて
for (m=0; m<16;m=m+1) begin//同じ符号語があるかどうかをチェック
if (b==code_array[m]) flag=1;//同じ符号語が見つかったら フラグON
end
end
end
end
end
if (!flag) $display( "2ビットエラーで、他の符号語になることはありませんでした。最小距離は、2より大きいです。\n");
//CODE Wordのビットの任意3ビットを変化させて別符号に一致するかを見る。
flag=0;
$display("3ビットエラーをチェックしています。");
for (i=0;i<16;i=i+1) begin//
work=code_array[i];//元のDataに
for ( j=0;j<8;j=j+1) begin
a=work ^ (1 <<j);//1bit エラーを乗せて
for (k=0;k<8;k=k+1) begin
b=a ^(1<< k);//もう1ビットエラーを乗せて
for (n=0;n<8;n=n+1) begin
c=b^(1<<n);//もう1ビットエラーを乗せ
if (work !=c) begin//同じ符号語は除いて
for (m=0; m<16;m=m+1) begin
if (c==code_array[m]) begin//同じ符号語があるかどうかをチェック
//$display("%b %b",work,c);
flag=1;//同じ符号語が見つかったら フラグON
end
end
end
end
end
end
end
if (!flag) $display( "3ビットエラーで、他の符号語になることはありませんでした。最小距離は、2より大きいです。");
else $display("3ビットエラーで、他の符号語になることがあります。最小距離は、3以下です。");
end
endmodule
module encoder(input [3:0] in,
output wire [7:0] out);
reg r0,r1,c0,c1;
wire [3:0] y=in[3:0];
assign out[3:0]=in;
assign out[4]=r0;
assign out[5]=r1;
assign out[6]=c0;
assign out[7]=c1;
always @* begin
r0=y[0] ^ y[1];
r1=y[2] ^ y[3];
c0=y[0] ^ y[2];
c1=y[1] ^ y[3];
end
endmodule
この結果を見ると、次のようになります。
コードワード0と1のハミング距離は、3になります。ハミング距離とは0と1が違うところの数です。全ての符号語でみたときに、
最小となるハミング距離が最小距離になります。プログラムでは、これを素直に全ワードについて試して最小距離を求めていて、
真の最小距離は、3であることを導いています。
他の符号語に化けるには、3ビットのエラーが必要です。訂正の立場から見ると、1ビットのエラーについては、どちらに近いか
硬判定でも容易に判断でき、2ビットエラーでは、誤訂正の可能性があり、3ビットでは、他の符号語に化けてしまってエラーがあったことすら、
分からない、ということになります。以上は、最小距離で見た場合で、全ての符号間の距離が3という訳でもなさそうなので、
軟判定では、2ビット訂正も可能な場面もでてくることが期待できるかもしれないということではないかと思います。
デジタル的に見たのが、ハミング距離ですが、これをアナログ的に見たのがユークリッド距離になります。今回のようにAWGNの系においては、受信ワードについて、
全符号語とのユークリッド距離を求め最小となる符号語を選び出せば、最も確からしい復号(Maximum likelihood Decoding)となることが知られています。
今回の場合、極端に符号長が短いので、歩はこちらにあるかもしれません。
F:\regression_test\ldgm\dwm_test1.v(3)::dwm1_test
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
Code [ 0]=00000000
Code [ 1]=01010001
Code [ 2]=10010010
Code [ 3]=11000011
Code [ 4]=01100100
Code [ 5]=00110101
Code [ 6]=11110110
Code [ 7]=10100111
Code [ 8]=10101000
Code [ 9]=11111001
Code [ 10]=00111010
Code [ 11]=01101011
Code [ 12]=11001100
Code [ 13]=10011101
Code [ 14]=01011110
Code [ 15]=00001111
1ビットエラーをチェックしています。
1ビットエラーで、他の符号語になることはありませんでした。最小距離は、1より大きいです。
2ビットエラーをチェックしています。
2ビットエラーで、他の符号語になることはありませんでした。最小距離は、2より大きいです。
3ビットエラーをチェックしています。
3ビットエラーで、他の符号語になることがあります。最小距離は、3以下です。
---------- シミュレーションを終了します。time=160----------
課題の取り組み方針
コンテストの取り組み方針は、上の検討で決まりました。懲りずにまた、参戦してみたいと思います。狙いは、
- スループット 4Gbps (Iterative Decoderは使わない独自方式)
- AWGN生成器搭載->1e8ビットでのBERを実測(スタータキット3)
に決めましたAWGNについてもサーベイしてみました。
課題を解くよりも、6σまで耐えるAWGNのIPを作る方が難しいです。
ハードで発生させるとなると、Box Muller、Ziggurat、Wallaceの方法のいずれをもってしても浮動小数演算をすることになるので、
面倒です。今回は、YACCに、zigguratの方法をソフトで実装することにしました。(YACCの項をご参照ください。)
on the fly では、ありませんが、自律的にAWGNを生成できるので、一度走らせれば、後はχ自乗分布まで、プログラムで検証することが可能になります。
BPSKの生エラーレートと1ビット訂正回路
生エラーレートに対して、上の硬判定訂正回路の効果を見てみましょう。
課題通り、0dB,3dB,6dB,9dBを含んだAWGNを発生させ、生エラーレートに対する比較を行ってみます。
//Nov.2.2005
//Nov.3.2005
module raw_error_rate;
parameter integer RATE=2;
parameter integer No_Of_Data_Bits=10000;
parameter integer No_Of_Array=No_Of_Data_Bits/4;
parameter integer Total_Bits=No_Of_Data_Bits*RATE;
parameter integer SEED=1;
real expected_sigma;
real noise;
real noise_array[ 0 :Total_Bits-1];
real r_array [0 :Total_Bits-1];
reg [7:0] data_array [0 : No_Of_Array-1];
reg [7:0] decode_array [0 : No_Of_Array-1];
reg [3:0] hard_correction_array [0 : No_Of_Array-1];
initial begin
make_random_data;//10000個のランダムデータを作る 結果は=>data_array LSB側4bit
encode_data;//10000個のパイティを生成する 結果は=>data_array MSB側4bit
add_noise(0.0);//0dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(3.0);//3dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(5.0);//5dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(6.0);//6dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(7.0);//7dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(8.0);//8.0dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(9.0);//9.0dBノイズを加える
raw_decode;//デコードする
hard_correction;
add_noise(10.0);//10.0dBノイズを加える
raw_decode;//デコードする
hard_correction;
end
task make_random_data;
integer i;
integer work,counter;
begin
$display("%d個のランダムデータを生成中です。",No_Of_Data_Bits);
for (i=0;i<No_Of_Array-8; i=i+8) begin//4x8 ビットづつランダムデータを生成
work=$random;
{data_array[i+3][0 +:4],data_array[i+2][ 0 +:4],data_array[i+1][0 +:4],data_array[i+0][0 +:4]}=work[15:0];
{data_array[i+7][0 +:4],data_array[i+6][ 0 +:4],data_array[i+5][0 +:4],data_array[i+4][0 +:4]}=work[31:16];
end
work=$random;
counter=0;
for (i=No_Of_Array-8;i<No_Of_Array; i=i+1) begin//最後は、4ビットづつ
data_array[i][0 +:4]=work[counter*4 +:4];
counter=counter+1;
end
end
endtask
task encode_data;
integer i;
begin
$display("パリティを生成中です。");
if ( (Total_Bits/RATE)% No_Of_Array)begin//assert(0);
$display(" プログラムエラー");
$finish;
end
for (i=0;i<No_Of_Array; i=i+1) begin
data_array[i][4 +:4]=encoder(data_array[i][ 0 +:4]);//データを渡してパリティを受け取る
// $display("data=%h parity=%h",data_array[i][0 +:4],data_array[i][4 +:4]);
end
end
endtask
function [3:0] encoder (input [3:0] y);//パリティ生成器
reg r0,r1,c0,c1;
begin
r0=y[0] ^ y[1];
r1=y[2] ^ y[3];
c0=y[0] ^ y[2];
c1=y[1] ^ y[3];
encoder ={c1,c0,r1,r0};
end
endfunction
task make_noise( input real db);//所望のS/N[dB]を入力
real sigma2,sigma;
integer seed,i;
real noise;
real noise_sum;
begin
$display("-------------------------------------------------");
$display("ノイズパワー %f[dB] 狙いで生成中です。",db);
sigma2=$pow(10.0,-db/10.0);//$pow は、Veritak Unique
sigma=$sqrt(sigma2);//$sqrt は、Veritak Unique
seed=0;
noise_sum=0;
for (i=0;i<Total_Bits;i=i+1) begin
noise=$normal_vtak(seed,0.0,sigma);//$normal_vtakは、Veritak Unique 平均値0、σのAWGNを生成
noise_array[i]=noise;//ノイズ配列に収納する
noise_sum=noise_sum+noise*noise;
end
$display("ノイズパワー %f[dB]の生成をしました。",-10*$log10(noise_sum/Total_Bits));
end
endtask
task add_noise( input real db);//所望のS/N[dB]を入力
real sigma2,sigma;
integer counter,i,j;
real noise,RData;
begin
make_noise(db);//所望のS/N Noize をnoise_array に収納する
$display("ノイズを加算中です。");
counter=0;
for (i=0;i<No_Of_Array; i=i+1) begin
for (j=0;j<8;j=j+1) begin
if (data_array[i][j]==1'b1) RData=$itor(-1);//データ1=>−1.0にエンコード
else RData=$itor(1);//データ0=>1.0にエンコード
RData=RData+noise_array[counter];//計算しておいたAWGNノイズを加算する
r_array[counter]=RData;//r_array にノイズが重畳したreal data をSaveする。
counter=counter+1;
end
end
if ( counter !=Total_Bits) begin//assert(0);
$display(" プログラムエラー");
$finish;
end
end
endtask
task raw_decode();
integer i,j;
integer index;
integer error_count;
begin
error_count=0;
index=0;
for (i=0;i<Total_Bits;i=i+8) begin
for (j=0;j<8;j=j+1) begin
if (r_array[i+j]>0) decode_array[index][j]=0;//パリティも含めハードデコードする
else decode_array[index][j]=1;
if (j<4) begin//データ部はビットエラーをカウントする
if (decode_array[index][j] !=data_array[index][j]) error_count=error_count+1;
end
end
index=index+1;
end
$display("訂正なしシステム結果");
$display("トータルエラー数=%d エラーレート=%e",error_count, $itor(error_count)/No_Of_Data_Bits);
end
endtask
task hard_correction();
reg p0,p1,p2,p3;
reg [3:0] parities;
reg d0,d1,d2,d3;
integer index,error_count,i;
begin
error_count=0;
for (index=0;index<No_Of_Array; index=index+1) begin
{d3,d2,d1,d0}=decode_array[index][3:0];//work
p0=d0 ^ d1 ^ decode_array[index][4];//パリティを計算
p1=d2 ^ d3 ^ decode_array[index][5];//パリティを計算
p2=d0 ^ d2 ^ decode_array[index][6];//パリティを計算
p3=d1 ^ d3 ^ decode_array[index][7];//パリティを計算
parities={p3,p2,p1,p0};
hard_correction_array[index][3:0]={d3,d2,d1,d0};
if (parities==4'b0000);//No Error Nothing to Do
else if (parities==4'b0101) hard_correction_array[index][3:0]={d3,d2,d1,~d0};//1bit 訂正
else if (parities==4'b1001) hard_correction_array[index][3:0]={d3,d2,~d1,d0};//1bit 訂正
else if (parities==4'b0110) hard_correction_array[index][3:0]={d3,~d2,d1,d0};//1bit 訂正
else if (parities==4'b1010) hard_correction_array[index][3:0]={~d3,d2,d1,d0};//1bit 訂正
else ;//parity error or uncorrectable error.
//エラー数をカウント
if (data_array[index][3:0] !=hard_correction_array[index][3:0]) begin//ワード比較して
for (i=0;i<4;i=i+1) begin//違っていたらエラー数をカウント
if (data_array[index][i] !=hard_correction_array[index][i]) error_count=error_count+1;
end
end
end
$display("ハード訂正回路結果");
$display("トータルエラー数=%d エラーレート=%e",error_count, $itor(error_count)/No_Of_Data_Bits);
$display("\n");
end
endtask
endmodule
実行結果です。なお、BPSKのBER理論値は、
S/N |
BER |
5dB |
3.75e-2 |
6dB |
2.29e-2 |
7dB |
1.25e-2 |
8dB |
5.95e-3 |
9dB |
2.39e-3 |
です。
さて、訂正の効果は、どうでしょうか?グラフにしてみないと良くわかりませんが、BERは確かに下がっているので、効果はあると
言えるでしょう。問題は、これをMaximum Likelihood Decodingした場合どうなるか?、です。
F:\regression_test\ldgm\raw_error_rate.v(2)::raw_error_rate
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
10000個のランダムデータを生成中です。
パリティを生成中です。
-------------------------------------------------
ノイズパワー 0.000000[dB] 狙いで生成中です。
ノイズパワー 0.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 1607 エラーレート=1.607000e-001
ハード訂正回路結果
トータルエラー数= 1280 エラーレート=1.280000e-001
-------------------------------------------------
ノイズパワー 3.000000[dB] 狙いで生成中です。
ノイズパワー 3.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 810 エラーレート=8.100000e-002
ハード訂正回路結果
トータルエラー数= 402 エラーレート=4.020000e-002
-------------------------------------------------
ノイズパワー 5.000000[dB] 狙いで生成中です。
ノイズパワー 5.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 393 エラーレート=3.930000e-002
ハード訂正回路結果
トータルエラー数= 104 エラーレート=1.040000e-002
-------------------------------------------------
ノイズパワー 6.000000[dB] 狙いで生成中です。
ノイズパワー 6.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 238 エラーレート=2.380000e-002
ハード訂正回路結果
トータルエラー数= 41 エラーレート=4.100000e-003
-------------------------------------------------
ノイズパワー 7.000000[dB] 狙いで生成中です。
ノイズパワー 7.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 110 エラーレート=1.100000e-002
ハード訂正回路結果
トータルエラー数= 12 エラーレート=1.200000e-003
-------------------------------------------------
ノイズパワー 8.000000[dB] 狙いで生成中です。
ノイズパワー 8.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 52 エラーレート=5.200000e-003
ハード訂正回路結果
トータルエラー数= 2 エラーレート=2.000000e-004
-------------------------------------------------
ノイズパワー 9.000000[dB] 狙いで生成中です。
ノイズパワー 9.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 23 エラーレート=2.300000e-003
ハード訂正回路結果
トータルエラー数= 0 エラーレート=0.000000e+000
-------------------------------------------------
ノイズパワー 10.000000[dB] 狙いで生成中です。
ノイズパワー 10.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 8 エラーレート=8.000000e-004
ハード訂正回路結果
トータルエラー数= 0 エラーレート=0.000000e+000
---------- シミュレーションを終了します。time=0----------
MLによる復号
ユークリッド距離による復号です。上のhard_correctionタスクに対応しています。
task euclidean_decode();
integer i,j,k,m;
integer index;
integer error_count;
reg [3:0] min_code_word;
reg [7:0] data;
real distance,min_distance;
real bit_distance;
real data_r;
begin
error_count=0;
index=0;
for (i=0;i<Total_Bits;i=i+8) begin
//符号の列挙
min_distance=1e5;//Big Value
for (j=0;j<16;j=j+1) begin//全コードワードについて
data={encoder(j[3:0]),j[3:0]};//符号の列挙
//$display("Code [%d]=%b",j,data);
distance=0.0;
for (k=0;k<8;k=k+1) begin//ユークリッド距離を調べる
data_r=data[k]==1'b1 ? -1.0 : 1.0;//エンコード
bit_distance=r_array[i+k]- data_r;//ビット毎の距離
distance=distance+ bit_distance**2;//2乗して足す
end
if (distance <min_distance) begin//距離が最小か? 比較だけなのでルートは不要
min_distance=distance;//距離をSave
min_code_word=j[3:0];//コードワードを覚えておく
end
end
euclidean_correction_array[index]=min_code_word;
if (min_code_word !==data_array[index][3:0]) begin//コードワードを比較して
for (m=0;m<4;m=m+1) begin//違っていたらビットエラー数をカウント
if (data_array[index][m] !=euclidean_correction_array[index][m]) error_count=error_count+1;
end
end
index=index+1;
end
$display("MLシステム結果");
$display("トータルエラー数=%d エラーレート=%e",error_count, $itor(error_count)/No_Of_Data_Bits);
end
endtask
実行結果です。確かに上の硬判定訂正回路よりもエラーレートが向上しています。この結果は、この符号化方式の上界を与えます。
(これより良い結果はありません。) コンテストでは、いかにこの結果に、高速かつ最小ゲート数で近づけるか、がキーポイントになります。
F:\regression_test\ldgm\Euclidean_error_rate.v(3)::euclidean_error_rate
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
10000個のランダムデータを生成中です。
パリティを生成中です。
-------------------------------------------------
ノイズパワー 0.000000[dB] 狙いで生成中です。
ノイズパワー 0.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 1607 エラーレート=1.607000e-001
ハード訂正回路結果
トータルエラー数= 1280 エラーレート=1.280000e-001
MLシステム結果
トータルエラー数= 755 エラーレート=7.550000e-002
-------------------------------------------------
ノイズパワー 3.000000[dB] 狙いで生成中です。
ノイズパワー 3.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 810 エラーレート=8.100000e-002
ハード訂正回路結果
トータルエラー数= 402 エラーレート=4.020000e-002
MLシステム結果
トータルエラー数= 128 エラーレート=1.280000e-002
-------------------------------------------------
ノイズパワー 5.000000[dB] 狙いで生成中です。
ノイズパワー 5.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 393 エラーレート=3.930000e-002
ハード訂正回路結果
トータルエラー数= 104 エラーレート=1.040000e-002
MLシステム結果
トータルエラー数= 13 エラーレート=1.300000e-003
-------------------------------------------------
ノイズパワー 6.000000[dB] 狙いで生成中です。
ノイズパワー 6.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 238 エラーレート=2.380000e-002
ハード訂正回路結果
トータルエラー数= 41 エラーレート=4.100000e-003
MLシステム結果
トータルエラー数= 4 エラーレート=4.000000e-004
-------------------------------------------------
ノイズパワー 7.000000[dB] 狙いで生成中です。
ノイズパワー 7.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 110 エラーレート=1.100000e-002
ハード訂正回路結果
トータルエラー数= 12 エラーレート=1.200000e-003
MLシステム結果
トータルエラー数= 3 エラーレート=3.000000e-004
-------------------------------------------------
ノイズパワー 8.000000[dB] 狙いで生成中です。
ノイズパワー 8.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 52 エラーレート=5.200000e-003
ハード訂正回路結果
トータルエラー数= 2 エラーレート=2.000000e-004
MLシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
-------------------------------------------------
ノイズパワー 9.000000[dB] 狙いで生成中です。
ノイズパワー 9.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 23 エラーレート=2.300000e-003
ハード訂正回路結果
トータルエラー数= 0 エラーレート=0.000000e+000
MLシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
-------------------------------------------------
ノイズパワー 10.000000[dB] 狙いで生成中です。
ノイズパワー 10.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 8 エラーレート=8.000000e-004
ハード訂正回路結果
トータルエラー数= 0 エラーレート=0.000000e+000
MLシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
---------- シミュレーションを終了します。time=0----------
さて、次に課題提示の方法でも結果を比較しておきましょう。
素直に、例示の方法をコーディングします。
task iterative_decoder(input integer iteration,input integer min_sum_flag);//min_sum を用いる場合は、min_sum=1とする
integer i,j,m;
integer index;
integer iter;
integer error_count;
real y0,y1,y2,y3,r0,r1,c0,c1;
real y0col,y1col,y2col,y3col;
real y0row,y1row,y2row,y3row;
reg d0,d1,d2,d3;
begin
error_count=0;
index=0;
for (i=0;i<Total_Bits;i=i+8) begin
//iterative decoder の初期化
y0=r_array[i+0];
y1=r_array[i+1];
y2=r_array[i+2];
y3=r_array[i+3];
r0=r_array[i+4];
r1=r_array[i+5];
c0=r_array[i+6];
c1=r_array[i+7];
y0col=0.0;
y1col=0.0;
y2col=0.0;
y3col=0.0;
for (iter=0;iter< iteration;iter=iter+1) begin//interative デコーディング
//行、外部値の計算
y0row=func(y1+y1col,r0,min_sum_flag);
y1row=func(y0+y0col,r0,min_sum_flag);
y2row=func(y3+y3col,r1,min_sum_flag);
y3row=func(y2+y2col,r1,min_sum_flag);
//列、外部値の計算
y0col=func(y2+y2row,c0,min_sum_flag);
y1col=func(y3+y3row,c1,min_sum_flag);
y2col=func(y0+y0row,c0,min_sum_flag);
y3col=func(y1+y1row,c1,min_sum_flag);
end
//繰り返しが終わったらデコード=チャネル値+事前値+事後値
d0=y0+y0row+y0col > 0 ? 0 :1;
d1=y1+y1row+y1col > 0 ? 0: 1;
d2=y2+y2row+y2col > 0 ? 0: 1;
d3=y3+y3row+y3col > 0 ? 0: 1;
iterative_correction_array[index]={d3,d2,d1,d0};
if (iterative_correction_array[index] !==data_array[index][3:0]) begin//コードワードを比較して
for (m=0;m<4;m=m+1) begin//違っていたらビットエラー数をカウント
if (data_array[index][m] !=iterative_correction_array[index][m]) error_count=error_count+1;
end
end
index=index+1;
end
if (min_sum_flag) $display("Min-Sum Iterative Decoding Logシステム結果 ");
else $display("Log-Sum Iterative Decoding Logシステム結果 ");
$display("トータルエラー数=%d エラーレート=%e",error_count, $itor(error_count)/No_Of_Data_Bits);
end
endtask
function real func (input real a, input real b,input integer min_sum_flag);//min_sum を用いる場合は min_sum_flag =1に設定する
real den,num;
real sign;
real min;
begin
if (min_sum_flag) begin
sign=a*b > 0 ? 1.0 : -1.0;
min=$fabs(a) > $fabs(b) ? $fabs(b) : $fabs(a);
func=sign* min;
end else begin
num=1.0 +$exp(a+b);
den=$exp(a)+$exp(b);
func=$log(num/den);
end
end
endfunction
結果です。iteration は、5回にしました。意外にも、殆どOptimumな結果になりました。実際のところ、2回でも、殆ど違いは、ないように思います。
どうして、このiterative algorithmが収束するかというのは、感覚的に言っても不思議ですね。
それにしても、これ以上簡単化しようのないLDPC復号例になっており、面白い課題になっています。。
グラフ化してみました。Min-Sum とユークリッドは、ピッタリ重なってしまっています。1e-3で見ると、
生エラーレートに対して、5dB位のゲインがあります。符号化による帯域ノイズの上昇は、2倍の3dBなので、符号化に
よって見かけ上2dBの符号化利得が得られることになります。(2dB送信電力を落としても同じBERが得られる)
F:\regression_test\ldgm\iterative_decoding.v(3)::iterative_decoding
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
10000個のランダムデータを生成中です。
パリティを生成中です。
-------------------------------------------------
ノイズパワー 0.000000[dB] 狙いで生成中です。
ノイズパワー 0.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 1607 エラーレート=1.607000e-001
ハード訂正回路結果
トータルエラー数= 1280 エラーレート=1.280000e-001
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 765 エラーレート=7.650000e-002
MLシステム結果
トータルエラー数= 755 エラーレート=7.550000e-002
-------------------------------------------------
ノイズパワー 1.000000[dB] 狙いで生成中です。
ノイズパワー 1.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 1345 エラーレート=1.345000e-001
ハード訂正回路結果
トータルエラー数= 969 エラーレート=9.690000e-002
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 494 エラーレート=4.940000e-002
MLシステム結果
トータルエラー数= 489 エラーレート=4.890000e-002
-------------------------------------------------
ノイズパワー 2.000000[dB] 狙いで生成中です。
ノイズパワー 2.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 1061 エラーレート=1.061000e-001
ハード訂正回路結果
トータルエラー数= 645 エラーレート=6.450000e-002
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 283 エラーレート=2.830000e-002
MLシステム結果
トータルエラー数= 282 エラーレート=2.820000e-002
-------------------------------------------------
ノイズパワー 3.000000[dB] 狙いで生成中です。
ノイズパワー 3.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 810 エラーレート=8.100000e-002
ハード訂正回路結果
トータルエラー数= 402 エラーレート=4.020000e-002
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 131 エラーレート=1.310000e-002
MLシステム結果
トータルエラー数= 128 エラーレート=1.280000e-002
-------------------------------------------------
ノイズパワー 4.000000[dB] 狙いで生成中です。
ノイズパワー 4.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 577 エラーレート=5.770000e-002
ハード訂正回路結果
トータルエラー数= 214 エラーレート=2.140000e-002
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 40 エラーレート=4.000000e-003
MLシステム結果
トータルエラー数= 40 エラーレート=4.000000e-003
-------------------------------------------------
ノイズパワー 5.000000[dB] 狙いで生成中です。
ノイズパワー 5.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 393 エラーレート=3.930000e-002
ハード訂正回路結果
トータルエラー数= 104 エラーレート=1.040000e-002
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 13 エラーレート=1.300000e-003
MLシステム結果
トータルエラー数= 13 エラーレート=1.300000e-003
-------------------------------------------------
ノイズパワー 6.000000[dB] 狙いで生成中です。
ノイズパワー 6.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 238 エラーレート=2.380000e-002
ハード訂正回路結果
トータルエラー数= 41 エラーレート=4.100000e-003
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 4 エラーレート=4.000000e-004
MLシステム結果
トータルエラー数= 4 エラーレート=4.000000e-004
-------------------------------------------------
ノイズパワー 7.000000[dB] 狙いで生成中です。
ノイズパワー 7.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 110 エラーレート=1.100000e-002
ハード訂正回路結果
トータルエラー数= 12 エラーレート=1.200000e-003
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 3 エラーレート=3.000000e-004
MLシステム結果
トータルエラー数= 3 エラーレート=3.000000e-004
-------------------------------------------------
ノイズパワー 8.000000[dB] 狙いで生成中です。
ノイズパワー 8.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 52 エラーレート=5.200000e-003
ハード訂正回路結果
トータルエラー数= 2 エラーレート=2.000000e-004
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
MLシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
-------------------------------------------------
ノイズパワー 9.000000[dB] 狙いで生成中です。
ノイズパワー 9.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 23 エラーレート=2.300000e-003
ハード訂正回路結果
トータルエラー数= 0 エラーレート=0.000000e+000
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
MLシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
-------------------------------------------------
ノイズパワー 10.000000[dB] 狙いで生成中です。
ノイズパワー 10.024707[dB]の生成をしました。
ノイズを加算中です。
訂正なしシステム結果
トータルエラー数= 8 エラーレート=8.000000e-004
ハード訂正回路結果
トータルエラー数= 0 エラーレート=0.000000e+000
Min-Sum Iterative Decoding Logシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
MLシステム結果
トータルエラー数= 0 エラーレート=0.000000e+000
---------- シミュレーションを終了します。time=0----------
さて、以上で理想化したシステムでのモデルの構築ができました。
今までは、論理合成を意識しませんでした。当面の問題は、ビット数を幾つにするかという問題です。
それには、上のモデルを量子化ビット幅をパラメータにして、シミュレーションしてみればいいですね。
量子化誤差が入り込んでくるので、上のシミュレーションから劣化は避けられません。理想値を知った上での
ゲート数/速度とのトレードオフになります。Version 1.83のregresiion_test\ldgmフォルダに上のコードは入っていますので、そこから、
個々のアイデアを展開してみるのもよいかもしれません。
ビット幅の検討
アーキテクチャが決まったので、RTLを書いて、ビット幅の検討を行いました。
この段階では、速度と、合成回路規模、性能のトレードオフになるので、ビット幅をパラメータにして、合成も行っています。
下の記述は、ハードウェアトップのポート記述ですが、ビット幅BWをパラメータにしています。XILINXでは、このパラメータも
ちゃんと認識してくれて、BWの値を換えるだけで、全体のビット幅が変わってくれます。ビット幅のコストは、合成してみないと
予想がつかないことも多く、この手法はお勧めです。
module hardware # (parameter BW=8)
( input [BW*8-1:0] indata,
output reg [3:0] outdata,
input clock, Reset );
localparam integer FIFO_DEPTH=6;
reg [BW*8-1:0] indataR,indataR_D;
また、このHW記述では、verilog-2001のgenerate を使ってパイプラインレジスタを書いてみました。
FIFO_DEPTHをパラメータとして、HW変更に対して柔軟にしています。(Verilog
2001 generateについては、こちらをご参照ください。)
generate
genvar g;
for (g=0;g <FIFO_DEPTH; g=g+1) begin :fifo
reg [3:0] BinDD;
reg [3:0] word0_D;
reg [3:0] word1_D;
reg [3:0] word2_D;
if (g==0) begin :if_label //why xilinx needs label here?
always @(posedge clock) begin
BinDD<=BinD;//2nd
word0_D<=word0[3:0];//2nd
word1_D<=word1[3:0];
word2_D<=word2[3:0];
end
end else begin :else_label//why xilinx needs label here?
always @(posedge clock) begin
BinDD<=fifo[g-1].BinDD;//
word0_D<=fifo[g-1].word0_D;//
word1_D<=fifo[g-1].word1_D;
word2_D<=fifo[g-1].word2_D;
end
end //if
end //for
endgenerate
ところで、性能ですが、提案しているアーキテクチャでは、MLの理想値にたいして、劣化は避けられません。ここでは、0.5dB位にとどめたいと思っています。
下のシステムシミュレーションのグラフから、3ビット以上が必要であることがわかります。なお、同じベンチで、合成に使ったRTLでもシミュレーション
を行い、同一の結果であることを確認しました。このシミュレーションでは、各1e6ビット流しています。エラーレートが低いところで、バタついているのは、数個のエラーしかでない為です。
合成後の規模・速度共、大体想定内でしたので、これで、コア部の設計終了です。
余談ですが、XILINXスパルタン3とStratix2とでは、ロジックの深さが違います。スパルタン3は、とても浅いので、深いロジックを
書く事ができません。溢れたロジックは、即速度低下という形で現れます。最初3段位で書いていましたが、70MHz位
しか出なくて、目を疑いました。結果、最終的に8段になってしまいました。試してはいませんが、ST2なら自身の最高速度を保ったまま、3-4段で収まるような気がします。
=>さすがに最速デバイス(ST2)を使うと速い結果になりました。
合成ソフト/デバイス |
合成対象 |
LUT数 |
遅延(ns) |
周波数(MHz) |
LUT数比 |
速度比 |
転送レート(Gbps) |
Quartus5.1/ |
リファレンス回路 |
14 |
10.57 |
94.60 |
1 |
1 |
|
EP2S15F484C3 |
hardware.v |
309 |
2.11 |
473.26 |
22.07 |
5.003 |
3.79 |
ISE7.1/ |
リファレンス回路 |
17 |
12.73 |
78.57 |
1 |
1 |
|
XC3S200-4 |
hardware.v |
291 |
5.37 |
186.22 |
17.12 |
2.370 |
1.49 |
遅延シミュレーション
設計したコアの遅延シミュレーションを行ってみました。RTL上は、9クロック遅延なのですが、出力の遅延(約7ns)のため、10クロック遅延になってしまっています。
また、下で、1ビットないし、2ビットのエラーパターンが発生していますが、訂正が行われてノイズ加算前のデータが再現していることが分かります。
YACCとの結合
YACCのメモリ上にコアをマップし、実働回路を作成します。
3Eは、待っていられないので、スパルタン3のスタータキット上で作成しました。結果、Cプログラムのダイエットを余儀なくされました。
Area優先で、遅延約25nsが得られています。
後は、下のような、Cプログラムをひたすら走らせ、UARTで、エラーレートの報告を(寝て)待てば、よいだけです。
double target_sds[]={ 1.0, //0db PASS0
0.891,//1db 1
0.794,//2db 2
0.708,//3db 3
0.631,//4db 4
0.562,//5dB 5
0.501,//6dB 6
0.447,//7 7
0.422,//7.5 8
0.398,//8.0 9
0.376,//8.5 10
0.355,//9 11
0.335,//9.5 12
0.315// 10.0 13
};
void main()
{
double sum,avg,a,target_sd;
double noise;
int i,j,index,I;
unsigned data_in,data_out;
int n=No;
#ifdef RTL_SIM
print_uart("V1.1\n");
#endif
total_bits=0;
sum=0;
// for (i=0;i< (STATISTICS_LEVELS*2);i++) counter_array[i]=0;
for(j=0;j< 14 ;j++) {
target_sd=target_sds[j];
bit_counter=0;
bit_error_counter=0;
raw_bit_error_counter=0;
do{
data_in=make_input_data(target_sd);
#ifndef DOS
data_write_and_compare(data_in);
#endif
bit_counter +=4;
total_bits +=4;
if (bit_error_counter> ERROR_THRESHOLD){
print_uart("Pass=");
print_num(j);
print_num(bit_counter);
print_num(raw_bit_error_counter);
print_num(bit_error_counter);
print_uart("EndPass\n");
break;
}
}while(1);
}
#ifdef DOS
#ifdef SD_DISPLAY
avg=sum/No;
sum=0;
for (i=0;i<No;i=i+1){
a=array[i]-avg;
sum=sum+a*a;
}
sd=sqrt(sum/No);
printf("Done %d samples. avg=%f target_sd=%f sd=%f",n,avg,target_sd,sd);
#endif
printf("Done %d samples. target_sd=%f\n",n,target_sd);
for (i=0;i< (STATISTICS_LEVELS*2);i++){
printf("%d,%d\n",i-STATISTICS_LEVELS,counter_array[i]);
}
#else
print_uart("Done All\n");
#endif
}
<所感>
AWGNの生成に時間がかかっているので、もくろみのビット数は、難しい結果となりましたが、それでも、H/Wを
作成する手間を考えると、現実的な妥協点ではないかと思います。手軽にCプログラムが走るCPUがあると、
周辺H/Wの検証が楽になることを、実感しました。
一方、CプログラムのデバッグをVeritak上で行いましたが、AWGNの生成は、時間がかかるので結構な時間がかかりました。
ソフトウェアシミュレータでは、高速に走らせることができますが、周辺H/Wは、独自なので、やはりRTLでの高速化が望ましいと思いました。
また、システムの検討では、RTLはそのままで、それ以外をVPIを使ったC呼び出しで作成してもよかったかもしれません。
少し、時間があるので、この点での検討をしてみたいと思います。
なお、今回は、中国のエンジニア陸偉良氏との共作です。
=>
<VPIを使った高速RTLシミュレーション>
H/Wの記述以外の周辺をCで記述して、RTLシミュレーションを高速化しました。
これだと、総ビット数1e9のテストでも、それほど時間は、かかりません。上のスパルタン3でのテストよりも、
かなり速いです。実機CPUの方が情けなくなってきます。(なにせ、ソフトフロート25MHz駆動ですので。)
H/W部は、合成に使用したソースですし、AWGNのプログラムも同じなので、実機と同じ結果になるはずです。
以下テストベンチです。
//RTL VPIを用いた高速版
`timescale 1ns/1ps
`define CYCLE 10
module euclidean_error_rate;
parameter integer ERROR_LIMIT=1000;//エラー数 これを超えたら次のDB STEPに行く
parameter integer BW=3;//ビット幅
parameter integer FIFO_DEPTH=9;//ハードウェアの遅延待ち
reg clock=0;
reg [31:0] VPI_Data;//VPIで返される値
wire [23:0] indata=VPI_Data[23:0];//ハードウェア入力3ビットx8ビット
wire [3:0] correct_data=VPI_Data[27:24];//期待値
wire [3:0] outdata;//ハードウェア出力
reg Reset=1;
reg [63:0] bit_counter=0;
integer bit_error_counter=0;
real DB;
real sigma;
initial begin
#100;
Reset=0;
DB=0.0;
set_sigma;
end
generate
genvar gen;
for (gen=0;gen<FIFO_DEPTH;gen=gen+1) begin :loop
reg [4:0] D;
if (gen==0) begin
always @(posedge clock) begin
D<={Reset,correct_data};
end
end else if(gen==FIFO_DEPTH-1) begin//ハードウェアの遅延クロック分、期待値も遅延させる
always @(posedge clock) begin
D<=loop[gen-1].D;
@(negedge clock);
if (D[4]==0 ) begin//RESET がLOWのときだけカウントする
bit_counter=bit_counter+4;
count_bit_error(D[3:0],outdata);//エラー数のカウント D[3:0]は、期待値
end
end
end else begin
always @(posedge clock) begin
D<=loop[gen-1].D;
end
end
end
endgenerate
task count_bit_error( input [3:0] in1,in2) ;
integer i;
real rate;
begin
if ( in1 !==in2) begin
for (i=0;i<4;i=i+1) begin
if (in1[i] !==in2[i]) bit_error_counter=bit_error_counter+1;
end
end
if (bit_error_counter >ERROR_LIMIT) begin//エラー数のLIMITを上回ったら次のDB STEP
rate=bit_error_counter;
rate=rate/bit_counter;
$display("DB=%f bits=%d error=%d error_rate=%e sigma=%f",DB,bit_counter,bit_error_counter,rate,sigma);
DB=DB+0.5;
bit_counter=0;
bit_error_counter=0;
set_sigma;
end
end
endtask
task set_sigma;
real sigma2;
begin
sigma2=$pow(10.0,-DB/10.0);//
sigma=$sqrt(sigma2);//$sqrt
end
endtask
always @(negedge clock) begin
#1;
if (Reset) ;
else begin
VPI_Data=$my_random_for_dwm(sigma);//DWM 用 VPI
end
end
always #(`CYCLE) clock=~clock;
hardware # ( .BW(BW)) hw ( .indata(indata), .outdata(outdata), .clock(clock), .Reset(Reset) );
endmodule
VPIソースです。
static int sys_my_random_for_dwm_size_tf()//Aug.42003
{
return 32;
}
/* position of right-most step */
#define PARAM_R 2.96454468156
/* level values */
static const double ytab[32] = {
1,
0.907475617638,
0.8387295158,
0.780775785072,
0.729446868113,
0.682776316768,
0.639647716015,
0.599353201849,
0.561409662765,
0.525469625896,
0.491273228111,
0.458620229136,
0.427352696597,
0.397343775955,
0.368490127285,
0.340706676394,
0.313922886649,
0.288080067698,
0.263129417761,
0.23903060658,
0.215750777731,
0.193263899438,
0.171550433862,
0.150597335281,
0.130398439093,
0.110955385052,
0.0922793705114,
0.0743943543072,
0.0573431209268,
0.0411998625242,
0.0261009770388,
0.0123479825627,
};
/* quick acceptance check */
static const unsigned long ktab[32] = {
0,
12465559,
14143380,
14859376,
15254596,
15503949,
15674743,
15798352,
15891342,
15963265,
16020003,
16065358,
16101882,
16131333,
16154939,
16173564,
16187797,
16198017,
16204425,
16207053,
16205755,
16200181,
16189707,
16173323,
16149413,
16115345,
16066638,
15995077,
15883832,
15691829,
15281721,
15063248
};
/* quick value conversion */
static const double wtab[32] = {
2.6265107239e-08,
3.5349827263e-08,
4.19328107856e-08,
4.73449074891e-08,
5.20705831605e-08,
5.63468970139e-08,
6.03100167664e-08,
6.40468149156e-08,
6.76171489147e-08,
7.10648776583e-08,
7.44238783956e-08,
7.77216053723e-08,
8.09813473119e-08,
8.42237615336e-08,
8.74679979284e-08,
9.0732597892e-08,
9.4036290297e-08,
9.73987784303e-08,
1.00841606117e-07,
1.04389204949e-07,
1.08070261837e-07,
1.11919620405e-07,
1.15981071511e-07,
1.20311664676e-07,
1.24988739931e-07,
1.30122131768e-07,
1.35877026736e-07,
1.42521234138e-07,
1.50537318078e-07,
1.60949814958e-07,
1.76700632665e-07,
1.96806467179e-07
};
unsigned long s1=0xffffffff,s2=0xffffffff,s3=0xffffffff;
unsigned long taus88_int ()
{/*Generates numbers between 0 and 1.*/
unsigned b;
b =(((s1 <<13)^s1)>>19);
s1 =(((s1 &4294967294)<<12)^b);
b =(((s2 <<2)^s2)>>25);
s2 =(((s2 &4294967288)<<4)^b);
b =(((s3 <<3)^s3)>>11);
s3 =(((s3 &4294967280)<<17)^b);
return ((s1 ^s2 ^s3));
}
double taus88 ()
{
return (taus88_int()*2.3283064365e-10);
}
double
gsl_ran_gaussian_ziggurat ()
{
unsigned long U, sign, i, j;
double x, y;
while (1) {
U = taus88_int();
i = U & 0x0000001F; /* 7 bit to choose the step */
sign = U & 0x00000020; /* 1 bit for the sign */
j = U>>6; /* 24 bit for the x-value */
x = j*wtab[i];
if (j < ktab[i]) break;
if (i<32) {
double y0, y1;
y0 = ytab[i];
y1 = ytab[i+1];
y = y1+(y0-y1)*taus88();
} else {
x = PARAM_R - log(1.0-taus88())/PARAM_R;
y = exp(-PARAM_R*(x-0.5*PARAM_R))*taus88();
}
if (y < exp(-0.5*x*x)) break;
}
return sign ? x : -x;
}
unsigned quantize(double rvalue)
{
double R;
int qdata;
R=rvalue*1;
if (R>=1.5) qdata=3;
else if (R>=1.0) qdata=2;
else if (R>=0.5) qdata=1;
else if (R>=0) qdata=0;
else if (R>=-0.5) qdata=-1;
else if (R>=-1.0) qdata=-2;
else if (R>=-1.5) qdata=-3;
else qdata=-4;
qdata &=0x7;//3bit 切り出し
return qdata;
}
unsigned get_random_data()
{
unsigned y;
unsigned r0,r1,c0,c1;
unsigned y0,y1,y2,y3;
unsigned outdata;
y=taus88_int();//ランダムデータを得る。下位4ビットしか使っていない
//ビット切り出し
y0=y & 0x01;
y1=(y >> 1) & 0x01;
y2=(y >> 2) & 0x01;
y3=(y >> 3) & 0x01;
//パリティ計算
r0=y0 ^ y1;
r1=y2 ^ y3;
c0=y0 ^ y2;
c1=y1 ^ y3;
outdata=y0;
outdata |=y1 <<1;
outdata |=y2 <<2;
outdata |=y3 <<3;
outdata |=r0 <<4;
outdata |=r1 <<5;
outdata |=c0 <<6;
outdata |=c1 <<7;
outdata <<=24;// 上位8ビットが訂正前ノイズ加算前エンコードデータ
return outdata;
}
unsigned make_input_data(double target_sd)
{
double rvalue;
unsigned temp;
unsigned i,j;
double noise;
unsigned outdata;
unsigned word;
outdata=get_random_data();//エンコーダ上位8ビットにエンコードデータ
//3ビットアナログ受信値の作成
for (i=0;i<8 ;i++) {
noise=gsl_ran_gaussian_ziggurat();//1.0 ガウスノイズ生成
#ifdef STATISTICS
statistics(noise);//ガウスノイズの度数分布処理
#endif
noise *=target_sd;//ノイズシグマ乗算
if ( (outdata >> (24+i)) & 0x01) {
rvalue=-1.0;//1-> -1に
}else rvalue=+1.0;//0-> +1にエンコード
rvalue +=noise;
temp=quantize(rvalue);//3ビットに量子化
temp <<=3*i;
outdata |=temp;
}
return outdata;
}
static int sys_my_random_for_dwm(char* name)
{
vpiHandle systfref,argsiter,argh;
t_vpi_value value;
double r;
systfref = vpi_handle(vpiSysTfCall, NULL); /* get system function that invoked C routine */
argsiter = vpi_iterate(vpiArgument, systfref);/* get iterator (list) of passed arguments */
argh = vpi_scan(argsiter);/* get the one argument - add loop for more args */
if(!argh){
vpi_printf("$VPI missing parameter.\n");
return 0;
}
value.format = vpiRealVal;
vpi_get_value(argh, &value);
r = value.value.real;
value.value.integer =make_input_data(r) ;
value.format = vpiIntVal;/* return the result */
vpi_put_value(systfref, &value, NULL, vpiNoDelay);
vpi_free_object(argsiter);
return(0);
}
extern "C" void sys_math_vpi_register()//VPI DLLロード時CALLされ、$Functionが登録される。
{
s_vpi_systf_data tf_data;
//Dec.30.2005 FOR DWM
tf_data.type = vpiSysFunc;//Define as function
tf_data.subtype =vpiIntFunc;//return by integer
tf_data.tfname = "$my_random_for_dwm";
tf_data.user_data = "$my_random_for_dwm";
tf_data.calltf = sys_my_random_for_dwm;
tf_data.compiletf = 0;
tf_data.sizetf = sys_my_random_for_dwm_size_tf;//func なので返す
vpi_register_systf(&tf_data);
}
RTLシミュレータで、Cのデバッグをするなんて、筆者くらいでしょうか。
最終的な結果です。9/9.5dBの実測で、RTLシミュレーション値と一致していないのは、この2点だけ、エラー数を10で止めているためと思われます。
他のデータは、すべて1000個以上のエラー数ですが、RTLシミュレーション値とよく一致しています。どうして10で止めているかというと、時間がなかったからです。
1.3e8ビットをテストするのに、1週間以上回しました。次のデータ9.0dbでは、おそらく3週間はかかってしまうでしょう。
生成したAWGNが本当にガウス分布しているのかも調べました。カイ自乗検定で合格です。
提出したレポートです。
システムの検討からバックアノテーション後の遅延シミュレーションまで、単一の言語Verilog HDL上で検討を行いました。
足りない部分や、速度的にネックの部分は、C/C++で記述して、Verilog HDLで呼び出してしまえばよいのです。
、
テストベンチがシステムの検討から遅延シミュレーションまで、変わらなかったことにお気づきでしょうか?その事がHDLを使う
もっとも大きな点だと筆者は思います。確かにH/Wは、抽象から具体へ、すなわち、モデル->RTL->ゲートー>遅延つきゲートに変化しましたが、テストベンチは、システムで
使ったものをそのまま使用しています。しかも、この記述は、SystemVerilogになっても変更の必要はありません。
20年も前に設計された言語が、その基本機能はそのままに、すくなくとも、今後10年間、生き続けるのは、すごいことだと思います。
LDPCのVerilog HDL記述
コンテスト課題は、LDGMの特殊例です。少し横道に逸れますが、LDPCのVerilogコーディング例は、Opencoresも含めてまとまったものは、
公開されていないようなので、ここで記述してみようかと思います。
幸い、MATLABやCでの例は、結構ありますので、それをポートしていきたいと思います。
T.B.C.
Verilog で画像処理?(Version 1.74A/3.24A)
Note:以下は、Veritak拡張オプションをEnableにして8ビット単位で書いています。これをEnableしないと、Verilog-2001の規格では、%uは、32ビット単位で行うという規定があり、C言語のイメージをそのまま移植した以下のソースは正しく動作しません。
3.24Aから、代わりに$fwriteの%cを使えますが、バイナリ0を書いても空白(20)にしてしまうシミュレータもありシミュレータ間で実装の差異があるようです。また、Veritakでは、1バイトライト用にfputcも使用できますが、これは、Standard(LRM)ではありません。
Verilog 2001でサポートされた、多次元配列とバイナリファイルを扱うシステムタスクの例です。
この例では、24ビットのBMPファイル(3port.bmp)をバイナリで読み込んで、
濃淡白黒画像(after_abc2.bmp)と、2値化画像(after_abc3.bmp)にしています。
速度を求める場合は、CでVPIを書いた方がよいのは、言うまでもありません。
バイナリのライトを行うには、$fwrite(”%u”、xx)、引数は%uは、強制バイナリ2進のフォーマット指示になります。通常、
Verilog HDLでは、4値なのでメモリ上では物理2ビットにアサインされていますが、ここでは、強制的に1ビットに対応します。
また、注意点として、バイナリでR/Wする場合は、
$fopenは、テキストモードではなく、バイナリモードで開かなくてはいけません。(筆者も最初テキストモードで開いて
しまって、変な結果に悩んでしまいました。) また、バイナリリードを行うには、$freadを使います。
無変換(after_abc1.bmp)
濃淡白黒画像(after_abc2.bmp)
2値化画像(after_abc3.bmp)
//参考にしたCソースは、
//http://www.fit.ac.jp/elec/7_online/lu/sample/bmp_image_proc.cpp
//です。
`define Y_SIZE 2048 // 処理できる最大画像
`define X_SIZE 2048
`define HIGH 255 // 画像の最大強度値
`define LOW 0 // 画像の最小強度値
`define LEVEL 256 // 画像の強度レベル値
module bmp_test;
parameter read_filename="3port.bmp";
parameter write_filename1="after_abc1.bmp";
parameter write_filename2="after_abc2.bmp";
parameter write_filename3="after_abc3.bmp";
parameter [7:0] INTENSITY=100;//0-255
integer biCompression,
biSizeImage,
biXPelsPerMeter,
biYPelsPerMeter,
biClrUsed,
biClrImportant;
reg [15:0] bfType;
integer bfSize;
reg [15:0] bfReserved1, bfReserved2;
integer bfOffBits;
integer biSize, biWidth, biHeight;
reg [15:0] biPlanes, biBitCount;
reg [7:0] image_in [0:`Y_SIZE][0:`X_SIZE][0:2]; // 入力カラー画像配列
reg [7:0] image_out [0:`Y_SIZE][0:`X_SIZE][0:2]; //出力カラー画像配列
reg [7:0] image_bw [0:`Y_SIZE][0:`X_SIZE]; //濃淡画像配列
//********************************************
// 24Bitビットマップファイル読み込み *
//********************************************
task readBMP(input [128*8:1] read_filename);
integer fp;
integer i, j, k;
reg [7:0] byte;
begin
// ファイルオープン
fp = $fopen(read_filename, "rb") ;//must be binary read mode
if (!fp) begin
$display("readBmp: Open error!\n");
$finish;
end
$display("input file : %s\n", read_filename);
// ヘッダー情報読み込む
$fread(bfType, fp);
$fread(bfSize, fp);
$fread(bfReserved1, fp);
$fread(bfReserved2, fp);
$fread(bfOffBits, fp);
$fread(biSize, fp);
$fread(biWidth, fp);
if (biWidth%4) begin
$display("Sorry, biWidth%4 must be zero in this program. Found =%d",biWidth);
$finish;
end
$fread(biHeight, fp);
$fread(biPlanes, fp);
$fread(biBitCount, fp);
if (biBitCount !=24) begin
$display("Sorry, biBitCount must be 24 in this program. Found=%d",biBitCount);
$finish;
end
$fread(biCompression, fp);
$fread(biSizeImage, fp);
$fread(biXPelsPerMeter, fp);
$fread(biYPelsPerMeter, fp);
$fread(biClrUsed, fp);
$fread(biClrImportant, fp);
// RGB画像データ読み込む
for (i=0; i< biHeight; i=i+1) begin
for (j=0; j< biWidth; j=j+1) begin
for (k=0; k<3; k=k+1) begin
$fread(byte,fp);
image_in[biHeight-i][j][2-k]=byte;
end
end
end
$display("Current POS=%d",$ftell(fp));
$fclose(fp);
end
endtask
//******************************************************
// 24ビット-ビットマップデータをBMPファイルに出力 *
//******************************************************
task writeBMP(input [128*8:1] write_filename,input O);
integer fp;
integer i, j, k;
begin
// ファイルオープン
fp = $fopen(write_filename, "wb");//must be binary read mode
if (!fp) begin
$display("writeBmp: Open error!\n");
$finish;
end
$display("output file : %s\n", write_filename);
// ヘッダー情報
$fwrite(fp,"%u",bfType);
$fwrite(fp,"%u",bfSize);
$fwrite(fp,"%u",bfReserved1);
$fwrite(fp,"%u",bfReserved2);
$fwrite(fp,"%u",bfOffBits);
$fwrite(fp,"%u",biSize);
$fwrite(fp,"%u",biWidth);
$fwrite(fp,"%u",biHeight);
$fwrite(fp,"%u",biPlanes);
$fwrite(fp,"%u",biBitCount);
$fwrite(fp,"%u",biCompression);
$fwrite(fp,"%u",biSizeImage);
$fwrite(fp,"%u",biXPelsPerMeter);
$fwrite(fp,"%u",biYPelsPerMeter);
$fwrite(fp,"%u",biClrUsed);
$fwrite(fp,"%u",biClrImportant);
// ビットマップデータ
for (i=0; i< biHeight; i=i+1) begin
for (j=0; j< biWidth; j=j+1) begin
for (k=0; k<3; k=k+1) begin
if (O) $fwrite(fp,"%u",image_out[biHeight-i][j][2-k]);
else $fwrite(fp,"%u",image_in[biHeight-i][j][2-k]);
end
end
end
$display("Current WPOS=%d",$ftell(fp));
$fclose(fp);
end
endtask
//**********************************************
// RGBカラー画像を256諧調白黒濃淡画像へ変換 *
//**********************************************
task BMPto256BW;
integer y, x, a;
begin
for (y=0; y<biHeight; y=y+1) begin
for (x=0; x<biWidth; x=x+1) begin
a =$rtoi(0.3*image_in[y][x][0] + 0.59*image_in[y][x][1] + 0.11*image_in[y][x][2]);
if (a<`LOW) a = `LOW;
if (a>`HIGH) a = `HIGH;
image_bw[y][x] = a;
end
end
end
endtask
//****************************************
// 白黒画像を24bitビットマップ形式に変換 *
//****************************************
task BWto24BMP;
integer y, x, a;
begin
for (y=0; y<biHeight; y=y+1) begin
for (x=0; x<biWidth; x=x+1) begin
a = image_bw[y][x];
image_out[y][x][0] = a;
image_out[y][x][1] = a;
image_out[y][x][2] = a;
end
end
end
endtask
//****************************************
// 白黒画像の2値化 *
//****************************************
task toBinary( input [7:0] intensity);
integer y, x;
begin
for (y=0; y<biHeight; y=y+1)begin
for (x=0; x<biWidth; x=x+1) begin
if(image_bw[y][x] >= intensity) image_bw[y][x]=`HIGH;
else image_bw[y][x] = `LOW;
end
end
end
endtask
initial begin
//画像処理1:
readBMP(read_filename); // 画像の入力,RGB24ビットカラーBMP画像を配列に格納
writeBMP(write_filename1,0);//無変換で書き込み
//画像処理2:白黒変換
BMPto256BW; // RGBカラー画像を白黒画像に変換
BWto24BMP; // 単チャンネル白黒画像を3チャンネルBMP標準フォーマットへ変換
writeBMP(write_filename2,1); // 白黒画像出力
//画像処理3: 2値化
toBinary(INTENSITY);
BWto24BMP;
writeBMP(write_filename3,1); // 白黒画像出力
end
endmodule
|
veritak Project File のダウンロード
Verilog でテキストファイル処理?(Version 1.74A)
上の例は、バイナリファイルを扱う例でしたが、テキストファイル処理を行うこともできます。
テストベンチで結果の妥当性をチェックする用途として機会は多いのではないでしょうか?
テキストファイル処理には、$fseek,$fscanf,$fdisplay,$fell等を使います。殆どCそのままですね。
下は、256MBのテキストファイルを作成して、$fseekで$randomに飛び、書き込んであるDataの妥当性をチェックしています。
なお、$randomは、符号付で返すので、$unsignedもしくは、{}で、符号なしにします。
//Sep.21.2005
//$fseek/$fscanf/$fdisplay Test
module large_file;
parameter integer WORDS=1024*1024*8;//1024*1024*34 BYTES;
parameter integer STR_LEN=32+2;//CR+LF
integer i;
integer fp;
integer offset;
reg [255:0] R2;
initial begin
//Open
fp=$fopen("large_file.txt","w+");//Open By Write & Read Mode
if (!fp) begin
$display("File Can not be opend.!");
$finish;
end
//Write
$display("Writing Large File..");
for (i=0; i<WORDS;i=i+1) begin
R2={i+7,i+6,i+5,i+4,i+3,i+2,i+1,i};
if (i%10000==1) $display("%d",i);
$fdisplay(fp,"%32x",R2[127:0]);
end
$display("Large Text File genrated Words=%d Total %fMBytes",WORDS,(WORDS*STR_LEN)/1e6);
//Trival Check
trival_check(fp);
//Random Check
random_check(fp);
end
task disp_current_position(input integer fp);
integer position;
begin
position=$ftell(fp);
$display("Current Posion=%d",position);
end
endtask
task trival_check(input integer fp);
parameter OFFSET=10;
begin
$display("Trival Check Starts...");
offset=$ftell(fp);
disp_current_position(fp);
offset=offset-OFFSET*STR_LEN;
$fseek(fp, offset,0);
disp_current_position(fp);
for (i=0;i<OFFSET;i=i+1) begin
$fscanf(fp,"%h\n",R2);
$display("%h",R2);
end
$display("Trival Check Done.\n");
end
endtask
task random_check(input integer fp);
integer EOF;
parameter integer No_of_Checks=1000_000;
integer i,position,aligned_pos,word_pos;
reg [127:0] word;
begin
$display("Random Check.Starts.. It takes several minutes.");
$fseek(fp,0,2);//Go to EOF
EOF=$ftell(fp);//EOF position
disp_current_position(fp);
for (i=0;i< No_of_Checks;i=i+1) begin
position={$random} % EOF;//or $unsigned($random) %EOF
word_pos=(position/STR_LEN);
aligned_pos=word_pos*STR_LEN;
$fseek(fp,aligned_pos,0);//Goto aligned_pos
$fscanf(fp,"%h\n",R2);
word={word_pos+3,word_pos+2,word_pos+1,word_pos};
if (word !==R2[127:0] ) begin//Check result
$display("Fails. Error detected");
$stop;//assert(0);
end
end
$display("Random Test passed. Random %d seeks performed . Error Detected 0",No_of_Checks);
end
endtask
endmodule
Opencores Veritak プロジェクトファイル(Version1.41A)
Opencoresには、プロフェッショナルが書いた様々なIPコアがあります。これを簡単に、評価/研究してみたい方も多いのではないでしょうか?
ところが、Opencores流儀のINCLUDE ファイルや、Defineの設定等が必要な場合があり、 原作者のシミュレータ環境がないと簡単にいかないところがあります。シミュレータが走り出すまでに挫折してしまった人もいるかもしれません。
そこで、Veritakプロジェクトファイルを作成し便宜を図りました。
解凍して、「Verilogプロジェクト=>Load Verilog」でプロジェクトファイルをロード、「Go」だけでテストベンチが走りだします。
人のRTLソースは、理解しがたいものですが、トレースファイル(タグファイル)も添付していますので、解析の一助になるでしょう。
必要に応じてトレースモードでコンパイルすることで、階層View、VeriPad、トレースファイル(タグファイル)、WaveformView上でのドライバ特定機能が連動し理想的な解析環境になる筈です。
プロジェクトは、以下の検証可能なテストベンチ付のコアについて作成しました。
プロジェクトは複数作成している場合がありますが、その意味は、次の通りです。
除算器のプロジェクトを追加しました。
プロジェクトの名前 |
内容 |
備考 |
*_no_save.prj |
波形Saveなしのプロジェクト。 |
完走を確認済み。このプロジェクトでは波形(WaveformView)をご覧になれませんのでご注意ください。
|
*_trace_mode.prj |
トレースモードでのプロジェクト |
|
*_trace_mode2.prj |
トレースモード2でのプロジェクト |
トレースファイルの生成用
|
IP CORES |
Veritak プロジェクトファイル位置 |
ソース総行数 |
シミュレーション時間(Athlon64
3000+ 1GB Memory on W2K) |
ダウンロード(ZIP) |
備考 |
AC97 |
\ac97_ctrl\bench\verilog |
11K |
49min54sec |
AC97(0.3MB) |
ac97_no_save.prj |
CAN |
\can |
12K |
0min |
CAN(0.2MB) |
can.prj |
ATA |
\ata |
4K |
13min38sec |
ATA(1MB) |
Nov.22.2004 no_save_ata.prj |
PCI |
\pci\bench\verilog |
89K |
2h |
PCI(14MB) |
pci_no_save.prj |
USB1.1 |
\usb11 |
11K |
2min37sec |
USB1.1(0.3MB) |
`includeを一箇所追加
usb11_no_save.prj |
I2C |
\i2c |
2K |
2sec |
I2C(0.7MB) |
i2c.prj |
ETHERNET |
\ethernet\ethernet |
45K |
4h |
ETHERNET(2.6MB) |
tb_ethernet_no_save.prj |
AES |
\aes_core |
2K |
13sec |
AES(0.2MB) |
aes.prj |
DES |
\des |
2K |
1sec |
DES(0.5MB) |
des_trace_mode.prj |
GENERIC FIFO |
\generic_fifos\generic_fifos\bench\verilog |
2K |
2h |
GENERIC
FIFO(0.1MB) |
fifo_no_save.prj |
GPIO |
\gpio\gpio |
4K |
41sec |
GPIO(0.6MB) |
gpio.prj |
WB_DMA |
\wb_dma |
15K |
46h |
WB_DMA(1.5MB) |
|
WB_CONBUS |
\wb_conbus |
4K |
6sec |
WB_CONBUS(0.4MB) |
conbus.prj |
WB_CONMAX |
\wb_conmax |
11K
|
10min6sec |
WB_CONMAX(0.2MB) |
|
Divider |
dividers\bench\verilog |
|
|
divierders |
divider.vtakprj (Version 2.11以上 RunLength1000us) |
**秒数まで、明示してあるものは、Goから$finishまでの時間です。(コンパイラステータス画面に出ます。) これで、ご自分のPCとAthlon64 3000+ DUAL PC3200 2GB メモリとPCの性能比較ができます。
(たとえば、Pentium500MHzだと、6倍弱程度にはなっているようです。
Veritak Version は、上がっており、計測時間は、古いVersionのデータです。例えば、ダイレクトコンパイルドVersion
2.20で、AC97を見ると10分以下,ETHERNETは、15分以下になっています。
<Opencoresについて>
大作が多いです。なかには、シミュレーション時間が異常にかかっているものがありますが、(上のCPUベンチマークテスト例では、長くても数分です)
これは、Regression Testで、網羅的なテストをしているためです。中身は、task毎で分割記述され、それをFOR LOOPで回しているので、設計エッセンスのシミュレーションでは、それほど多くを見る必要はないでしょう。
ハードウェアの記述に、 たとえば、A<=#1Aを使っている(シミュレーションサイクルが余計にかかる以外に何の益もない記述)、テストベンチでのRace記述が多い、等、
必ずしもよい記述と言えないものも含まれていますが、全体のレベルとしては高く、大変参考になると思います。
ところで、このOpencores はどうしてあるの?設計したプロセッサは、何の意味あるの?という質問がどこからか飛んできそうです。筆者の場合は、FAQSにVeritakの目指しているものとして書いてありますのそちらをご参照を。
Opencoresの人達の答えを引用します。
Mainly for fun.
Other reasons include:
- to learn,
- to teach,
- to improve your resume,
- to make the world a better place to live in.
This list goes on
forever, as everyone has their own reasons.
CRCのRTL自動生成プログラムの解析(May.5.2005 終了)
<概略>
下記リンクで、WEB上で、任意生成多項式、任意ビット数のRTLソースが得られます。
http://www.easics.be/webtools/crctool
実際にやってみると確かに生成します。ところで、これは、どうやって生成しているのでしょうか?生成プログラムを書いて、同じコードを出力することを確認しました。
また、使い方の例として、Verilog-2001でテストベンチを書きました。(本文は、英文です。)
なお、CRCについては以下が詳しいです。
インターフェース2004 12月号CRC回路の作り方とアレンジ 森岡澄夫氏
理論から学びたい方は、
符号理論 電子情報通信学会 今井秀樹
をお勧めします。
=>CRC32(RFC2083) のC プログラムと結果が合わない、というご質問をいただきました。
解析してみたところ、ビットのMSBとLSBが逆順になっておりました。上のH/W生成器は、MSBから入力する仕様になっています。
これを、LSBから入力する仕様のCプログラムと比較する場合は、ビットをリバースする必要がありますね。
そこで、ビットをリバースする記述を追加すると次のようになります。これによるH/Wリソース追加はありません。(配線だけです)
`define CYCLE (10)
`timescale 1ns/1ns
module crc_module_test;
reg RES; // Reset
reg CLK; // clock
reg[31:0] DATA; // data
wire w_RESULT;//TAK
always #20 CLK =~CLK;
parameter RATE = 50;
wire [31:0] DReverse;//TAK
wire [31:0] ResultReverse;//TAK
generate //TAK
genvar g;
for (g=0; g<32;g=g+1) begin :loop
assign DReverse[g]=DATA[31-g];
assign ResultReverse[g]=_crc_module.crc_reg[31-g];
end
endgenerate
initial begin
#0
RES = 0;
CLK = 0;
DATA = 0;
#200
RES=1;
#(RATE*2)
@(negedge CLK);//NEG TAK
DATA = 32'h000_0001;
@(negedge CLK);//NEG TAK
DATA = 0;//32'h30303030;
#1000;
$finish;
end
crc_module _crc_module(
.RES(RES),
.CLK(CLK),
.DATA(DReverse),//TAK
.CRC_RESULT(w_RESULT)
);
endmodule
通常、Cプログラムでは、256Byteのテーブルで、1Byteづつ計算されますが、上のH/W Generatorでは、任意の並列度(任意の語長)で計算することができます。
本例では、32ビット/CLOCKです。
=>その後、さらに、次のようなデータをファイルから読み出したい、というご質問がありました。
; 最初の行コメント大丈夫かな?
12345678
aaaa5555
; これは、コメント行です。冒頭に;が来ること。
1111aaaa
3456789a
; これも、コメント行です。
abcdef01
58d7e7e0
;最後の行のコメント大丈夫かな?
次の記述が、ユーザ様からご提供頂いたソースです。(筆者とやりとりしながら記述されました。=>がコメント部分です。)
この方は、Cでの記述は、筆者より経験をお持ちです。が、Verilog HDLは、似て非なる言語です。Cの類推から間違えやすい
箇所、Verilog 2001のFILE IO/generate 、そして、for loop におけるbreak、continue処理に関する記述が参考になると思います。
テストベンチの記述です。
`define CYCLE (10)
`timescale 1ns/1ns
module crc_module_test;
reg RES; // Reset
reg CLK; // clock
reg START; // calc start
reg[31:0] DATA; // data
parameter integer ROW_LINES=16;//=>パラメタライズ
wire w_RESULT;
always #20 CLK =~CLK;
parameter RATE = 50;
//--------------------------------------------------------------------
//ビット入れ替えMSB<->LSB, D30<->D1,....D16<->D15の場合はこう書くべし
//--------------------------------------------------------------------
//=>次は、ちょっと技です。 assgin DReverse[0]=DATA[31];..... と延々書いてもOKです。
wire [31:0] DReverse;
wire [31:0] ResultReverse;
generate //
genvar g;
for (g=0; g<32;g=g+1) begin :loop
assign DReverse[g]=DATA[31-g];
assign ResultReverse[g]=_crc_module.crc_reg[31-g];
end
endgenerate
//-----------------------------------------------------------
//task readFDATAで読み込むためのバッファを確保
//-----------------------------------------------------------
reg[31:0] FDATA[0:ROW_LINES]; //実際には2048くらい使いたい。=>パラメタライズ
reg[31:0] td;
reg [8*100:1] str_buffer;//=>$fgets は、テキスト読み込みなのでStrバッファを用意します。
//=>8は、charの意味です。コメントもありますので、十分大きく(100)に変更しました。
//-----------------------------------------------------------
//読み込みを開始
//-----------------------------------------------------------
task readFDATA;
integer fp;
integer i, r,c;
begin
fp = $fopen("tp.txt", "r"); //ダメ元でやってみました。
//=>OKです。 "r" を指定しないとDefault"w"なので
//大切なファイルが壊れてしまいます。
if (!fp)
begin
$display(" Open error!\n"); //ファイルが存在しなければ終了
$finish;
end
begin : gloval_loop //=>break するためのラベル
for(i=0; i< ROW_LINES;i=i+1) // i<16 =>直接数値指定するよりROW_LINES パラメータで指定した方が保守性がよろしいかと思います。
begin :local_loop //=>continueするためのラベル
if( !$feof(fp) )
begin
c=$fgetc(fp);//=>一文字読み込みます。
if (c==";") begin //=>コメント処理は冒頭の1文字を読みます。
//=> str_buffer[1] では、一ビットのセレクトになってしまいます。
//=>また、";"のバッファ上の位置は、コメントの長さによってしまう為、上記の記述としました。
r = $fgets(str_buffer,fp);//; の次から1行読みます
$display("Comment %s",str_buffer);//コメント行発見
i=i-1;//かなり苦しいです。。
disable local_loop;//continue
end
$ungetc(c,fp);//読み込んだ1文字を戻します。
// r = $fgets(td, 10, fp); //=>ファイルから1行読み込む。読み込むデータは32ビット分
r = $fgets(str_buffer,fp); //=> Cとは違います。10を指定するパラメータはありません。
$sscanf(str_buffer,"%h\n",td); //=>sscanf で改行までバッファを解析して数値に直します。
$display("%d:read data= %h \n",i,td);
FDATA[i] = td; //32ビット分のデータを格納
end
else
begin
$fclose(fp);
//ファイルの最後に到達したら抜けたい
//Cでいうbreakしたいが、表記不明
disable gloval_loop; //=>でbreakに相当します。
//=>ちなみにcontinue は、disable local_loop としてください。
end
end //end local_loop
end //gloval_loop
$display("Exit Task ");
end //endtask
endtask
integer i;
initial begin
// integer i;=> initail processの外で宣言してください。
readFDATA; //定義したタスクをコール
RES = 0;
CLK = 0;
DATA = 0;
START = 0;
i=0;
#200
RES=1;
#(RATE*2)
//ファイルから読み込んだFDATAを使ってCRC入力したい。
for(i=0; i<ROW_LINES; i=i+1)//=>i++ は、Verilog2001ではありません。
begin
@(negedge CLK);//=>ハードがPosなので、neg で入力してやれば、レース問題を回避できます。
if(i==0)
START = 1;
DATA = FDATA[i] ; //わざわざ数値を指定するのではなくファイルから読んだ値を使いたい
end
#1000;
$finish;
end
crc_module _crc_module(//=>DUT ハードウェアをインスタンス化します
.RES(RES),
.CLK(CLK),
.START(START),
.DATA(DReverse),
.CRC_RESULT(w_RESULT)
);
endmodule
ハードウェア本体の記述です。合成可能なソースに仕上がっていると思います。
/*******************************************************************************
** crc check
*******************************************************************************/
module crc_module(
RES, // input :Reset
CLK,
START, // crc calc start
DATA, // input :data
CRC_RESULT
);
/****************************************************************
モジュール入力、出力
****************************************************************/
input RES; // Reset
input CLK;
input START;
input[31:0] DATA; // data
output CRC_RESULT; //
/****************************************************************
reg [内部で使用]
****************************************************************/
reg [31:0] crc_reg;
reg crc_result;
wire[31:0] w_data;
wire[31:0] w_crc_temp;
/****************************************************************
出力設定
****************************************************************/
assign CRC_RESULT = crc_result;
assign w_data = DATA;
generate //=>Verilog-2001 generate Xilinx は、OKですが、Altera 5.1では、まだ対応できていないようです。
genvar g;
for (g=0; g<32;g=g+1)
begin
:loop
assign w_crc_temp[g] = crc_reg[31-g];
end
endgenerate
//---------------------------------------------------------
// crc check
//---------------------------------------------------------
always @ (posedge CLK)
if(RES == 0)
begin
crc_reg <= 32'hffffffff;
crc_result <= 0;
end
else
begin
if(START == 1)
begin
crc_reg = nextCRC32_D32(w_data, crc_reg);
if(crc_reg == 0)
begin
crc_result <= 1;
end
end
end
///////////////////////////////////////////////////////////////////////
// File: CRC32_D32.v
// Date: Sat Jan 7 09:33:48 2006
//
// Copyright (C) 1999-2003 Easics NV.
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Purpose: Verilog module containing a synthesizable CRC function
// * polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
// * data width: 32
//
// Info: tools@easics.be
// http://www.easics.com
///////////////////////////////////////////////////////////////////////
// polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
// data width: 32
// convention: the first serial data bit is D[31]
function [31:0] nextCRC32_D32;
input [31:0] Data;
input [31:0] CRC;
reg [31:0] D;
reg [31:0] C;
reg [31:0] NewCRC;
begin
D = Data;
C = CRC;
NewCRC[0] = D[31] ^ D[30] ^ D[29] ^ D[28] ^ D[26] ^ D[25] ^ D[24] ^
D[16] ^ D[12] ^ D[10] ^ D[9] ^ D[6] ^ D[0] ^ C[0] ^
C[6] ^ C[9] ^ C[10] ^ C[12] ^ C[16] ^ C[24] ^ C[25] ^
C[26] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
NewCRC[1] = D[28] ^ D[27] ^ D[24] ^ D[17] ^ D[16] ^ D[13] ^ D[12] ^
D[11] ^ D[9] ^ D[7] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[1] ^
C[6] ^ C[7] ^ C[9] ^ C[11] ^ C[12] ^ C[13] ^ C[16] ^
C[17] ^ C[24] ^ C[27] ^ C[28];
NewCRC[2] = D[31] ^ D[30] ^ D[26] ^ D[24] ^ D[18] ^ D[17] ^ D[16] ^
D[14] ^ D[13] ^ D[9] ^ D[8] ^ D[7] ^ D[6] ^ D[2] ^
D[1] ^ D[0] ^ C[0] ^ C[1] ^ C[2] ^ C[6] ^ C[7] ^ C[8] ^
C[9] ^ C[13] ^ C[14] ^ C[16] ^ C[17] ^ C[18] ^ C[24] ^
C[26] ^ C[30] ^ C[31];
NewCRC[3] = D[31] ^ D[27] ^ D[25] ^ D[19] ^ D[18] ^ D[17] ^ D[15] ^
D[14] ^ D[10] ^ D[9] ^ D[8] ^ D[7] ^ D[3] ^ D[2] ^
D[1] ^ C[1] ^ C[2] ^ C[3] ^ C[7] ^ C[8] ^ C[9] ^ C[10] ^
C[14] ^ C[15] ^ C[17] ^ C[18] ^ C[19] ^ C[25] ^ C[27] ^
C[31];
NewCRC[4] = D[31] ^ D[30] ^ D[29] ^ D[25] ^ D[24] ^ D[20] ^ D[19] ^
D[18] ^ D[15] ^ D[12] ^ D[11] ^ D[8] ^ D[6] ^ D[4] ^
D[3] ^ D[2] ^ D[0] ^ C[0] ^ C[2] ^ C[3] ^ C[4] ^ C[6] ^
C[8] ^ C[11] ^ C[12] ^ C[15] ^ C[18] ^ C[19] ^ C[20] ^
C[24] ^ C[25] ^ C[29] ^ C[30] ^ C[31];
NewCRC[5] = D[29] ^ D[28] ^ D[24] ^ D[21] ^ D[20] ^ D[19] ^ D[13] ^
D[10] ^ D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[3] ^ D[1] ^ D[0] ^
C[0] ^ C[1] ^ C[3] ^ C[4] ^ C[5] ^ C[6] ^ C[7] ^ C[10] ^
C[13] ^ C[19] ^ C[20] ^ C[21] ^ C[24] ^ C[28] ^ C[29];
NewCRC[6] = D[30] ^ D[29] ^ D[25] ^ D[22] ^ D[21] ^ D[20] ^ D[14] ^
D[11] ^ D[8] ^ D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^
C[1] ^ C[2] ^ C[4] ^ C[5] ^ C[6] ^ C[7] ^ C[8] ^ C[11] ^
C[14] ^ C[20] ^ C[21] ^ C[22] ^ C[25] ^ C[29] ^ C[30];
NewCRC[7] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^
D[16] ^ D[15] ^ D[10] ^ D[8] ^ D[7] ^ D[5] ^ D[3] ^
D[2] ^ D[0] ^ C[0] ^ C[2] ^ C[3] ^ C[5] ^ C[7] ^ C[8] ^
C[10] ^ C[15] ^ C[16] ^ C[21] ^ C[22] ^ C[23] ^ C[24] ^
C[25] ^ C[28] ^ C[29];
NewCRC[8] = D[31] ^ D[28] ^ D[23] ^ D[22] ^ D[17] ^ D[12] ^ D[11] ^
D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[0] ^ C[1] ^
C[3] ^ C[4] ^ C[8] ^ C[10] ^ C[11] ^ C[12] ^ C[17] ^
C[22] ^ C[23] ^ C[28] ^ C[31];
NewCRC[9] = D[29] ^ D[24] ^ D[23] ^ D[18] ^ D[13] ^ D[12] ^ D[11] ^
D[9] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[1] ^ C[2] ^ C[4] ^
C[5] ^ C[9] ^ C[11] ^ C[12] ^ C[13] ^ C[18] ^ C[23] ^
C[24] ^ C[29];
NewCRC[10] = D[31] ^ D[29] ^ D[28] ^ D[26] ^ D[19] ^ D[16] ^ D[14] ^
D[13] ^ D[9] ^ D[5] ^ D[3] ^ D[2] ^ D[0] ^ C[0] ^ C[2] ^
C[3] ^ C[5] ^ C[9] ^ C[13] ^ C[14] ^ C[16] ^ C[19] ^
C[26] ^ C[28] ^ C[29] ^ C[31];
NewCRC[11] = D[31] ^ D[28] ^ D[27] ^ D[26] ^ D[25] ^ D[24] ^ D[20] ^
D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[12] ^ D[9] ^ D[4] ^
D[3] ^ D[1] ^ D[0] ^ C[0] ^ C[1] ^ C[3] ^ C[4] ^ C[9] ^
C[12] ^ C[14] ^ C[15] ^ C[16] ^ C[17] ^ C[20] ^ C[24] ^
C[25] ^ C[26] ^ C[27] ^ C[28] ^ C[31];
NewCRC[12] = D[31] ^ D[30] ^ D[27] ^ D[24] ^ D[21] ^ D[18] ^ D[17] ^
D[15] ^ D[13] ^ D[12] ^ D[9] ^ D[6] ^ D[5] ^ D[4] ^
D[2] ^ D[1] ^ D[0] ^ C[0] ^ C[1] ^ C[2] ^ C[4] ^ C[5] ^
C[6] ^ C[9] ^ C[12] ^ C[13] ^ C[15] ^ C[17] ^ C[18] ^
C[21] ^ C[24] ^ C[27] ^ C[30] ^ C[31];
NewCRC[13] = D[31] ^ D[28] ^ D[25] ^ D[22] ^ D[19] ^ D[18] ^ D[16] ^
D[14] ^ D[13] ^ D[10] ^ D[7] ^ D[6] ^ D[5] ^ D[3] ^
D[2] ^ D[1] ^ C[1] ^ C[2] ^ C[3] ^ C[5] ^ C[6] ^ C[7] ^
C[10] ^ C[13] ^ C[14] ^ C[16] ^ C[18] ^ C[19] ^ C[22] ^
C[25] ^ C[28] ^ C[31];
NewCRC[14] = D[29] ^ D[26] ^ D[23] ^ D[20] ^ D[19] ^ D[17] ^ D[15] ^
D[14] ^ D[11] ^ D[8] ^ D[7] ^ D[6] ^ D[4] ^ D[3] ^
D[2] ^ C[2] ^ C[3] ^ C[4] ^ C[6] ^ C[7] ^ C[8] ^ C[11] ^
C[14] ^ C[15] ^ C[17] ^ C[19] ^ C[20] ^ C[23] ^ C[26] ^
C[29];
NewCRC[15] = D[30] ^ D[27] ^ D[24] ^ D[21] ^ D[20] ^ D[18] ^ D[16] ^
D[15] ^ D[12] ^ D[9] ^ D[8] ^ D[7] ^ D[5] ^ D[4] ^
D[3] ^ C[3] ^ C[4] ^ C[5] ^ C[7] ^ C[8] ^ C[9] ^ C[12] ^
C[15] ^ C[16] ^ C[18] ^ C[20] ^ C[21] ^ C[24] ^ C[27] ^
C[30];
NewCRC[16] = D[30] ^ D[29] ^ D[26] ^ D[24] ^ D[22] ^ D[21] ^ D[19] ^
D[17] ^ D[13] ^ D[12] ^ D[8] ^ D[5] ^ D[4] ^ D[0] ^
C[0] ^ C[4] ^ C[5] ^ C[8] ^ C[12] ^ C[13] ^ C[17] ^
C[19] ^ C[21] ^ C[22] ^ C[24] ^ C[26] ^ C[29] ^ C[30];
NewCRC[17] = D[31] ^ D[30] ^ D[27] ^ D[25] ^ D[23] ^ D[22] ^ D[20] ^
D[18] ^ D[14] ^ D[13] ^ D[9] ^ D[6] ^ D[5] ^ D[1] ^
C[1] ^ C[5] ^ C[6] ^ C[9] ^ C[13] ^ C[14] ^ C[18] ^
C[20] ^ C[22] ^ C[23] ^ C[25] ^ C[27] ^ C[30] ^ C[31];
NewCRC[18] = D[31] ^ D[28] ^ D[26] ^ D[24] ^ D[23] ^ D[21] ^ D[19] ^
D[15] ^ D[14] ^ D[10] ^ D[7] ^ D[6] ^ D[2] ^ C[2] ^
C[6] ^ C[7] ^ C[10] ^ C[14] ^ C[15] ^ C[19] ^ C[21] ^
C[23] ^ C[24] ^ C[26] ^ C[28] ^ C[31];
NewCRC[19] = D[29] ^ D[27] ^ D[25] ^ D[24] ^ D[22] ^ D[20] ^ D[16] ^
D[15] ^ D[11] ^ D[8] ^ D[7] ^ D[3] ^ C[3] ^ C[7] ^
C[8] ^ C[11] ^ C[15] ^ C[16] ^ C[20] ^ C[22] ^ C[24] ^
C[25] ^ C[27] ^ C[29];
NewCRC[20] = D[30] ^ D[28] ^ D[26] ^ D[25] ^ D[23] ^ D[21] ^ D[17] ^
D[16] ^ D[12] ^ D[9] ^ D[8] ^ D[4] ^ C[4] ^ C[8] ^
C[9] ^ C[12] ^ C[16] ^ C[17] ^ C[21] ^ C[23] ^ C[25] ^
C[26] ^ C[28] ^ C[30];
NewCRC[21] = D[31] ^ D[29] ^ D[27] ^ D[26] ^ D[24] ^ D[22] ^ D[18] ^
D[17] ^ D[13] ^ D[10] ^ D[9] ^ D[5] ^ C[5] ^ C[9] ^
C[10] ^ C[13] ^ C[17] ^ C[18] ^ C[22] ^ C[24] ^ C[26] ^
C[27] ^ C[29] ^ C[31];
NewCRC[22] = D[31] ^ D[29] ^ D[27] ^ D[26] ^ D[24] ^ D[23] ^ D[19] ^
D[18] ^ D[16] ^ D[14] ^ D[12] ^ D[11] ^ D[9] ^ D[0] ^
C[0] ^ C[9] ^ C[11] ^ C[12] ^ C[14] ^ C[16] ^ C[18] ^
C[19] ^ C[23] ^ C[24] ^ C[26] ^ C[27] ^ C[29] ^ C[31];
NewCRC[23] = D[31] ^ D[29] ^ D[27] ^ D[26] ^ D[20] ^ D[19] ^ D[17] ^
D[16] ^ D[15] ^ D[13] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^
C[0] ^ C[1] ^ C[6] ^ C[9] ^ C[13] ^ C[15] ^ C[16] ^
C[17] ^ C[19] ^ C[20] ^ C[26] ^ C[27] ^ C[29] ^ C[31];
NewCRC[24] = D[30] ^ D[28] ^ D[27] ^ D[21] ^ D[20] ^ D[18] ^ D[17] ^
D[16] ^ D[14] ^ D[10] ^ D[7] ^ D[2] ^ D[1] ^ C[1] ^
C[2] ^ C[7] ^ C[10] ^ C[14] ^ C[16] ^ C[17] ^ C[18] ^
C[20] ^ C[21] ^ C[27] ^ C[28] ^ C[30];
NewCRC[25] = D[31] ^ D[29] ^ D[28] ^ D[22] ^ D[21] ^ D[19] ^ D[18] ^
D[17] ^ D[15] ^ D[11] ^ D[8] ^ D[3] ^ D[2] ^ C[2] ^
C[3] ^ C[8] ^ C[11] ^ C[15] ^ C[17] ^ C[18] ^ C[19] ^
C[21] ^ C[22] ^ C[28] ^ C[29] ^ C[31];
NewCRC[26] = D[31] ^ D[28] ^ D[26] ^ D[25] ^ D[24] ^ D[23] ^ D[22] ^
D[20] ^ D[19] ^ D[18] ^ D[10] ^ D[6] ^ D[4] ^ D[3] ^
D[0] ^ C[0] ^ C[3] ^ C[4] ^ C[6] ^ C[10] ^ C[18] ^
C[19] ^ C[20] ^ C[22] ^ C[23] ^ C[24] ^ C[25] ^ C[26] ^
C[28] ^ C[31];
NewCRC[27] = D[29] ^ D[27] ^ D[26] ^ D[25] ^ D[24] ^ D[23] ^ D[21] ^
D[20] ^ D[19] ^ D[11] ^ D[7] ^ D[5] ^ D[4] ^ D[1] ^
C[1] ^ C[4] ^ C[5] ^ C[7] ^ C[11] ^ C[19] ^ C[20] ^
C[21] ^ C[23] ^ C[24] ^ C[25] ^ C[26] ^ C[27] ^ C[29];
NewCRC[28] = D[30] ^ D[28] ^ D[27] ^ D[26] ^ D[25] ^ D[24] ^ D[22] ^
D[21] ^ D[20] ^ D[12] ^ D[8] ^ D[6] ^ D[5] ^ D[2] ^
C[2] ^ C[5] ^ C[6] ^ C[8] ^ C[12] ^ C[20] ^ C[21] ^
C[22] ^ C[24] ^ C[25] ^ C[26] ^ C[27] ^ C[28] ^ C[30];
NewCRC[29] = D[31] ^ D[29] ^ D[28] ^ D[27] ^ D[26] ^ D[25] ^ D[23] ^
D[22] ^ D[21] ^ D[13] ^ D[9] ^ D[7] ^ D[6] ^ D[3] ^
C[3] ^ C[6] ^ C[7] ^ C[9] ^ C[13] ^ C[21] ^ C[22] ^
C[23] ^ C[25] ^ C[26] ^ C[27] ^ C[28] ^ C[29] ^ C[31];
NewCRC[30] = D[30] ^ D[29] ^ D[28] ^ D[27] ^ D[26] ^ D[24] ^ D[23] ^
D[22] ^ D[14] ^ D[10] ^ D[8] ^ D[7] ^ D[4] ^ C[4] ^
C[7] ^ C[8] ^ C[10] ^ C[14] ^ C[22] ^ C[23] ^ C[24] ^
C[26] ^ C[27] ^ C[28] ^ C[29] ^ C[30];
NewCRC[31] = D[31] ^ D[30] ^ D[29] ^ D[28] ^ D[27] ^ D[25] ^ D[24] ^
D[23] ^ D[15] ^ D[11] ^ D[9] ^ D[8] ^ D[5] ^ C[5] ^
C[8] ^ C[9] ^ C[11] ^ C[15] ^ C[23] ^ C[24] ^ C[25] ^
C[27] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
nextCRC32_D32 = NewCRC;
end
endfunction
endmodule
結果です。
コンソールの出力です。
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
Comment 最初の行コメント大丈夫かな?
0:read data= 12345678
1:read data= aaaa5555
Comment これは、コメント行です。冒頭に;が来ること。
2:read data= 1111aaaa
3:read data= 3456789a
Comment これも、コメント行です。
4:read data= abcdef01
5:read data= 58d7e7e0
Comment 最後の行のコメント大丈夫かな?
Exit Task
Info: $finishコマンドを実行します。time=1920
---------- シミュレーションを終了します。time=1920----------
注意:
iなお、上記は、RFC2083のそれでは、ありません。(出力にINVERTERが入っていません。)
32ビットCRCを8ビットDataで使用する例
こちらの方にあるベンチを少しだけ書き換えて32ビットCRC8ビットデータ版を作ってみました。
CRCのテストは、送信側と受信側で同じCRCを使います。ですので、同じモジュールでインスタンス化すればよいです。
CRC32_D8_Module #(.initial_value(initial_value),.poly_width(poly_width),.data_width(data_width)) crc_sender_module( clock,
data,sync_reset,hold,
crc_sender);
CRC32_D8_Module #(.initial_value(initial_value),.poly_width(poly_width),.data_width(data_width)) crc_receiver_module( clock,
receive_data,sync_reset,receiver_hold,
crc_receiver);
送信側では、CRCを送るときは、生成をホールドします。
for (i=0;i<data_length;i=i+1) begin
data=$random;//ランダムデータを生成
@(negedge clock);
end
hold=1;//送り側CRC生成ホールド
for (i=0;i<crc_bytes;i=i+1) begin//CRCバイト数分送る
data=crc_sender[poly_width-1-data_width*i -:data_width];
@(negedge clock);
end
受信側では、通常のデータとして受信します。上記例では、4ByteのCRC受信後、受け側CRCが0になっていることがわかります。
なお、後半のテストでは、故意にエラーを加えて、CRCが0にならないことを確認します。エラーがあるのにCRCが0になるケースは誤検出です。誤検出確率は、生成多項式に依存
しますので、生のエラーレート環境に応じて適切な生成多項式を選択する必要があります。
テストベンチです。
//Dec.18.2006
module CRC32D8_test_bench;
parameter integer initial_value=-1;
parameter integer poly_width=32;
parameter integer data_width=8;//;
parameter integer maximum_no_of_errors=6;
parameter integer data_length=10;
parameter integer crc_bytes=poly_width/data_width;
reg clock=0;
reg sync_reset=1;
reg hold=0, receiver_hold=0;
wire [poly_width-1:0] crc_sender,crc_receiver;
reg done=0;
integer i,test_loops,error_counter=0;
reg error=0;
reg [data_width-1:0] data=0;
wire [data_width-1:0] receive_data=data^ error;
always #10 clock=~clock;
initial begin
#5;
test_loops=0;
$display("Make sure no CRC error ocrrurs when we don't have error additions.");
//Test 1 Make sure no crc error occurs
repeat (1000) begin
test_loops=test_loops+1;
if (test_loops%100==0) $display("Test Loops=%d",test_loops);
sync_reset=1;
@(negedge clock);
@(negedge clock);
sync_reset=0; hold=0;
for (i=0;i<data_length;i=i+1) begin
data=$random;//ランダムデータを生成
@(negedge clock);
end
hold=1;//送り側CRC生成ホールド
for (i=0;i<crc_bytes;i=i+1) begin//CRCバイト数分送る
data=crc_sender[poly_width-1-data_width*i -:data_width];
@(negedge clock);
end
done=1;
if (crc_receiver !==0) $display("Miss Detection or Programming Error");//CRCが0でなかったらプログラムエラー
@(negedge clock);
done=0;
end
$display("Test Done.!");
//Make sure crc error occurs
$display("Make sure CRC occurs when we have some trivial error additions.");//故意にエラーを加えるテスト
test_loops=0;
repeat (1000) begin
test_loops=test_loops+1;
if (test_loops%1000==0) $display("Test Loops=%d",test_loops);
sync_reset=1;
@(negedge clock);
@(negedge clock);
sync_reset=0; hold=0;error_counter=0;
for (i=0;i<data_length;i=i+1) begin
data=$random;//ランダムデータを生成
if (i==0) begin
error=1;//We add at least one error.
error_counter=error_counter+1;
end else begin//Limit maxinum no of errors
if (error_counter <maximum_no_of_errors) begin
error=$random;//$random error addition
error_counter=error_counter+1;
end
end
@(negedge clock);
end
hold=1;//Stop CRC generation in sender//送り側CRC生成ホールド
for (i=0;i<crc_bytes;i=i+1) begin//CRCバイト数分送る
data=crc_sender[poly_width-1-data_width*i -:data_width];
@(negedge clock);
end
done=1;//CRCが0だったらプログラムエラーか誤検出
if (crc_receiver ==0) $display("Miss Error Detection or Programming Error Test Loops=%d",test_loops);
@(negedge clock);
done=0;
end
$display("Test Done.! .... see you again..");
$finish;
end
CRC32_D8_Module #(.initial_value(initial_value),.poly_width(poly_width),.data_width(data_width)) crc_sender_module( clock,
data,sync_reset,hold,
crc_sender);
CRC32_D8_Module #(.initial_value(initial_value),.poly_width(poly_width),.data_width(data_width)) crc_receiver_module( clock,
receive_data,sync_reset,receiver_hold,
crc_receiver);
endmodule
CRC生成モジュール(H/W)です。
//Dec.18.2006 Tak.S
module CRC32_D8_Module #(parameter integer initial_value=-1, poly_width=32,data_width=8) (input clock,
input [data_width-1:0] data,
input sync_reset,hold,
output reg [poly_width-1:0] crc);
always @(posedge clock) begin
if (sync_reset) crc <=initial_value;
else if (hold) crc <=crc;
else crc<=nextCRC32_D8(data,crc);
end
///////////////////////////////////////////////////////////////////////
// File: CRC32_D8.v
// Date: Mon Dec 18 10:47:11 2006
//
// Copyright (C) 1999-2003 Easics NV.
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Purpose: Verilog module containing a synthesizable CRC function
// * polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
// * data width: 8
//
// Info: tools@easics.be
// http://www.easics.com
///////////////////////////////////////////////////////////////////////
// polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
// data width: 8
// convention: the first serial data bit is D[7]
function [31:0] nextCRC32_D8;
input [7:0] Data;
input [31:0] CRC;
reg [7:0] D;
reg [31:0] C;
reg [31:0] NewCRC;
begin
D = Data;
C = CRC;
NewCRC[0] = D[6] ^ D[0] ^ C[24] ^ C[30];
NewCRC[1] = D[7] ^ D[6] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[30] ^
C[31];
NewCRC[2] = D[7] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^
C[26] ^ C[30] ^ C[31];
NewCRC[3] = D[7] ^ D[3] ^ D[2] ^ D[1] ^ C[25] ^ C[26] ^ C[27] ^
C[31];
NewCRC[4] = D[6] ^ D[4] ^ D[3] ^ D[2] ^ D[0] ^ C[24] ^ C[26] ^
C[27] ^ C[28] ^ C[30];
NewCRC[5] = D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[24] ^
C[25] ^ C[27] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
NewCRC[6] = D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[25] ^ C[26] ^
C[28] ^ C[29] ^ C[30] ^ C[31];
NewCRC[7] = D[7] ^ D[5] ^ D[3] ^ D[2] ^ D[0] ^ C[24] ^ C[26] ^
C[27] ^ C[29] ^ C[31];
NewCRC[8] = D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[0] ^ C[24] ^ C[25] ^
C[27] ^ C[28];
NewCRC[9] = D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[1] ^ C[25] ^ C[26] ^
C[28] ^ C[29];
NewCRC[10] = D[5] ^ D[3] ^ D[2] ^ D[0] ^ C[2] ^ C[24] ^ C[26] ^
C[27] ^ C[29];
NewCRC[11] = D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[3] ^ C[24] ^ C[25] ^
C[27] ^ C[28];
NewCRC[12] = D[6] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^ D[0] ^ C[4] ^ C[24] ^
C[25] ^ C[26] ^ C[28] ^ C[29] ^ C[30];
NewCRC[13] = D[7] ^ D[6] ^ D[5] ^ D[3] ^ D[2] ^ D[1] ^ C[5] ^ C[25] ^
C[26] ^ C[27] ^ C[29] ^ C[30] ^ C[31];
NewCRC[14] = D[7] ^ D[6] ^ D[4] ^ D[3] ^ D[2] ^ C[6] ^ C[26] ^ C[27] ^
C[28] ^ C[30] ^ C[31];
NewCRC[15] = D[7] ^ D[5] ^ D[4] ^ D[3] ^ C[7] ^ C[27] ^ C[28] ^
C[29] ^ C[31];
NewCRC[16] = D[5] ^ D[4] ^ D[0] ^ C[8] ^ C[24] ^ C[28] ^ C[29];
NewCRC[17] = D[6] ^ D[5] ^ D[1] ^ C[9] ^ C[25] ^ C[29] ^ C[30];
NewCRC[18] = D[7] ^ D[6] ^ D[2] ^ C[10] ^ C[26] ^ C[30] ^ C[31];
NewCRC[19] = D[7] ^ D[3] ^ C[11] ^ C[27] ^ C[31];
NewCRC[20] = D[4] ^ C[12] ^ C[28];
NewCRC[21] = D[5] ^ C[13] ^ C[29];
NewCRC[22] = D[0] ^ C[14] ^ C[24];
NewCRC[23] = D[6] ^ D[1] ^ D[0] ^ C[15] ^ C[24] ^ C[25] ^ C[30];
NewCRC[24] = D[7] ^ D[2] ^ D[1] ^ C[16] ^ C[25] ^ C[26] ^ C[31];
NewCRC[25] = D[3] ^ D[2] ^ C[17] ^ C[26] ^ C[27];
NewCRC[26] = D[6] ^ D[4] ^ D[3] ^ D[0] ^ C[18] ^ C[24] ^ C[27] ^
C[28] ^ C[30];
NewCRC[27] = D[7] ^ D[5] ^ D[4] ^ D[1] ^ C[19] ^ C[25] ^ C[28] ^
C[29] ^ C[31];
NewCRC[28] = D[6] ^ D[5] ^ D[2] ^ C[20] ^ C[26] ^ C[29] ^ C[30];
NewCRC[29] = D[7] ^ D[6] ^ D[3] ^ C[21] ^ C[27] ^ C[30] ^ C[31];
NewCRC[30] = D[7] ^ D[4] ^ C[22] ^ C[28] ^ C[31];
NewCRC[31] = D[5] ^ C[23] ^ C[29];
nextCRC32_D8 = NewCRC;
end
endfunction
endmodule
F.A.Q.
Q.MSBとLSBを入れ替え・ ビット極性について
頂いたソースとテストベンチでさっそく
シュミレーションしてみました
やはり 結果CRCのMSBとLSBの反転 と極性の反転が起きます
実行しましすと
最初のDATA 0x24に対して 波形上で出力されるCRCは
”C52F7F88"でした
フリーのソフトのCRC32の計算ソフトで計算させると
”EE010B5C"となりました
2種類のフリーソフトで試してみましたが 同じ結果でした
”C52F7F88"を MSBとLSBを入れ替えて ビット極性を反転させると
”EE010B5C"となります
なにか私が勘違いしているのでしょうか?
A.それは、CRCの利用の定義に依存します
本質的なのは、生成多項式で、これだけで誤検出確率を決定します。
CRC初期値や、INVや順序を変えても、同じ生成多項式なら、誤検出確率は変わりません。
つまり、送信と受信がClosedした世界(上のCRCや、HDD内部等)では、CRC初期値/INV/順序を変えて定義してなんら誤検出確率は変わりません。
利用するときのプロトコルの問題です。
既に送信側受信側の処理が決まっている場合(Ethernet/CD/FDD/DVDのCRCとか)は、CRC初期値はいくらにするとか、INVするとかMSBから入れるかLSBから入れるか、
これらは、そのプロトコルSpec.のなかで定義しているはずですから、それにあわせこむ必要があります。(結果的にxx様がやられている作業です)
でないと、まさにCRCエラーになってしまいますね。勿論テストベンチは、その場合、そのプロトコルに沿う形にするべきでしょう。
アナログPLLのシミュレーション(May.7.2005 終了)
一つの古典的なデザインを行ってみました。
リードソロモン自動プログラムの実験 (Under Development)
リードソロモンは、CDやDVDで使われている誤り訂正(ECC)の一種です。5年位前のハードディスクのテクノロジーでは、5インターリーブのの3重訂正(CPUベンチマークで取り上げました。)が使われていました。(CDは2重訂正までです。)
リードソロモンは、訂正次数が3次までなら、比較的簡単な代数方程式で高速に解くことができます。(なので、CD・DVD・HardDiskではインターリーブを使ってバーストエラー能力を上げてます。)
3次以下では、CPUベンチマークに示した代数手法例(3次方程式の一般解:カルダノの公式)で、それ以上では、探索による方法(5次以上の代数方程式の一般解が存在しないように)、以下の自動Verilogが一般的だと思います。
ガロア体上の乗除算は、CPUでは表引きになるので、高速化のためには、ハードウェアで演算するのが一般的でした。(2次元バーコードように低速でよい場合には、現在でもソフトウェアで可能です。)
今後、組み込みCPUが、リコンフィグアブルになってくると、ガロア体のALUを装備して、命令追加したCPUで行う場面も多くなってくるでしょう。
SourceForgeで、Verilogを自動出力してくれるプログラムを見つけました。簡単にできるようなら、実験してみたいと思います。
=>テストベンチを吐いてくれないので、自分で作らなければなりません。コードは、それなりに吐くみたいです。Erasureは、サポートされていませんし、更新も滞っているようです。
とりあえず、VC++でコンパイルしたバイナリを入れておきます。 CDで使われている生成多項式で、接続H/Wとテストベンチを書くつもりでしたが、下のコンテストの問題で時間がなくなってしまいました。
デザインウェーブ コンテスト2005を解く(終了)
FMレシーバの問題です。まず、疑問に思うのは、設計仕様の曖昧なところです。送信波形の帯域制限(スペクトラム整形)は、どうなっているのでしょうか? 受信フィルタの最適化設計においては、必要だと思うのですが。
さらに、三角波は、無限帯域を持つ。。。
とりあえず、DPLLの実装例としては、面白い課題だと思うので、取り組んでみたいと思います。コンテストのHPを見ましたが、誌面で設計されているソース(Verilog/VHDL)はないようです。
そこで、誌面で説明されている設計の(例題としての)Veritakプロジェクトを作成し便宜を図りろうと思ったのですが、興味がDPLLからARCTANに移ってしまいました。)
=>
少し、検討してみました。これは、DPLLとして考えるよりFSKとして考えた方がよさそうです。
確かに、位相がロックすれば、周波数ずれはないので、確実に周波数変化を捉えることができます。しかし、要は、周波数変化=>位相の変化が分かればよい訳で、必ずしもPLLにこだわる必要はないでしょう。
ソフトウェア無線的な考えで、高機能を狙うよりも、ハードウェア(FPGA)にしかできないこと(そのうち、ソフトウェアで出来てしまうのがこの世界の常ですが。)、すなわちスピードで最速を狙う設計をしてみたいと思います。
それにしてもS/Nを無視してよいのかどうかで、まったく設計が異なってしまいます。実用性を無視ししたコンテスト課題と捉えるか、ある程度、実使用に耐えうる設計とするか悩みどころですね。
=>
かなり検討(休日のAM)してみました。1月号のDWM誌 西村芳一氏の解説にある通り、やはりPLLのアプローチは、直接的ではありません。
そこで、方式選定ですが、
- パルスカウント法
- 位相直接計算
- Quadrature
のいずれかだと思いました。具体設計はしていませんが、位相計算の方が上での目標に合致するように思います。
(アナログでは、Quadratureによる方法が一般的で、実際、筆者も2.4GHzを110MHzのIFに落とした後、これで設計したことがありました。)
そうなると、最終的には、この問題のキーポイントは、ARCTANをいかに計算するかだと思います。
ARCTANの計算は、CORDICや+テーラ展開等、数種類の計算方法があります。
=>
三角関数の公式をひっぱりだしてさらに検討しました。(休日のPM, 微積もすっかり忘れていました。) 別な視点からよい方法を思いつきました。S/Nを無視すれば、紙の上では、うまくいきそうな多分新しいアルゴリズムです。
とりあえず、NETでSearchした論文で実装例は、ありませんでした。Spartan3(1月号付録)で260MHz位行きそうです。また、検証のためのH/W(PICが小さそう)も余裕で載るでしょう。
後は、
- システムとしてのモデルシミュレーション(MATALBでは記述しないで、Verilogでのシステムモデリング(real、$rungekutta等を使います))
-16h
- デジタルフィルタ設計(T.B.D. ) -4h
- VerilogによるH/W記述 -4h
- Verilog RTLシミュレーション -8h
- 検証用周辺記述、テスト記述 -24h
- Xilinx用記述にマッピング -2h
- Xlinx論理合成 -2h
- Xlinx ポストレイアウトシミュレーション -8h
- FPGA 実機検証(付録にFPGAがつくといつも発売初日に売り切れてしまうようですが、今回は確保済みです。) −8h
- レポート作成 −12h
結構かかりますね。お金はそんなにかからないけど(Veritak+付録基板+その他<1万円)、チームでやるか、暇がある人でないと無理ですね。。。。
=>設計方針を決めました。
- 課題1に取り組む(1/−1)、デジタルFSKと勝手に解釈
- 課題を以下の通り勝手に解釈
GFSKの変調指数(T.B.D 0.5)のRandomDataを造り、そのアイが受信端で、再現することを波形で示す。
メモリ 18ビットx1KWORDx4=>2x1Kx4のサンプルが可=>8KBのデータが収納可能=>ベースバンドで60個分は入る。=>アイは可能
- ベースバンド最速(5MBPSを300MHzCLOCKで)と最小LUT(300LUT)数を目指す。
- CPは、8x8符号付乗算器1個=>Xilinx内蔵は使わずパイプライン化(YACCの乗算器を8ビットベースに変更)
- CPUは載せずに、周辺記述時間を最小にする。スタート=>メモリダンプ=>Excel処理でよい。
コンセプトは、世界最速 Zero-IF Digital FSK Demodulator with Minimum LUTs
on FPGA
このまま、アルゴリズムが破綻しないようだったら、Verilog上でのシミュレーションは、システム/RTL/ゲートと3回行うことになります。抽象から具体設計に落としていくトップダウン設計手法のよい例になっている(いく?)と思うので、
実際に設計、製作していきたいと思います。また、RTLシミュレーションまで行って、行けそうだったらそのまま応募してみたいと思います。
=>システムシミュレーション
1)送信波形の作成
ベースバンドのランダムNRZ波形を作成します。これは、$random %2でOKでしょう。($randomは、Verilog2001仕様では、生成Seq.のシミュレータ互換があります。) これを、ガウスフィルタ(アナログベッセル5次で近似)に通します。
FIRでも記述できますが、Veritakの場合、$rungekuttaを使えるので、こちらの方が簡単です。
次に、FSK変調ですが、f(t)を変調後の波形とすると、瞬時的には、
f(t)=sin(ωt)ですから、
ω=ωc+ωb
ここで、ωcは、キャリア、ωbは、ベースバンドのVCOの角速度になります。
ところが、ωbは変化するので、若干の積分操作が必要になります。
ベースバンドのVCOは、ガウスフィルタの出力に変調度1%を乗算したものにすればOKです。以上の式をそのまま、Verilogで書けば、送信波形の出来上がりです。MATLAB並みに数十行で書けてしまうところがVerilogのいいところです。
ところで、GFSKは、DECT・GSM・Bluetoothで使われている、歴史のある変調方式です。Bluetoothでは、FHのテクニックで、2.4GHz
ISM帯79Channelに拡散されます。
課題は、アナログを想定しているみたいですが、こういったDigital変復調について検討しても面白いのではないでしょうか?
Verilog2001スタイルで書いてみました。
これは、最終的なソースリストです。 Xilinx Coregenで生成したもの以外は、これとuartソース(下)が全てです。
//Jan.27.2005 Refine 2
//Jan.21.2005 Refine
//Jan.19.2005 最終版 Baseband/DemodulatorのEye 生成
// Coe FILE 生成
`timescale 1ps/1ps
module hard_test_bench;
//Hard パラメータ
parameter INPUT_DATA_MSB=7;
parameter HOST_DATA_MSB=((INPUT_DATA_MSB+1)*2-1);
parameter OUTPUT_DATA_MSB=11;
parameter ADDRESS_MSB=11;
//テストベンチパラメータ
parameter real Freq =150e6*1000/999;//150MHz Carrior Frequency
parameter real Modulation =0.01;// +-1% GFSK Modulation
parameter integer Clock_Period=10;//10ps 10ps resolution test bench
parameter File_Name="bessel5.txt";//System Matrix A,B,C,D file for bessl filter
// 3dB cutoff=5MHz
parameter integer Filter_Degree= 5;//System Matrix 's Degree
parameter integer CYCLE=Clock_Period*3*333 ;//
parameter integer BasebandCycle=1000*100/(Clock_Period*2);//10Mbps
localparam integer Item_Counter_Max=2048*2-1;//4KB
parameter integer IQ_Delay=1667;//90Degree shift at 150MHz
parameter integer HOLD_TIME=1;
real fc;//Carrier Frequency
real fb;//BaseBand Frequency
real fm;//Modulated Frequency
//rungekutta systems matrix input/output array
real read_array[0:10];// Input vector for rungekutta
real write_array[0:10];//Output vector from rugekutta
real t;
reg clock=0;
reg signed [11:0] filt_out;//for monitoring
real filt_outr;
reg sync_reset1,sync_reset;
real modulated_waveform;//変調波形
reg signed [INPUT_DATA_MSB:0] demodulator_input;//8x2ビットサンプリング信号
// 復調器の入力になる
real theta,delta_theta,omega;//Dec.22.2004
wire NRZ;//Baseband NRZ
wire TXD;//UART 出力
wire signed [OUTPUT_DATA_MSB:0] demodulated_wave;//復調器出力Data
integer fp=0;
//Hardware IF Signals
reg clk=0;
reg RST_In;
reg [ADDRESS_MSB:0] HOST_ADDRESS=0;
reg [HOST_DATA_MSB:0] HOST_DATA=0;
reg HOST_WRITE_ENABLE=0;
wire CLKFX_OUT;
wire dcm_clock=CLKFX_OUT;//150MHz FPGA output CLOCK
wire delayed_clock;
wire HOST_WRITE_CLOCK;
//システムシミュレーション用
real cos_real,sin_real;
real cos_real_z1,sin_real_z1;
real diff_real;
integer mag;
assign #(HOLD_TIME) HOST_WRITE_CLOCK=delayed_clock;//RTL シミュレーション時、
//HOSTにIQをWriteするためのクロック
assign #(IQ_Delay) delayed_clock = dcm_clock;//CLKFX_OUT;//CLKFX_OUTを90 度
//シフトした150MHz クロック
//テストベンチクロック ベッセルフィルタの時間応答計算に使用するので、十分細かくする
//DCMに端数がでないように3の倍数(150/50)とすること。そうでないとジッタが発生する
always #Clock_Period clock=~clock;
//FPGAシステムクロック 50MHz Starter Kit仕様
always #(CYCLE) clk=~clk;
//NRZ よりベッセルフィルタの時間応答を計算する。
//
//`define USE_ROM_DATA //ROM DATAを使うならこれをONにする
`ifndef USE_ROM_DATA //ROM DATA を使わない場合、NRZより送信変調波を作成する
// ROM DATAを使う場合は、SIM時間短縮のため
//以下は実行しない
always @( clock) begin//Jan.19.2005
t=$time()*1e-12;
read_array[0]=(NRZ==1 ? 1 :-1);//1/0 => 1/-1 にマッピング
$runge_kutta(File_Name,1);//アナログシミュレータで、ベッセルフィルタ出力計算
filt_outr=write_array[Filter_Degree-1];//出力をREALで得る Get filtered outout
filt_out=$rtoi($rint(filt_outr*1023));//フィルタ出力のモニタ用
fc=Freq;
fb=Freq*Modulation*filt_outr;
fm=fc+fb;
omega=2.0*fm*$M_PI;
delta_theta=(Clock_Period)*1e-12*omega;//Jan.19.2005
theta=theta+delta_theta;
modulated_waveform=$sin(theta);//変調した送信波 150MHz
//量子化した、変調した送信波 150MHzオーバフロー考慮、四捨五入後、整数変換
demodulator_input=$rtoi($rint(modulated_waveform*( 2**INPUT_DATA_MSB -1.0)));
end
`else
`endif
//coe file 生成
//`define MAKE_COE_FILE // XILINX RAM 初期化ファイル生成を生成するならON
`ifdef MAKE_COE_FILE
initial begin
fp=$fopen("modulator_out.coe","w");
$fwrite(fp,"memory_initialization_radix=16;\n");
$fwrite(fp,"memory_initialization_vector=\n");
end
`endif
integer item_counter=0;
integer dcm_instead_counter=0;
integer cos_monitor;
always @(posedge dcm_clock) begin//cos エッジ
#1;
HOST_DATA[INPUT_DATA_MSB:0]=demodulator_input;//Set LSB WORD
cos_real_z1=cos_real;
cos_real=modulated_waveform;
cos_monitor=$rtoi(1000*cos_real);
end
always @(posedge delayed_clock) begin//sin エッジ
#1;
HOST_DATA[HOST_DATA_MSB: INPUT_DATA_MSB+1]=demodulator_input;
//Set MSB WORD
if (!HOST_WRITE_ENABLE) HOST_ADDRESS=0;//最初は0
else HOST_ADDRESS=HOST_ADDRESS+1;
//次からインクリメント
HOST_WRITE_ENABLE=1;//Write Start
sin_real_z1=sin_real;
sin_real=modulated_waveform;
diff_real=cos_real*sin_real_z1 -sin_real*cos_real_z1;
diff_real=diff_real*1023*16;
mag=$rtoi(diff_real);
`ifdef MAKE_COE_FILE // XILINX RAM 初期化ファイル生成を生成するなら
if (item_counter==Item_Counter_Max) begin//RAM 最終アドレスまで書いたら
//終わり
$fwrite(fp,"%4h;\n",HOST_DATA);
$fclose(fp);
$finish;
end else begin
$fwrite(fp,"%4h,\n",HOST_DATA);
end
`endif
item_counter=item_counter+1;
end
//NRZ 生成
baseband #(.counter_max(BasebandCycle)) base(clock,NRZ);//NRZ 生成
//アイパターン生成
`define EYE_BASEBAND //ベースバンドのアイパターンを生成するとき これをON
`define EYE_DEMODULATOR //復調器出力のアイパターンを生成するとき これをON
`ifdef EYE_BASEBAND
eye_monitor #(.samples_per_scan(15*2*2),.max_columns(32)
,.Eye_Save_Data_File("eye_base.txt")) eye_base(dcm_clock,filt_out);
`endif
`ifdef EYE_DEMODULATOR
eye_monitor #(.samples_per_scan(15*2*2),.max_columns(32)) eye_demo(dcm_clock,mag);
//mag,demodulated_wave
`endif
//Reset
initial begin
$runge_kutta(File_Name,0,read_array,write_array);//アナログシミュレータ
//のオブジェクト初期化
RST_In=0;
#(10*1000);
RST_In=1;
#(100*1000);
RST_In=0;
end
//復調器
hardware #( .INPUT_DATA_MSB(INPUT_DATA_MSB),
.HOST_DATA_MSB(HOST_DATA_MSB),
.ADDRESS_MSB(ADDRESS_MSB),
.OUTPUT_DATA_MSB(OUTPUT_DATA_MSB) )
dut ( .RST_In(RST_In),//Reset
. CLKIN_IN(clk),//FPGA 入力CLOCK=50MHz
. HOST_CLK(HOST_WRITE_CLOCK),// 復調器RAMへWrite 入力CLOCK
. HOST_ADDRESS(HOST_ADDRESS),//復調器入力 RAM Address指定
. HOST_WRITE_ENABLE(HOST_WRITE_ENABLE),//復調器入力Write
.HOST_DATA(HOST_DATA), // 復調器入力Data
.output_data(demodulated_wave), //復調器出力Data
.CLKFX_OUT(CLKFX_OUT),//150MHz FPGA 出力
.TXD(TXD));//UART 出力 115.2Kbps
//uart read port
wire [7:0] buffer_reg;
wire int_req;
localparam LF=8'h0d;//改行コード
always @(posedge clk, posedge RST_In) begin
if (RST_In) sync_reset <=1'b1;
else sync_reset<=1'b0;
end
//`define READ_GENERATED_UART_DATA //FPGA UARTからのデータをTEXT Save
//=>uart.txt
//RTL とコンペアをとる場合は、コメントをトル
`ifdef READ_GENERATED_UART_DATA
parameter uart_file="uart.txt";//実機が出力したUART テキストファイル
reg [OUTPUT_DATA_MSB:0] uart_mem [0 :4096*2-1];//実機のデータ保持メモリ
reg signed [OUTPUT_DATA_MSB:0] uart_output;//メモリ内容を引っ張り出す
reg [ADDRESS_MSB+1:0] uart_mem_address=-(13'h100a-13'h0c70);
//垂れ流しUART DATAの調整値
initial begin
$readmemh(uart_file,uart_mem);//uart_mem に読み込んだデータを格納
end
always @* uart_output=uart_mem[uart_mem_address];//150MHz クロック同期
always @(posedge CLKFX_OUT) uart_mem_address<=uart_mem_address+1;//
`endif
uart_read uart_read_port( .sync_reset(sync_reset), .clk(clk)
, .rxd(TXD),.buffer_reg(buffer_reg), .int_req(int_req));//実機のTX port のテスト用として
//UART からのデータを12'hxxxCRで表示する
always @(posedge int_req) begin
begin :local
reg [7:0] local_mem [0:3];
integer i=0;
if (i>=4) $stop;//Assert(0);
if (buffer_reg==LF) begin :local2 //pop stack
integer j;
j=0;
while( j < i) begin
$write( "%c",local_mem[j]);
j=j+1;
end
$write(" : time=%t\n",$time);
i=0;//clear stack
end else begin//push stack
local_mem[i]=buffer_reg;
i=i+1;
end
end
end
endmodule
//ランダムNRZを生成する
module baseband
#(parameter counter_max=1000)
(
input clock,
output reg NRZ=1
);
localparam integer MAX=counter_max-1;
localparam integer initial_value_counts=4;//最初は、Bessel安定期間
localparam integer finish_value_counts=counter_max-5;//最後も1にしているが、
//位相があっていないので、Wrap時にNoiseがでる。
reg [15:0] counter=0;
reg [15:0] baseband_counter=0;
always @(posedge clock) begin
if (counter==MAX) counter<=0;//10Mbps counter
else counter<=counter+1;
end
always @(posedge clock) begin
if (counter==MAX) begin
baseband_counter <=baseband_counter+1;
if ( baseband_counter <=initial_value_counts ||
baseband_counter >=finish_value_counts) NRZ<=1;
else NRZ<=$random %2==1;//ランダム 10Mbps NRZ
end
end
endmodule
//アイパターンを作る。EXCEL 読み込み用のコンマセパレート テキストファイルを生成する
//EXCEL読み込み時に、コンマ を指定すること。
module eye_monitor #(parameter samples_per_scan=32,//行数
max_columns=64,//列数
Eye_Save_Data_File="eye_demo.txt" //ファイル名
)
(
input clock,
input signed [11:0] baseband_out
);
integer sample_counter=0;
integer column_counter=0;
integer fi;
integer i,j;
reg [11:0] saved_wave [0:samples_per_scan][0:max_columns];
always @(posedge clock) begin
saved_wave[sample_counter][column_counter] =baseband_out;
if (sample_counter==samples_per_scan-1) begin
sample_counter<=0;
column_counter<=column_counter+1;
if (column_counter==max_columns) begin
save_data_to_file;
$stop;
end
end else sample_counter <=sample_counter+1;
end
task save_data_to_file;
begin
fi=$fopen(Eye_Save_Data_File);
for (i=0;i<samples_per_scan;i=i+1) begin
for (j=0;j< max_columns;j=j+1) begin
if (j==0) $fwrite(fi,"%d ",$signed(saved_wave[i][j]));
else if (j==max_columns-1) $fdisplay(fi,", %d ",$signed(saved_wave[i][j]));
else $fwrite(fi,",%d",$signed(saved_wave[i][j]));
end
end
$fclose(fi);
end
endtask
endmodule
//Jan.27.2005 Refine
//FPGA 回路記述モジュール
//RTL シミュレーション時は、HOSTからIQをもらう 、復調出力12ビット150MHz
//実機では、内蔵ROMによりIQを生成 UART 115.2Kbps で、RAMにSaveされた復調出力を出力
//
module hardware #(parameter INPUT_DATA_MSB=7,
parameter HOST_DATA_MSB=(INPUT_DATA_MSB+1)*2-1,
parameter ADDRESS_MSB=11,
parameter OUTPUT_DATA_MSB=11 )
( input RST_In,
input CLKIN_IN,
input HOST_CLK,
input [ADDRESS_MSB :0] HOST_ADDRESS,
input HOST_WRITE_ENABLE,
input [HOST_DATA_MSB :0] HOST_DATA,
output signed [OUTPUT_DATA_MSB :0] output_data,
output CLKFX_OUT,
output TXD);
reg [ADDRESS_MSB:0] address,address_d,address_dup1,address_dup2,address_dup3,address_dup4,address_dup5;
wire signed [INPUT_DATA_MSB:0] data_in1,data_in2;
//uart
wire [ADDRESS_MSB:0] address_for_uart;
reg sync_reset_uart;
wire clk0;
wire signed [OUTPUT_DATA_MSB:0] demodulated_wave_final;
//XilinX DCMモジュール: 50MHz システムクロックを入力 =>150MHzを出力
mydcm dcm(.CLKIN_IN(CLKIN_IN),
.RST_IN(RST_In),
.CLKFX_OUT(CLKFX_OUT),
.CLKIN_IBUFG_OUT(),
.CLK0_OUT(clk0),
.LOCKED_OUT());
//復調器モジュール: 150MHz クロックで、I/Qを入力、=>復調出力を12ビット幅で出力
demodulator_hardware_new_sampling #(.Demo_MSB(INPUT_DATA_MSB)) demodulator(
.dcm_clock(CLKFX_OUT),//
.async_reset(RST_In),
.modulated_wave_sin(data_in1),//
.modulated_wave_cos(data_in2),//
.demodulated_wave_final(demodulated_wave_final));//
//Dual Portモジュール:12ビットx4KWords
//復調出力SaveのためのDual Port RAM 入力は、復調出力(12ビット幅)=> 出力は、
//UARTに出力しないのなら、RTLシミュレーション用に150MHzで復調出力を出す
//UART選択時は、UART_CNTRLは、アドレスを制御する
//`define UART_TX_OUTPUT
`ifndef UART_TX_OUTPUT //UART を使わないのなら
dualram dual_portram(
.addra(address_dup4),
.addrb(address_dup5),
.clka(CLKFX_OUT),
.clkb(CLKFX_OUT),
.dina(demodulated_wave_final),
.dinb(),
.douta(),
.doutb(output_data),
.wea(1'b1),//Jan.23.2005
.web(1'b0)); // synthesis black_box
`else//uart 出力
dualram dual_portram(
.addra(address_dup4),
.addrb(address_for_uart),
.clka(CLKFX_OUT),
.clkb(clk0),//uart を選択すると出力は50MHz Clockになるので
.dina(demodulated_wave_final),//RAM入力も50MHzサンプリングになる。
.dinb(),
.douta(),
.doutb(output_data),//RAM からの出力Data
.wea(1'b1), //Jan.23.2005
.web(1'b0)); // synthesis black_box
uart_ctrl uart_write_port(
.ASYNC_RESET(RST_In),
.clk_50M(clk0),
.ram_data(output_data),
.ram_address(address_for_uart),
.TXD(TXD));
`endif
//初期化付RAMモジュール:16bits(IQ)x4KWords
//`define USE_ROM_DATA //HOST から生成Dataを使う場合には、コメントアウト
//RTL シミュレーション時は、HOSTからのDATA(150MHz)をバッファリングする
//実機時は、HOST DATAは、無視。RAM初期値を使う
myrom rom(
.addra(address_dup2),
.addrb(HOST_ADDRESS),
.clka(CLKFX_OUT),
.clkb(HOST_CLK),
.dina(),
.dinb(HOST_DATA),
.douta( {data_in2,data_in1}),
.doutb( ),
.wea(1'b0),
`ifdef USE_ROM_DATA //ROM を使うならWRITEしない
.web(1'b0));
`else
.web(HOST_WRITE_ENABLE));
`endif
always @(posedge CLKFX_OUT or posedge RST_In) begin
if (RST_In) address<=0;
else address<=address+1;
end
always @(posedge CLKFX_OUT) address_d<=address;
always @(posedge CLKFX_OUT) address_dup1<=address;
always @(posedge CLKFX_OUT) address_dup2<=address_dup1;
always @(posedge CLKFX_OUT) address_dup3<=address_dup2;
always @(posedge CLKFX_OUT) address_dup4<=address_dup3;
always @(posedge CLKFX_OUT) address_dup5<=address_dup4;
endmodule
//Jan.27.2005 Refine
//FM 復調器
module demodulator_hardware_new_sampling #(parameter Demo_MSB=7) (
input dcm_clock,//150MHz
input async_reset,
input signed [Demo_MSB:0] modulated_wave_sin,//150MHz
input signed [Demo_MSB:0] modulated_wave_cos,//150MHz
output signed [Demo_MSB+4:0] demodulated_wave_final);//150MHz
reg signed [Demo_MSB:0] input_reg_sin,input_reg_cos;
reg signed [Demo_MSB:0] sin_input,cos_input,cos_i,sin_i,cos_r,sin_r;
reg signed [Demo_MSB:0] sin_z2,cos_z2, sin_z4,cos_z4,sin_z1,sin_z3,cos_z1,cos_z3;
reg signed [Demo_MSB:0] sin_z5,cos_z5, sin_z6,cos_z6,sin_z7,sin_z8,cos_z7,cos_z8;
reg signed [(Demo_MSB+1)*2-1:0] mult1,mult2;
wire signed [(Demo_MSB+1)*2-1:0] sin_mul,cos_mul;
wire signed [(Demo_MSB+1)*2-1:0] sin_ex_z4,cos_ex_z4;
wire signed [(Demo_MSB+1)*2-1:0] diff_reg;
always @(posedge dcm_clock ) //復調器入力を一旦FFで受ける
input_reg_sin<=modulated_wave_sin;
always @(posedge dcm_clock ) //復調器入力を一旦FFで受ける
input_reg_cos<=modulated_wave_cos;
always @(posedge dcm_clock) begin//ディレイ Z8まであるが、合成されるのは、Z4まで
sin_z1<=input_reg_sin;
sin_z2<=sin_z1;
sin_z3<=sin_z2;
sin_z4<=sin_z3;
sin_z5<=sin_z4;
sin_z6<=sin_z5;
sin_z7<=sin_z6;
sin_z8<=sin_z7;
cos_z1<=input_reg_cos;
cos_z2<=cos_z1;
cos_z3<=cos_z2;
cos_z4<=cos_z3;
cos_z5<=cos_z4;
cos_z6<=cos_z5;
cos_z7<=cos_z6;
cos_z8<=cos_z7;
end
assign sin_ex_z4=sin_z4;//アイパターン検討結果、Z4を選択
assign cos_ex_z4=cos_z4;//アイパターン検討結果、Z4を選択
always @(posedge dcm_clock ) begin
begin
mult1<=input_reg_sin*cos_ex_z4;//符号付乗算器記述
mult2<=input_reg_cos*sin_ex_z4;//符号付乗算器記述
end
end
mysub sub(//Xilinx パイプラインド減算モジュール Coregenで生成
.A(mult1),
.B(mult2),
.Q(diff_reg),
.CLK(dcm_clock)); // synthesis black_box
assign demodulated_wave_final=diff_reg[Demo_MSB+4+2:2];//復調器出力
endmodule
|
一番上が、NRZ波形、filt_outがベッセルフィルタを通した波形です。過渡がとれて、オーバシュートのない綺麗な波形になります。この性質が、狭帯域かつ信号自体の劣化を最小にするという目的に合致しています。
一番下が送信波形ですが、Aliasingのためまともに見えません。
そこで、カーソル間を拡大してみると、sin波になっていることがわかりますが、1%DeviationなのでDataの変化はよくわかりません。
この波形を復調して上のfilt_outに戻す操作がdemodulationです。
(2)Demodulation
Zero-IFのブロック図は、下のようになります。4倍サンプリングすると、周波数変換のsin,cosの係数は、下のようになりますから、実際のところ乗算器は不要になります。
同じ周波数のの掛け算は、その2倍の周波数成分を持ちます。そこで、2倍の周波数成分をLPFで落としてやる必要があります。これは、2次のFIRで十分です。
下図は、そのFIRの特性ですが、サンプリング周波数の1/2においてNullになっていることがわかります。(4倍サンプリングの1/2周波数=キャリアの2倍周波数)
ところが、係数をsin、cosの係数は、2CLOCK毎0なので、これもまた、FIR演算を行う必要はないことがわかります。ここまで計算らしい計算は、必要ありませんでしたが、問題は、その後のI/Q計算、ARCTAN計算です。
それが、今回の課題のポイントです。
上記で、量子化誤差を考えなくて良いRealで書いてみました。
一番下の波形がDemodulateした波形で、期待通りベースバンド波形が再現していることが分かります。PLL復調方式と違いLatencyが非常に小さいところがこの方式の特徴になっています。
(3) アイパターン
ベースバンドの転送レートを倍にするとどうなるでしょうか?ベッセル3dBのカットオフを変えずに、ベースバンドの転送レートを倍の2MBPSにしてみます。
ベースバンド波形は、歪み、遷移時間が小さいところでは、振幅も小さくなります。
この波形をオシロでTriggerをかけて見たとすると下の絵のように見えます。これをアイパターンといいます。
振幅方向の余裕は半分以下になってしまいますが、アイの中央でサンプリングすれば、未だデータの判別は可能です。
アイパターンは、やはりVerilogでプログラムを書いてExcelで処理しました。Verilog2001では、多次元配列も使えるのでテストベンチを書くときは重宝します。(上記ソース参照)
(4)RTL
次は、Demodulatorを実際のH/Wを意識した書き方に直します。量子化誤差、Overflow等を考慮して演算ビット幅を決定します。
その前に、設計仕様をもう少し具体化します。
GFSKとして代表的なものは、Bluetoothです。コンテスト課題のModulationは+-1%と、BluetoothからSpec.をもらい設計仕様として以下の通りまとめました。
No |
項目 |
仕様 |
単位 |
備考 |
1 |
Clock周波数 |
300 |
MHz |
Spartan3 限界? |
2 |
Carrior周波数 |
75 |
MHz |
4x Oversampling |
3 |
Modulation Index |
0.3 |
|
Bluetooth |
4 |
BT |
0.5 |
|
Bluetooth |
5 |
転送Rate |
5 |
Mbps |
75*0.01*2/0.3 |
なお、最終的なClockは、論理合成後に、決定します。Targetは、Starter Kit(-4)です。
=>とりあえず、8ビット乗算器だけで、論理合成すると276MHzになりました。ところが、波形入力用のRAMを記述すると230MHz位に落ちてしまいました。明らかにRAMで律速しています。
しょうがないので実機でのターゲットは、200MHz、としました。
アイパターンは、VGAで出力させる方式としました。VGAは初めてなのですが、R-2RラダーDAコンバート、アナログオシロで撮るよりもスマートです。
VGAは、50MHzを使うみたいですし、Xilinx Starter Kitは50MHzClockなので、4倍CLOCKとすれば、相性がいいのです。VGAのコネクタもついているので、特に半田付けすることもありません。
また一回作っておけば、あとあとアナログオシロの代わりにもなるような気がします。
以上より 実機検証用のTargetは次の通りとします。
No |
項目 |
仕様 |
単位 |
備考 |
1 |
Clock周波数 |
200 |
MHz |
Sartan3 RAMのSpeedより |
2 |
Carrior周波数 |
50 |
MHz |
4x Oversampling |
3 |
Modulation Index |
0.3 |
|
Bluetooth |
4 |
BT |
0.5 |
|
Bluetooth |
5 |
転送Rate |
3.3 |
Mbps |
50*0.01*2/0.3 |
6 |
Demodulator Slice数 |
100以下 |
|
乗算器2個は、専用。Demodulatorは、276MHzで動く能力 |
7 |
RAM |
4x2 |
個 |
Dual Port 入出力及びVGA出力兼用 |
上記パラメータでRTLを記述してみました。Bluetooth Spec.で規定されている波形に近くなりました。
Modulation Index 0.3というのは、+-0.15で、ベースバンド転送レート3.33Mbpsに対して、Peak-Peakで1MHzで、振れることを意味しています。
3.33Mbpsを送るのに3.33MHzは使っていません。このようにGFSKは、狭帯域の通信に適しています。
量子化の影響(8ビット)が、懸念事項だったのですが、案の定、量子化の影響がでています。(下図、真中)
RTLのシステムシミュレーションでは、ビット幅をパラメータ化しておくことで、インスタンス化時に簡単にその影響をシミュレーションすることができます。
この辺は、Hardに近い(Hard そのもの)の記述なので、Matlabよりもある意味便利です。ビット幅を12ビットくらいにすると、もう上のRealの波形と区別できないくらいになるのが確認できました。
ところで、量子化というのは、ノイズを加えたことと同じです。今回の量子化が白色Noiseかどうかはわかりませんが、簡単には、1次のIIRフィルタで逃げることができます。(一番下の波形)
これで、システムとしてのシミュレーションが終わりました。
アルゴリズムに破綻がなかったので、応募してみたいと思います。
Demodulator単体での合成結果です。最初の記述では、100MHz程度でした。
パイプライン化と、演算ビット数の削減によって240MHz程度まできました。合成→システムシミュレーション→..を繰り返し、Reductionによって特性が変化しないことを確認しながら進めます。
目標の100LUT以下は達成できたので、ここでよしとします。
Critical Pathは、16ビット減算部分です。Demodulatorの記述は、約100行です。
=========================================================================
* Final Report *
=========================================================================
Device utilization summary:
---------------------------
Selected Device : 3s200pq208-4
Number of Slices: 72 out of 1920 3%
Number of Slice Flip Flops: 126 out of 3840 3%
Number of 4 input LUTs: 98 out of 3840 2%
Number of bonded IOBs: 21 out of 141 14%
Number of MULT18X18s: 2 out of 12 16%
Number of GCLKs: 1 out of 8 12%
=========================================================================
TIMING REPORT
Clock Information:
------------------
-----------------------------------+------------------------+-------+
Clock Signal | Clock buffer(FF name) | Load |
-----------------------------------+------------------------+-------+
dcm_clock | BUFGP | 144 |
-----------------------------------+------------------------+-------+
Timing Summary:
---------------
Speed Grade: -4
Minimum period: 4.179ns (Maximum Frequency: 239.292MHz)
Minimum input arrival time before clock: 2.373ns
Maximum output required time after clock: 6.172ns
Maximum combinational path delay: No path found
|
=>
DCM を合成してみました。Spec.を見ると結構ジッタが大きいです。真面目に考えると、このジッタでサンプリングをすると位相誤差が無視できないほど大きいという問題があります。
また、最大駆動周波数に、ジッタで失われるはずのタイミングマージン減少が計算に入っていないようですが、いいのでしょうか?
(4)XILINX RTLマッピング
検証方法について、検討したのですが、VGAよりUARTの方が簡単そうです。UARTでDUAL PORT RAM内容を垂れ流しし、PC側でExcel処理することにします。
周辺回路としてDCM,UARTを使う構成がイメージできたので、次のSTEPは、システムシミュレーション記述をXILINX RTLにマッピングすることです。
そのためには、ブロックRAMをROMとして使う必要があります。RAMの初期化データを作成しなくてはいけません。これは、システムシミュレーションからROMのVerilog記述を生成することにします。
また、ROMが記述できると、自律システムとして動きますから、今までの仮想クロックの代わりにDCM200MHz クロックで駆動します。
量子化誤差を考えなくてもよいrealでの記述から、量子化するHardware記述への記述で注意する点は、二つあります。一つは、realからbitに変換する操作での四捨五入です。
Verilogの変換は、C言語と同様切捨てなので、たとえば、2.999であっても2になってしまいます。この場合は、3にした方がよいことはいうまでもありません。
Veritakは、四捨五入function $rintがあるのでそれを使ってreal上で四捨五入(この場合は3.0に変換)した後に整数に変換します。
二つ目は、演算回路は、精度と速度のトレードオフになる場合が多く、後でビット幅を変えたくなる場合もあります。
Verilog2001 になってparameterが強力になっているので、それを駆使してビット幅を可変にしておくと後で楽ができます。
=>UARTをハードで回すとなると、やはり面倒です。PCで受け取ってEXCEL形式にDATAを整理するのも面倒です。JTAGを使えば、簡単にダンプできそうですが、理解している時間的な余裕がありません。
C言語で記述できるCPUがあり、かつStarter Kitに載って70MHz以上で動けば、UART出力時にフォーマット化してだすことも容易です。そんなCPU...ありました。YACCです。
最小で去年のDWM付録に載りますからStarter Kitに載らないはずはありません。
速度的にも、70MHzは、容易でしょう。そこで、安直にYACCのRAM周りの記述をXILINXにポートしてみることにしました。
=>[チームVeritak」として応募することにしました。応募レポートは、応募後に公開します。(2月1日以降)
Xilinx spartan3スタータキット上にC言語で動作するYACC(32ビットMIPST互換CPU)とFM Demodulatorのトップダウン設計及び実装例になると思います。
=>YACCを合成してみました。
Alteraからのポートが必要なのは次の2箇所です。
- RAMの記述方法。特にRAMの初期値を与える方法
- レジスタファイルの記述
RAMの初期値を与える方法は、色々方法があるようですが、COEファイルを生成する方法をとりました。)YACCのツールは、HEXファイルを生成しますが、それにCOEファイルも生成するように追加改造しました。
また、ModulatorのROMファイルは、上のシステムシミュレーション上でCOEファイルを生成するVerilog記述としました。(上記ソース参照
COEファイルが出来たらCoregenでメモリを生成します。このときmifファイルが生成され、Veritakはこれを読みます。合成シンセサイズ用のファイルはまた別のファイルになります。
つまりHDLシミュレーションだけのときは、mifを書き換えてもいいのですが、合成した結果には反映されません。
レジスタファイルにも少し工夫が要ります。3PORTのレジスタファイルが要るのですがAlteraでは、これを3PORTのRAMで合成することができました。Xilinxでは、それはありません。
分散RAMを使えばできるのですが、それでは、リソース消費が大きすぎ、到底載りません。そこで、2ポートのブロックRAMを2つ使う(同じデータを書きます)ことにしました。
勿体ないですが、こうするとFFの消費を抑えることができます。結果90%でFITしました。
これは、予想外に大きく、Demodulatorを載せるとギリギリです。FITしないかもしれません。そこで、この方法は、断念し単純にUART垂れ流し方式としました。
(5)ゲートレベルシミュレーション
合成後のRTLシミュレーションをまず行いました。この段階での問題は、signedの解釈がHDLシミュレータとシンセサイザで異なることです。Xilinxシンセサイザでは、$singedもサポートされていません。
ここでは、詳しく述べませんがsignedとビット幅拡張に関してはHDLシミュレータとシンセサイザの解釈が一致しない場合が多々あるので注意が必要です。
今回は、問題のある箇所をVerilog2001 signed から従来と同じ書き方(signedに依存しない書き方)に変更して一致させました。
Coregen Libraryを使ってシミュレーションを行いましたが、この辺は、論理合成しゲートレベルのシミュレーションをしないと問題の有無を確認できません。
ゲートレベルシミュレーションは、「遅延シミュレーション」の他に論理合成とHDLの一致検証としても意味を持ちます。
一番上の波形は、50MHzの入力波形です。DCMがLOCKEDすると、4xCLOCKのDCM生成波形(5ns=200MHz)が出力されていることが分かります。その下は、8ビットROMの波形です。
4倍サンプリングの為現波形のsin波を想像するのは、難しいかもしれません。これが、Demodulatorの入力になります。
ちなみにその下の波形は、DCMの内部信号を出したものです。180度、270度等の信号が生成されているのが分かります。
このときのDemodulator出力波形です。転送レートは、3.3MBPSですから、最小ピークは、300nsになっています。
ゲートシミュレーションについてXILINXでは、MAPとPOST ROUTEというシミュレーションファイルが生成されます。MAPでは、Placeだけの情報のみらしく、ほぼ上の合成速度でシミュレーションができました。
しかし、POST ROUTEでVeritakゲートシミュレーションを行ってみると、Setup/Hold エラーのオンパレードで200MHzでは動きませんでした。
Systhesize Reportでは、240MHz出ていたのにPOST ROUTE TIMING REPORTを見ると、確かに200MHzより落ちています。150Mhzしかでていません。20%劣化なら仕方ないような気もしますが、50%近くなると詐欺に近い。。。。。
とりあえず、現在200MHzでは動かないので、150MHzでPostLayoutGateシミュレーションを行ってみました。下の上の波形がそうですがカーソルを拡大してみるとノイズのようなヒゲがでています。(左下)
さらにヒゲの部分を拡大してみると複数ビットのばたつきであることがわかります。この信号は、12ビット幅のREG出力です。各ビットのピン出力の遅延時間が異なるためにこのように見えます。
(右下波形で、最小CLKFXより細かくバタついている様子がお分かりでしょう。ちなみに遅延シミュレーションなので、全波形Saveではメモリ消費も激しいです。下の波形で、155.1MBも食っています。)
とりあえず、どうするか考え中です。CDが150KB/Secなので、CD音質を転送しようと考えると1.2Mbpsあれば、よいですが、パケット化を考えると50%程度に低下するので、3Mbpsは欲しい。。。。
=>
結局、200MHzも無理という結論に達しました。何の論理がはいらないFF間の接続だけで、3.xns食っています。乗算器で2nsはくいますからどう頑張っても200MHzは無理だろうという結論です。
(フローアプランをちゃんとやれば、入るのかもしれませんが。。)
そこで、DSMを使ってキャリア周波数のCLOCKで動く仕様に変更することにします。Alteraでもそうでしたが、120MHzを超えたあたりから配線遅延が支配的になってしまって性能がだしづらくなります。(もぐらたたき状態)
そこで、本来の目的に立ち返り、拘束条件下で、最速ベースバンドを達成するという目的を思い出しました。その為には、4xクロックを1xクロックにしてしまえばいいことになります。
位相が4倍速くまわるので、パイプライン化でごまかせない部分がでてきますが、それでも100MHz程度はいくでしょう。6.7Mbps位は行くと思います。パイプラインが使えないので、LUT数は、減少します。
No |
項目 |
仕様 |
単位 |
備考 |
1 |
Clock周波数 |
T.B.D. |
MHz |
Sartan3 RAMのSpeedより |
2 |
Carrior周波数 |
T.B.D. |
MHz |
1x Oversampling |
3 |
Modulation Index |
0.3 |
|
Bluetooth |
4 |
BT |
0.5 |
|
Bluetooth |
5 |
転送Rate |
T.B.D. |
Mbps |
T.B.D.*0.01*2/0.3 |
6 |
Demodulator Slice数 |
80以下 |
|
乗算器2個は、専用。 |
7 |
RAM |
T.B.D. |
個 |
Dual Port 入出力兼用 |
=>
どうにも駆動周波数があがりません。多分、積和演算を1CLOCKで処理しようとすると、130MHz位が限界なのではないでしょうか?
ということで、IIRも止めにしてデシメーションだけで行くことにしました。これで、150MHz狙いで、10Mbpsになります。10Mbpsというのは、課題提示の1000倍なので、受け狙いとしては、いいかもしれません。
普通は、設計が進むにつれて、LUT数が上がるのに、今回は、下がっていくという不思議な事例です。
締め切りも近いので、ハードをFIXさせて、実機で動かしてみることにしましょう。
=>その前に周辺TEST回路を書かなくてはいけません。コンテスト課題は、最終的には、70行の答案になってしまったのですが、周辺回路の記述は、その数十倍です。かけた時間と反比例しています。
(仕事の量が、ソース行数で推し量れない例ですね。
遅延シミュレーションでは、150MHzの波形が、観測可能ですが、実デバイス上では、(高度なロジアナを持ち合わせていないので)、出力DataをDUAL PORT RAMに保存しておいて、別CLOCK(50MHz)でUARTに出力します。
ここでは、Verilog2001、@* の記述が参考になるかもしれません。Sensibity Listをいちいち書かなくてよいので、組み合わせ回路でラッチが合成されてしまうという、誰でも一度は犯しただろうバグを回避することができます。
RTLテストするときは、UARTのブロックだけでテストします。分解能1psの世界とμsecの世界を一緒にテストしようとしても時間の浪費です。
上の回路は、1psのジッタがあると、波形上で、ノイズとして観測できますが、下の回路は、数%クロック周期がずれていたところで、問題なく動くでしょう。そういう回路感覚でテストベンチを記述することも重要かもしれません。
UARTのテストです。波形を見ていて、「動いているみたいだが、正しいかどうかわからない」ときがあります。(シリアルを人間UARTするのはつらい。)こんなときは、接続されるポートをモデリングしてしまいます。
今回は、READのUARTを接続してコンソールにメッセージをだすとよいでしょう。波形は、ステートマシンの状態遷移とボーレートの確認に使います。
//Jan20.2005 115.Kbps に調整
//Jan.19.2005
//uart control 仕様
// 50MHz Clockで動く
// 12bit RAM をUARTでダンプする
// 50MHz sync_reset を出力
// ダンプは ASYNC_RESETを抜けたら、2CLOCK WAITしした後 RAM を上位4BITからアクセス
// HEX で出力 ABCLF LF=0Aで4DIGIT単位に出力
// 4KADDRESS は、ラップするとき、0Aを出す
// => 50M CLOCK
// => ASYNC_RESET
// => RAM_ADDRESS[11:0]
// <= RAM_DATA [11:0]
// => TXD
//
//
//
module uart_ctrl( input ASYNC_RESET,
input clk_50M,
input wire [11:0] ram_data,
output reg [11:0] ram_address,
output TXD);
parameter [7:0] CR=8'h0d;
reg sync_reset1,sync_reset2,sync_reset;
reg [3:0] state;
wire busy;
//monitor address
always @* $display("UART RAM_ADDRESS=%h",ram_address);
//combinatial logics
reg write_request;
reg [7:0] set_data;
always @(posedge clk_50M, posedge ASYNC_RESET) begin
if (ASYNC_RESET) sync_reset1<=1;
else sync_reset1 <=0;
end
always @(posedge clk_50M) sync_reset2<=sync_reset1;
always @(posedge clk_50M) sync_reset <=sync_reset2;
localparam idle_state=4'b0000,
state1=4'b0001,
uart_set_msb=4'b0010,
waiting_msb_write_done=4'b0011,
uart_set_middle=4'b0100,
waiting_middle_write_done=4'b0101,
uart_set_lsb=4'b0110,
waiting_lsb_write_done=4'b0111,
uart_set_lf=4'b1000,
address_check_state=4'b1001,
waiting_lf_write_done=4'b1010,
address_inc_state=4'b1011,
state12=4'b1100;
//state machine
always @(posedge clk_50M) begin
if (sync_reset) state <=0;
else case (state)
idle_state: state<=state1;
state1: if (busy) ;//wait
else state <=uart_set_msb;
uart_set_msb: state <=waiting_msb_write_done;
waiting_msb_write_done: if (busy);//wait
else state <=uart_set_middle;
uart_set_middle: state <=waiting_middle_write_done;
waiting_middle_write_done: if (busy);//wait
else state <=uart_set_lsb;
uart_set_lsb: state <=waiting_lsb_write_done;
waiting_lsb_write_done: if (busy);//wait
else state <=uart_set_lf;
uart_set_lf: state <=address_check_state;
address_check_state: state<=waiting_lf_write_done; //if (address_last) uart_set
waiting_lf_write_done: if (busy);//wait
else state <=address_inc_state;
address_inc_state: state<=idle_state;
default : state <=idle_state;
endcase
end
//ram address
always @(posedge clk_50M) begin
if (sync_reset) ram_address<=0;
else if (state==address_inc_state) ram_address <=ram_address+1;
end
//uart
uart_write uw( .sync_reset(sync_reset),
.clk(clk_50M),
.txd(TXD),
.data_in(set_data) ,
.write_request(write_request),
.write_done(),
.write_busy(busy));
//combinational logic
//write_request
always @* begin
case (state)
uart_set_msb,uart_set_middle,uart_set_lsb,uart_set_lf: write_request=1;//uart set
address_check_state: if (ram_address==12'hfff) write_request=1;//wrap address
else write_request=0;
default:write_request=0;
endcase
end
//set_data
always @* begin
case (state)
uart_set_msb: set_data=num_to_ascii(ram_data[ 11:8]);
uart_set_middle:set_data=num_to_ascii(ram_data[ 7:4]);
uart_set_lsb: set_data=num_to_ascii(ram_data[ 3:0]);
address_check_state:set_data=CR;//Jan.24.2005 wrap address
uart_set_lf: set_data=CR;//Jan.24.2005
default :set_data=8'hxx;
endcase
end
//digit to ascii code
function [7:0] num_to_ascii (input [3:0] num);
begin
if (num<=9) num_to_ascii=num+8'h30;
else num_to_ascii=num+55;// 41hex =>A decimal65=A a=>10
end
endfunction
endmodule
//YACC から持ってきた。
module uart_write( sync_reset, clk, txd, data_in , write_request,write_done,write_busy);
input sync_reset,clk;
input [7:0] data_in;
input write_request;
output txd,write_done;
output write_busy;
parameter MAX_DEPTH=7;
parameter ADDRESS_MSB=2;
reg [7:0] queue[0:MAX_DEPTH];
reg [ADDRESS_MSB:0] wpointer,rpointer;
reg [ADDRESS_MSB+1:0] queue_counter;
wire queue_full;
wire queing, read_request;
wire [7:0] queue_data;
reg read_request_ff;
reg [8:0] clk_ctr;
reg [2:0] bit_ctr;
reg [2:0] ua_state;
reg [7:0] tx_sr;
reg write_done_n;
reg txd;
wire clk_ctr_equ15, clk_ctr_equ31, bit_ctr_equ7,
clk_ctr_enable_state, bit_ctr_enable_state ;
wire tx_state;
always @ (posedge clk) begin
if (sync_reset) begin
wpointer <=0;
end else if (write_request) begin
queue[wpointer]<=data_in;
wpointer <=wpointer+1;
end
end
always @ (posedge clk) begin
if (sync_reset) read_request_ff<=1'b0;
else read_request_ff<=read_request;
end
always @ (posedge clk) begin
if (sync_reset) begin
rpointer <=0;
end else if (read_request_ff) begin
rpointer <=rpointer+1;
end
end
always @ (posedge clk) begin
if (sync_reset) begin
queue_counter <=000;
end else if (!read_request_ff && write_request) begin
queue_counter <=queue_counter+1;
end else if ( read_request_ff && !write_request) begin
queue_counter <=queue_counter-1;
end
end
assign queue_full = (queue_counter == MAX_DEPTH+1);
assign queing= queue_counter !=000;
assign read_request = queing && ua_state==3'b000;
assign queue_data =queue[rpointer];
assign write_done=ua_state==3'b101;
assign write_busy=queue_full;
always @(posedge clk ) begin
if (sync_reset)
clk_ctr <= 0;
else if (clk_ctr_enable_state && clk_ctr_equ31) clk_ctr<=0;
else if (clk_ctr_enable_state) clk_ctr <= clk_ctr + 1;
else clk_ctr <= 0;
end
assign clk_ctr_equ15 = clk_ctr== 216; //orig 206
assign clk_ctr_equ31 = clk_ctr== 433;//413
always @(posedge clk) begin
if (sync_reset)
bit_ctr <= 0;
else if (bit_ctr_enable_state) begin
if (clk_ctr_equ15)
bit_ctr <= bit_ctr + 1;
end
else
bit_ctr <= 0;
end
assign bit_ctr_equ7 = (bit_ctr==7);
assign clk_ctr_enable_state = bit_ctr_enable_state || ua_state==3'b001 || ua_state==3'b100 ;
assign bit_ctr_enable_state = ua_state==3'b010 || ua_state==3'b011;
always @(posedge clk ) begin
if (sync_reset) ua_state <= 3'b000;
else begin
case (ua_state)
3'b000: if (queing) ua_state <= 3'b001;
3'b001: if ( clk_ctr_equ15) ua_state <= 3'b010;
3'b010: if (bit_ctr_equ7 & clk_ctr_equ15) ua_state <= 3'b011;
3'b011: if (clk_ctr_equ15) ua_state <= 3'b100;
3'b100: if (clk_ctr_equ15) ua_state <= 3'b101;
3'b101: ua_state <= 3'h0;
default: ua_state <= 3'h0;
endcase
end
end
always @(posedge clk ) begin
if (sync_reset) tx_sr<=0;
else if (read_request_ff) tx_sr <= queue_data[7:0];
else if (tx_state ) tx_sr <= {1'b0, tx_sr[7:1]};
end
assign tx_state=( ua_state==3'h2 || ua_state==3'h3) && clk_ctr_equ15;
always @(posedge clk ) begin
if (sync_reset) txd <=1'b1;
else if (sync_reset) txd<=1'b1;
else if (ua_state==3'h0) txd<=1'b1;
else if (ua_state==3'h1 && clk_ctr_equ15) txd<=1'b0;
else if (ua_state==3'h2 && clk_ctr_equ15) txd<=tx_sr[0];
else if (ua_state==3'h3 && clk_ctr_equ15) txd<=1'b1;
end
endmodule
//以下はUART専用テストベンチ
//`define UART_CTRL_TEST //UART RTLテスト時だけ、その他はコメントアウトのこと
//UART RTL テスト時は、単独ファイルで可
`ifdef UART_CTRL_TEST
module uart_ctrl_test;
parameter CR=8'h0d;
reg ASYNC_RESET=0;
reg clk_50M=0;
reg [11:0] ram_data=0;
wire [11:0] ram_address;
wire TXD;
wire RXD;
wire [7:0] buffer_reg;
wire int_req;
always #10 clk_50M =~clk_50M;
always @* ram_data=ram_address;
initial begin
#1 ASYNC_RESET=1;
#105 ASYNC_RESET=0;
$display("UART WRITE PORT Test Using UART READ PORT.");
end
uart_ctrl uart_write_port( ASYNC_RESET,
clk_50M,
ram_data,
ram_address,
TXD);
reg sync_reset;
always @(posedge clk_50M ,posedge ASYNC_RESET )
if (ASYNC_RESET) sync_reset<=1'b1;
else sync_reset<=1'b0;
uart_read uart_read_port( .sync_reset(sync_reset), .clk(clk_50M), .rxd(TXD),.buffer_reg(buffer_reg), .int_req(int_req));
always @(posedge int_req) begin
begin :local
reg [7:0] local_mem [0:3];
integer i=0;
if (i>=4) $stop;//Assert(0);
if (buffer_reg==CR) begin :local2 //pop stack
integer j;
j=0;
while( j < i) begin
$write( "%c",local_mem[j]);
j=j+1;
end
$write(" : time=%t\n",$time);
i=0;//clear stack
end else begin//push stack
local_mem[i]=buffer_reg;
i=i+1;
end
end
end
endmodule
`endif
module uart_read( sync_reset, clk, rxd,buffer_reg, int_req);
input sync_reset;
input clk, rxd;
output [7:0] buffer_reg;
output int_req;
//________|-|______int_req (This module,, posedge interrupt)
//
//Spec. Upper module must service within 115.2Kbpsx8bit time. Maybe enough time..hom.
//
//No error handling (overrun ) is supported.
localparam COUNTER_VALUE1 = 216;//207
localparam COUNTER_VALUE2 =COUNTER_VALUE1*2+1;//415
localparam COUNTER_VALUE3 =COUNTER_VALUE1+3;//210
reg rxq1;
reg [8:0] clk_ctr;
reg [2:0] bit_ctr;
reg [2:0] ua_state;
reg [7:0] rx_sr; //.,tx_sr;
reg int_req;
reg [7:0] buffer_reg;
wire clk_ctr_equ15, clk_ctr_equ31, bit_ctr_equ7,
clk_ctr_enable_state, bit_ctr_enable_state ;
wire clk_ctr_equ0;
//sync_reset
//synchronization
always @(posedge clk ) begin
rxq1 <=rxd ;
end
// 7bit counter
always @(posedge clk ) begin
if (sync_reset)
clk_ctr <= 0;
else if (clk_ctr_enable_state && clk_ctr_equ31) clk_ctr<=0;
else if (clk_ctr_enable_state) clk_ctr <= clk_ctr + 1;
else clk_ctr <= 0;
end
// When clock is 24MHz ,followings should be set Do not forget to change simulation file too.
assign clk_ctr_equ15 = (clk_ctr==COUNTER_VALUE1) ; // 416/2-1 Feb.9
assign clk_ctr_equ31 = (clk_ctr==COUNTER_VALUE2) ; // 416-1 Feb.9
assign clk_ctr_equ0= (clk_ctr==COUNTER_VALUE3); // for write strobe Feb.9
// 3bit counter
always @(posedge clk) begin
if (sync_reset)
bit_ctr <= 0;
else if (bit_ctr_enable_state) begin
if (clk_ctr_equ15)
bit_ctr <= bit_ctr + 1;
end
else
bit_ctr <= 0;
end
assign bit_ctr_equ7 = (bit_ctr==7);
assign clk_ctr_enable_state = ua_state !=3'b000 && ua_state<=3'b011;
assign bit_ctr_enable_state = ua_state==3'h2;
//
always @(posedge clk ) begin
if (sync_reset) ua_state <= 3'h0;
else begin
case (ua_state)
3'h0: if (rxq1==0) ua_state <= 3'h1; // if rxd==0 then goto next state and enable clock // start bit search
3'h1: if (clk_ctr_equ15) ua_state <= 3'h2; // start bit receive
3'h2: if (bit_ctr_equ7 & clk_ctr_equ15) ua_state <= 3'h3;
3'h3: if (clk_ctr_equ15) ua_state <=3'h4; // stop bit receive
3'h4: ua_state <= 3'b000;
default: ua_state <= 3'b000;
endcase
end
end
//reg_we
always @(posedge clk ) begin
if (sync_reset) buffer_reg<=8'h00;
else if (ua_state==3'h3 && clk_ctr_equ0) buffer_reg<=rx_sr;
end
//int_req
always @(posedge clk ) begin
if (sync_reset) int_req<=1'b0;
// else if (ua_state==3'h3 && clk_ctr_equ15) int_req<=1'b1;
else if (ua_state==3'h4 ) int_req<=1'b1; //Feb.1 After buffer_reg_set
else int_req<=1'b0;
end
// rx shift reg.
always @(posedge clk ) begin
if (sync_reset) rx_sr <= 0;
else if (clk_ctr_equ15) rx_sr <= {rxq1, rx_sr[7:1]};
end
endmodule
|
=> ようやく、最終回路で150MHzを超えることができ遅延シミュレーションも通りました。UARTは、50MHz CLOCKなので楽勝です。後は火をいれるだけです。火を入れる瞬間はいつもワクワクします。
=>火をいれてみました。
ボーレート115.2Kbpsで接続すると、設計通り、UARTの垂れ流し状態になっています。
これを、テキストファイルに落としてVerilogで12ビットの符号付で読めば、シミュレーション時の波形が再現するという訳です。
XilinxのStarter KitのUCFファイル等は、佐藤さんのファイルを参考にさせていただきました。
$readmemhで、上のテキストファイルを読み込みます。UARTは、垂れ流しなので、読み込んだ波形位置(時間)をRTL波形と同じになるように調整します。視覚的には、同じように見えるので多分OKです。
正確には、下のように、RTLシミュレーション波形(demodulated_output)と読み込んだ波形(UARTが受け取った結果:uart_output)と波形比較コマンドで比較して、相違がないことを確認しておきます。
以上で、RTLシミュレーションと実機との整合検証が完了しました。
課題に対する最終合成結果です。(配置配線前です。)
リファレンス回路(parity.vhdl)の合成結果です。(配置配線前です。)
最終的な検証回路での緒元です。
No |
項目 |
仕様 |
単位 |
備考 |
1 |
Clock周波数 |
50 |
MHz |
Sartan3 RAMのSpeedより |
2 |
Carrior周波数 |
150 |
MHz |
1x Oversampling |
3 |
Modulation Index |
0.3 |
|
Bluetooth |
4 |
BT |
0.5 |
|
Bluetooth |
5 |
情報転送Rate |
10 |
Mbps |
150*0.01*2/0.3 |
6 |
Demodulator Slice数 |
25 |
|
乗算器2個は、専用。 |
これで、終わりです。12月半ばから構想を始めて、設計、製作と行って、ほぼ休日は、この作業でした。見積もり時間の3倍位かかってしまいました。
提出したレポートは、割と綺麗にまとまっているように見えますが、実際は、上のように紆余曲折しながらの設計です。
ともあれ、思いついたアイデアを視覚的に検証することができ、結果がでるまで延々とコーディングするストレスがなく設計自体を楽しむことができました。(課題から大きく道をそれてしまったようなので、入賞は難しいと思いますが。)
提出したレポートです。
=>残念ながら、入賞は、できませんでした。なお、本アルゴリズムは、2値に限ったものではなく、「高速FSKに特化した..」ものでもありません。
アナログFMの汎用的なアルゴリズムである(つまり、150MHzのアナログFM信号がそのままで復調可能です。)ことも補足しておきます。オープンコアでもFMのプロジェクトがあるので、そのうち提案してみるかも。
それにしてもFMという古典的なテーマでありながら、いろいろな設計があるものですね。公開されていない他のチームの設計も是非見てみたいと思いました。
演算 除算/対数/平方根のH/Wアルゴリズム(終了)
OpencoresにはIEEE754適合のFPUソースがあります。しかし、テストベンチのデータを展開すると500MB
にもなってしまうので、上ではUpしませんでした。
Opencoresでなくても、小規模な演算ソースを公開されている方を見つけました。
VHDLで書いておられるので、トランスレータを使ってVerilogにしてみたいと思います。(Version1.47では、Single VHDLファイルならDrag&Dropでトランスレートします。)
掲載許可をいただきましたが、テストベンチを消失してしまったそうです。そこで、Verilogによるテストベンチを書いてみることにしました。以下は、
- 原作者の方のVHDLのソース
- トランスレータを通した後のVerilogソース
- Verilog テストベンチ
ですが、アルゴリズムについては、原作者のサイトで解説されています。
注意:なお、フリーハードウェアですが、著作権は原作者にあります。サポートはありませんし特許が成立している可能性もあります。使う方の自己責任でどうぞ。
1)平方根
36bitから18ビットの根を出力します。
テストベンチは、手書きで書きました。網羅的にチェックしました。OKです。
こんな感じです。
オリジナルのソースコードとトランスレータ出力です。組み合わせ回路のみで記述されています。実際的には、パイプライン化が必要になるでしょう。
------------------------------------------------------------------------
-- File SQRT36.vhd --
-- Entity SQRT36 --
-- rev date coded contents --
-- 001 98/06/10 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all;
use IEEE.std_logic_arith.all;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity SQRT36 is
port(
X : in std_logic_vector(35 downto 0) ; -- Input(36bit)
Z : out std_logic_vector(17 downto 0) -- Output(18bit)
);
end SQRT36 ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of SQRT36 is
begin
--------------------------------
-- Square Root
--------------------------------
SQRT_LOOP : process( X )
variable R : std_logic_vector(35 downto 0); -- Remain
variable S : std_logic_vector(17 downto 0); -- Result
variable T : std_logic_vector(35 downto 0); -- Calclate Value
begin
-- Initialize value
R := X ;
-- Calculate MSB(bit 17)
if( R(35 downto 34) >= "01" ) then
S(17) := '1' ;
R(35 downto 34) := R(35 downto 34) - "01" ;
else
S(17) := '0' ;
R(35 downto 34) := R(35 downto 34) ;
end if;
-- Calculate 2nd bit(bit 16)
T(35 downto 32) := '0' & S(17) & "01" ;
if( R(35 downto 32) >= T(35 downto 32) ) then
S(16) := '1' ;
R(35 downto 32) := R(35 downto 32) - T(35 downto 32) ;
else
S(16) := '0' ;
end if;
-- Calculate 3rd bit(bit 15)
T(35 downto 30) := '0' & T(35 downto 34) & S(16) & "01" ;
if( R(35 downto 30) >= T(35 downto 30) ) then
S(15) := '1' ;
R(35 downto 30) := R(35 downto 30) - T(35 downto 30) ;
else
S(15) := '0' ;
end if;
-- Calculate 4th bit(bit 14)
T(35 downto 28) := '0' & T(35 downto 32) & S(15) & "01" ;
if( R(35 downto 28) >= T(35 downto 28) ) then
S(14) := '1' ;
R(35 downto 28) := R(35 downto 28) - T(35 downto 28) ;
else
S(14) := '0' ;
end if;
-- Calculate bit 13
T(35 downto 26) := '0' & T(35 downto 30) & S(14) & "01" ;
if( R(35 downto 26) >= T(35 downto 26) ) then
S(13) := '1' ;
R(35 downto 26) := R(35 downto 26) - T(35 downto 26) ;
else
S(13) := '0' ;
end if;
-- Calculate bit 12
T(35 downto 24) := '0' & T(35 downto 28) & S(13) & "01" ;
if( R(35 downto 24) >= T(35 downto 24) ) then
S(12) := '1' ;
R(35 downto 24) := R(35 downto 24) - T(35 downto 24) ;
else
S(12) := '0' ;
end if;
-- Calculate bit 11
T(35 downto 22) := '0' & T(35 downto 26) & S(12) & "01" ;
if( R(35 downto 22) >= T(35 downto 22) ) then
S(11) := '1' ;
R(35 downto 22) := R(35 downto 22) - T(35 downto 22) ;
else
S(11) := '0' ;
end if;
-- Calculate bit 10
T(35 downto 20) := '0' & T(35 downto 24) & S(11) & "01" ;
if( R(35 downto 20) >= T(35 downto 20) ) then
S(10) := '1' ;
R(35 downto 20) := R(35 downto 20) - T(35 downto 20) ;
else
S(10) := '0' ;
end if;
-- Calculate bit 9
T(35 downto 18) := '0' & T(35 downto 22) & S(10) & "01" ;
if( R(35 downto 18) >= T(35 downto 18) ) then
S(9) := '1' ;
R(35 downto 18) := R(35 downto 18) - T(35 downto 18) ;
else
S(9) := '0' ;
end if;
-- Calculate bit 8
T(35 downto 16) := '0' & T(35 downto 20) & S(9) & "01" ;
if( R(35 downto 16) >= T(35 downto 16) ) then
S(8) := '1' ;
R(35 downto 16) := R(35 downto 16) - T(35 downto 16) ;
else
S(8) := '0' ;
end if;
-- Calculate bit 7
T(35 downto 14) := '0' & T(35 downto 18) & S(8) & "01" ;
if( R(35 downto 14) >= T(35 downto 14) ) then
S(7) := '1' ;
R(35 downto 14) := R(35 downto 14) - T(35 downto 14) ;
else
S(7) := '0' ;
end if;
-- Calculate bit 6
T(35 downto 12) := '0' & T(35 downto 16) & S(7) & "01" ;
if( R(35 downto 12) >= T(35 downto 12) ) then
S(6) := '1' ;
R(35 downto 12) := R(35 downto 12) - T(35 downto 12) ;
else
S(6) := '0' ;
end if;
-- Calculate bit 5
T(35 downto 10) := '0' & T(35 downto 14) & S(6) & "01" ;
if( R(35 downto 10) >= T(35 downto 10) ) then
S(5) := '1' ;
R(35 downto 10) := R(35 downto 10) - T(35 downto 10) ;
else
S(5) := '0' ;
end if;
-- Calculate bit 4
T(35 downto 8) := '0' & T(35 downto 12) & S(5) & "01" ;
if( R(35 downto 8) >= T(35 downto 8) ) then
S(4) := '1' ;
R(35 downto 8) := R(35 downto 8) - T(35 downto 8) ;
else
S(4) := '0' ;
end if;
-- Calculate bit 3
T(35 downto 6) := '0' & T(35 downto 10) & S(4) & "01" ;
if( R(35 downto 6) >= T(35 downto 6) ) then
S(3) := '1' ;
R(35 downto 6) := R(35 downto 6) - T(35 downto 6) ;
else
S(3) := '0' ;
end if;
-- Calculate bit 2
T(35 downto 4) := '0' & T(35 downto 8) & S(3) & "01" ;
if( R(35 downto 4) >= T(35 downto 4) ) then
S(2) := '1' ;
R(35 downto 4) := R(35 downto 4) - T(35 downto 4) ;
else
S(2) := '0' ;
end if;
-- Calculate bit 1
T(35 downto 2) := '0' & T(35 downto 6) & S(2) & "01" ;
if( R(35 downto 2) >= T(35 downto 2) ) then
S(1) := '1' ;
R(35 downto 2) := R(35 downto 2) - T(35 downto 2) ;
else
S(1) := '0' ;
end if;
-- Calculate bit 0
T(35 downto 0) := '0' & T(35 downto 4) & S(1) & "01" ;
if( R(35 downto 0) >= T(35 downto 0) ) then
S(0) := '1' ;
R(35 downto 0) := R(35 downto 0) - T(35 downto 0) ;
else
S(0) := '0' ;
end if;
-- Result
Z <= S ;
end process ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// File SQRT36.vhd --
// Entity SQRT36 --
// rev date coded contents --
// 001 98/06/10 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module sqrt36 ( x, z );
input [35:0] x ;
output [17:0] z ;
reg [35:0] sqrt_loop__r;
reg [17:0] sqrt_loop__s;
reg [35:0] sqrt_loop__t;
reg [17:0] z;
always @ (x ) begin
sqrt_loop__r = x;
if ((sqrt_loop__r[35:34] >= 2'b01))
begin
sqrt_loop__s[17] = 1'b1;
sqrt_loop__r[35:34] = (sqrt_loop__r[35:34] - 2'b01);
end
else
begin
sqrt_loop__s[17] = 1'b0;
sqrt_loop__r[35:34] = sqrt_loop__r[35:34];
end
sqrt_loop__t[35:32] = {{1'b0,sqrt_loop__s[17]},2'b01};
if ((sqrt_loop__r[35:32] >= sqrt_loop__t[35:32]))
begin
sqrt_loop__s[16] = 1'b1;
sqrt_loop__r[35:32] = (sqrt_loop__r[35:32] - sqrt_loop__t[35:32]);
end
else
sqrt_loop__s[16] = 1'b0;
sqrt_loop__t[35:30] = {{{1'b0,sqrt_loop__t[35:34]},sqrt_loop__s[16]},2'b01};
if ((sqrt_loop__r[35:30] >= sqrt_loop__t[35:30]))
begin
sqrt_loop__s[15] = 1'b1;
sqrt_loop__r[35:30] = (sqrt_loop__r[35:30] - sqrt_loop__t[35:30]);
end
else
sqrt_loop__s[15] = 1'b0;
sqrt_loop__t[35:28] = {{{1'b0,sqrt_loop__t[35:32]},sqrt_loop__s[15]},2'b01};
if ((sqrt_loop__r[35:28] >= sqrt_loop__t[35:28]))
begin
sqrt_loop__s[14] = 1'b1;
sqrt_loop__r[35:28] = (sqrt_loop__r[35:28] - sqrt_loop__t[35:28]);
end
else
sqrt_loop__s[14] = 1'b0;
sqrt_loop__t[35:26] = {{{1'b0,sqrt_loop__t[35:30]},sqrt_loop__s[14]},2'b01};
if ((sqrt_loop__r[35:26] >= sqrt_loop__t[35:26]))
begin
sqrt_loop__s[13] = 1'b1;
sqrt_loop__r[35:26] = (sqrt_loop__r[35:26] - sqrt_loop__t[35:26]);
end
else
sqrt_loop__s[13] = 1'b0;
sqrt_loop__t[35:24] = {{{1'b0,sqrt_loop__t[35:28]},sqrt_loop__s[13]},2'b01};
if ((sqrt_loop__r[35:24] >= sqrt_loop__t[35:24]))
begin
sqrt_loop__s[12] = 1'b1;
sqrt_loop__r[35:24] = (sqrt_loop__r[35:24] - sqrt_loop__t[35:24]);
end
else
sqrt_loop__s[12] = 1'b0;
sqrt_loop__t[35:22] = {{{1'b0,sqrt_loop__t[35:26]},sqrt_loop__s[12]},2'b01};
if ((sqrt_loop__r[35:22] >= sqrt_loop__t[35:22]))
begin
sqrt_loop__s[11] = 1'b1;
sqrt_loop__r[35:22] = (sqrt_loop__r[35:22] - sqrt_loop__t[35:22]);
end
else
sqrt_loop__s[11] = 1'b0;
sqrt_loop__t[35:20] = {{{1'b0,sqrt_loop__t[35:24]},sqrt_loop__s[11]},2'b01};
if ((sqrt_loop__r[35:20] >= sqrt_loop__t[35:20]))
begin
sqrt_loop__s[10] = 1'b1;
sqrt_loop__r[35:20] = (sqrt_loop__r[35:20] - sqrt_loop__t[35:20]);
end
else
sqrt_loop__s[10] = 1'b0;
sqrt_loop__t[35:18] = {{{1'b0,sqrt_loop__t[35:22]},sqrt_loop__s[10]},2'b01};
if ((sqrt_loop__r[35:18] >= sqrt_loop__t[35:18]))
begin
sqrt_loop__s[9] = 1'b1;
sqrt_loop__r[35:18] = (sqrt_loop__r[35:18] - sqrt_loop__t[35:18]);
end
else
sqrt_loop__s[9] = 1'b0;
sqrt_loop__t[35:16] = {{{1'b0,sqrt_loop__t[35:20]},sqrt_loop__s[9]},2'b01};
if ((sqrt_loop__r[35:16] >= sqrt_loop__t[35:16]))
begin
sqrt_loop__s[8] = 1'b1;
sqrt_loop__r[35:16] = (sqrt_loop__r[35:16] - sqrt_loop__t[35:16]);
end
else
sqrt_loop__s[8] = 1'b0;
sqrt_loop__t[35:14] = {{{1'b0,sqrt_loop__t[35:18]},sqrt_loop__s[8]},2'b01};
if ((sqrt_loop__r[35:14] >= sqrt_loop__t[35:14]))
begin
sqrt_loop__s[7] = 1'b1;
sqrt_loop__r[35:14] = (sqrt_loop__r[35:14] - sqrt_loop__t[35:14]);
end
else
sqrt_loop__s[7] = 1'b0;
sqrt_loop__t[35:12] = {{{1'b0,sqrt_loop__t[35:16]},sqrt_loop__s[7]},2'b01};
if ((sqrt_loop__r[35:12] >= sqrt_loop__t[35:12]))
begin
sqrt_loop__s[6] = 1'b1;
sqrt_loop__r[35:12] = (sqrt_loop__r[35:12] - sqrt_loop__t[35:12]);
end
else
sqrt_loop__s[6] = 1'b0;
sqrt_loop__t[35:10] = {{{1'b0,sqrt_loop__t[35:14]},sqrt_loop__s[6]},2'b01};
if ((sqrt_loop__r[35:10] >= sqrt_loop__t[35:10]))
begin
sqrt_loop__s[5] = 1'b1;
sqrt_loop__r[35:10] = (sqrt_loop__r[35:10] - sqrt_loop__t[35:10]);
end
else
sqrt_loop__s[5] = 1'b0;
sqrt_loop__t[35:8] = {{{1'b0,sqrt_loop__t[35:12]},sqrt_loop__s[5]},2'b01};
if ((sqrt_loop__r[35:8] >= sqrt_loop__t[35:8]))
begin
sqrt_loop__s[4] = 1'b1;
sqrt_loop__r[35:8] = (sqrt_loop__r[35:8] - sqrt_loop__t[35:8]);
end
else
sqrt_loop__s[4] = 1'b0;
sqrt_loop__t[35:6] = {{{1'b0,sqrt_loop__t[35:10]},sqrt_loop__s[4]},2'b01};
if ((sqrt_loop__r[35:6] >= sqrt_loop__t[35:6]))
begin
sqrt_loop__s[3] = 1'b1;
sqrt_loop__r[35:6] = (sqrt_loop__r[35:6] - sqrt_loop__t[35:6]);
end
else
sqrt_loop__s[3] = 1'b0;
sqrt_loop__t[35:4] = {{{1'b0,sqrt_loop__t[35:8]},sqrt_loop__s[3]},2'b01};
if ((sqrt_loop__r[35:4] >= sqrt_loop__t[35:4]))
begin
sqrt_loop__s[2] = 1'b1;
sqrt_loop__r[35:4] = (sqrt_loop__r[35:4] - sqrt_loop__t[35:4]);
end
else
sqrt_loop__s[2] = 1'b0;
sqrt_loop__t[35:2] = {{{1'b0,sqrt_loop__t[35:6]},sqrt_loop__s[2]},2'b01};
if ((sqrt_loop__r[35:2] >= sqrt_loop__t[35:2]))
begin
sqrt_loop__s[1] = 1'b1;
sqrt_loop__r[35:2] = (sqrt_loop__r[35:2] - sqrt_loop__t[35:2]);
end
else
sqrt_loop__s[1] = 1'b0;
sqrt_loop__t[35:0] = {{{1'b0,sqrt_loop__t[35:4]},sqrt_loop__s[1]},2'b01};
if ((sqrt_loop__r[35:0] >= sqrt_loop__t[35:0]))
begin
sqrt_loop__s[0] = 1'b1;
sqrt_loop__r[35:0] = (sqrt_loop__r[35:0] - sqrt_loop__t[35:0]);
end
else
sqrt_loop__s[0] = 1'b0;
z <= sqrt_loop__s;
end //always
endmodule
|
2)除算
正の整数 X 18ビットを正の整数 Y 18ビットで除算する回路です。
テストベンチは、時間がかかるので網羅的にしていません。$randomのxを作り、それ以下の全てのyに対してチェックしています。
オリジナルのソースコードとトランスレータ出力です。
------------------------------------------------------------------------
-- File DIV18.vhd --
-- Entity DIV18 --
-- rev date coded contents --
-- 001 98/06/23 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all;
--use IEEE.std_logic_arith.all;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity DIV18 is
port(
X : in std_logic_vector(17 downto 0) ; -- Input(18bit)
Y : in std_logic_vector(17 downto 0) ; -- Input(18bit)
C : out std_logic ; -- OverFlow Flag
Z : out std_logic_vector(17 downto 0) -- Output(18bit)
);
end DIV18 ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of DIV18 is
begin
--------------------------------
-- X divide by Y (X < Y)
--------------------------------
DIVIDE_LOOP : process( X, Y )
variable R : std_logic_vector(19 downto 0); -- Remain
variable S : std_logic_vector(17 downto 0); -- Result
variable T : std_logic_vector(19 downto 0); -- Temporaly
begin
if( X < Y ) then
-- Initialize value
R := '0' & X & '0' ; -- R = 2 * X
T := "00" & Y ; -- T = Y
for i in 17 downto 0 loop
if( R >= T ) then
S(i) := '1' ;
R := R - T ;
else
S(i) := '0' ;
end if ;
R := R(18 downto 0) & '0' ;
end loop ;
-- Result
Z <= S ;
C <= '0' ;
else
C <= '1' ;
Z <= "000000000000000000" ;
end if ;
end process ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// File DIV18.vhd --
// Entity DIV18 --
// rev date coded contents --
// 001 98/06/23 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module div18 ( x, y, c, z );
input [17:0] x ;
input [17:0] y ;
output c;
output [17:0] z ;
reg [19:0] divide_loop__r;
reg [17:0] divide_loop__s;
reg [19:0] divide_loop__t;
reg c;
reg [17:0] z;
always @ (x or y ) begin
if ((x < y))
begin
divide_loop__r = {{1'b0,x},1'b0};
divide_loop__t = {2'b00,y};
begin :Block_Name_1
integer i;
for (i=17;i>=0;i=i-1) begin
begin
if ((divide_loop__r >= divide_loop__t))
begin
divide_loop__s[i] = 1'b1;
divide_loop__r = (divide_loop__r - divide_loop__t);
end
else
divide_loop__s[i] = 1'b0;
divide_loop__r = {divide_loop__r[18:0],1'b0};
end
end //for
end //end Block
z <= divide_loop__s;
c <= 1'b0;
end
else
begin
c <= 1'b1;
z <= 18'b000000000000000000;
end
end //always
endmodule
|
3)平方根の逆数PartT
Z = 1/√X (但し X=0 の場合 Z=0) 正の整数 X 20 ビットの平方根の逆数をとる回路
出力は浮動小数点形式で指数部(ZN) 4 ビット,仮数部(ZM) 20 ビットです。
テストベンチは、網羅的に書きました。
オリジナルのソースコードとトランスレータ出力です。
------------------------------------------------------------------------
-- Title Reverse Square-Root (1/sqr(X)) --
-- File RSQRT.vhd --
-- Entity RSQRT --
-- rev date coded contents --
-- 001 98/11/05 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all ;
use IEEE.std_logic_arith.all ;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity RSQRT is
port(
X : in std_logic_vector(19 downto 0) ; -- Input(20bit)
ZN : out std_logic_vector(3 downto 0) ; -- Exp(4bit)
ZM : out std_logic_vector(19 downto 0) -- Man(20bit)
);
end RSQRT ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of RSQRT is
--
-- 1st stages
-- 10bit calc
-- XX.XXXXXXXX
signal A : std_logic_vector(9 downto 0) ; --
constant CONSA : std_logic_vector(9 downto 0) := "1000000111" ; -- 2.02734375
--
-- 2nd stages
-- 16bit calc
-- XX.XXXXXXXXXXXXXXXX
signal B : std_logic_vector(15 downto 0) ; --
--
-- 3rd stages
-- 26bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXXXX
signal C : std_logic_vector(25 downto 0) ; --
--
-- Constant Value
constant CONSX : std_logic_vector(31 downto 0) := "11000000000000000000000000000000" ; -- 3.0
--
--
-- 0.XXXXXXXX
signal M : std_logic_vector(19 downto 0) ; -- Mantissa
signal N : std_logic_vector(3 downto 0) ; -- Expornent
begin
--------------------------------
-- Reverse Square-Root Argolizm
--
-- X = m x 4^n (m = 0.25~0.999999)
-- Z = 1/sqrt(X) = sqrt(m)/m x 2^-n
-- ^^^^^^^^^ |
-- ZM ZN
-- --1st stage (3.16bit)
-- a = (2.0275551-m) -- a = 1.78~1.02
-- --2nd stage (5.70bit) : 1000 LCs
-- b1 = (a*a) -- b1 = +3.17~+1.04
-- b2 = (m*b1) -- b2 = +0.813~+1.0208
-- b3 = (3-b2)/2 -- b3 = +0.99~+1.094
-- b4 = a*b3 -- b4 = +1.00~+1.98
-- b = b4
-- --3nd stage (10.82bit) : 2500 LCs
-- c1 = (b*b) -- c1 = +3.92~+1.00
-- c2 = (m*c1) -- c2 = +0.99~+1.01
-- c3 = (3-c2)/2 -- c3 = +0.99~+1.01
-- c4 = b*c3 -- c4 = +1.00~+1.99
-- c = c4
-- --4th stage (21.06bit) : ???? LCs
-- d1 = (c*c) -- d1 = +3.98~+1.00
-- d2 = (m*d1) -- d2 = +0.99~+1.01
-- d3 = (3-d2)/2 -- d3 = +0.99~+1.01
-- d4 = c*d3 -- d4 = +1.00~+1.99
-- d = d4
--
-- ZM = g3
-- ZN = n
--------------------------------
-----------------------------------------------------------
-- Initialize --
-----------------------------------------------------------
RSQRT_INIT : process( X )
begin
if( X(19 downto 0) = "00000000000000000000" ) then
M <= (others=>'0') ;
N <= (others=>'0') ;
else
-- Generate M,N
if( X(19 downto 2) = "000000000000000000" ) then
M <= X(1 downto 0) & "000000000000000000" ;
N <= "0001" ;
elsif( X(19 downto 4) = "0000000000000000" ) then
M <= X(3 downto 0) & "0000000000000000" ;
N <= "0010" ;
elsif( X(19 downto 6) = "00000000000000" ) then
M <= X(5 downto 0) & "00000000000000" ;
N <= "0011" ;
elsif( X(19 downto 8) = "000000000000" ) then
M <= X(7 downto 0) & "000000000000" ;
N <= "0100" ;
elsif( X(19 downto 10) = "0000000000" ) then
M <= X(9 downto 0) & "0000000000" ;
N <= "0101" ;
elsif( X(19 downto 12) = "00000000" ) then
M <= X(11 downto 0) & "00000000" ;
N <= "0110" ;
elsif( X(19 downto 14) = "000000" ) then
M <= X(13 downto 0) & "000000" ;
N <= "0111" ;
elsif( X(19 downto 16) = "0000" ) then
M <= X(15 downto 0) & "0000" ;
N <= "1000" ;
elsif( X(19 downto 18) = "00" ) then
M <= X(17 downto 0) & "00" ;
N <= "1001" ;
else
M <= X ;
N <= "1010" ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- 1st stage --
-----------------------------------------------------------
RSQRT_1ST : process( M )
begin
if( M = "00000000000000000000" ) then
A <= (others=>'0') ;
else
-- A = 2.03-M
A <= CONSA - ("00" & M(19 downto 12)) ;
end if ;
end process ;
-----------------------------------------------------------
-- 2nd stage --
-----------------------------------------------------------
RSQRT_1ND : process( A )
variable B1 : std_logic_vector(17 downto 0); -- A(9bit)*A(9bit)
variable B2 : std_logic_vector(16 downto 0); -- M(8bit)*B1(9bit)
variable B3 : std_logic_vector(10 downto 0); -- 3-B2(11bit)
variable B4 : std_logic_vector(19 downto 0); -- A(9bit)*B3(11bit)
begin
if( A = "0000000000" ) then
B <= (others=>'0') ;
else
B1 := A(8 downto 0) * A(8 downto 0) ;
B2 := B1(17 downto 9) * M(19 downto 12) ;
B3 := CONSX(31 downto 21) - B2(16 downto 6) ;
B4 := B3 * A(8 downto 0) ;
B <= B4(19 downto 4) ;
end if ;
end process ;
-----------------------------------------------------------
-- 3rd stage --
-----------------------------------------------------------
RSQRT_3RD : process( B )
variable C1 : std_logic_vector(29 downto 0); -- B(15bit)*B(15bit)
variable C2 : std_logic_vector(31 downto 0); -- M(16bit)*C1(16bit)
variable C3 : std_logic_vector(18 downto 0); -- 3-C2(19bit)
variable C4 : std_logic_vector(33 downto 0); -- B(15bit)*C3(19bit)
begin
if( B = "0000000000000000" ) then
C <= (others=>'0') ;
else
C1 := B(14 downto 0) * B(14 downto 0) ;
C2 := C1(29 downto 14) * M(19 downto 4) ;
C3 := CONSX(31 downto 13) - C2(31 downto 13) ;
C4 := C3 * B(14 downto 0) ;
C <= C4(33 downto 8) ;
end if ;
end process ;
ZN <= N ;
--ZM <= A & "00000000000" ;
--ZM <= B & "0000" ;
ZM <= C(24 downto 5) ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// Title Reverse Square-Root (1/sqr(X)) --
// File RSQRT.vhd --
// Entity RSQRT --
// rev date coded contents --
// 001 98/11/05 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module rsqrt ( x, zn, zm );
input [19:0] x ;
output [3:0] zn ;
output [19:0] zm ;
reg [17:0] rsqrt_1nd__b1;
reg [16:0] rsqrt_1nd__b2;
reg [10:0] rsqrt_1nd__b3;
reg [19:0] rsqrt_1nd__b4;
reg [29:0] rsqrt_3rd__c1;
reg [31:0] rsqrt_3rd__c2;
reg [18:0] rsqrt_3rd__c3;
reg [33:0] rsqrt_3rd__c4;
reg [9:0] a;
parameter [9:0] consa=10'b1000000111;
reg [15:0] b;
reg [25:0] c;
parameter [31:0] consx=32'b11000000000000000000000000000000;
reg [19:0] m;
reg [3:0] n;
wire [3:0] zn;
wire [19:0] zm;
always @ (x ) begin
if ((x[19:0] === 20'b00000000000000000000))
begin
m <= {(19-0+1- 0){1'b0}};
n <= {(3-0+1- 0){1'b0}};
end
else
begin
if ((x[19:2] === 18'b000000000000000000))
begin
m <= {x[1:0],18'b000000000000000000};
n <= 4'b0001;
end
else if ((x[19:4] === 16'b0000000000000000))
begin
m <= {x[3:0],16'b0000000000000000};
n <= 4'b0010;
end
else if ((x[19:6] === 14'b00000000000000))
begin
m <= {x[5:0],14'b00000000000000};
n <= 4'b0011;
end
else if ((x[19:8] === 12'b000000000000))
begin
m <= {x[7:0],12'b000000000000};
n <= 4'b0100;
end
else if ((x[19:10] === 10'b0000000000))
begin
m <= {x[9:0],10'b0000000000};
n <= 4'b0101;
end
else if ((x[19:12] === 8'b00000000))
begin
m <= {x[11:0],8'b00000000};
n <= 4'b0110;
end
else if ((x[19:14] === 6'b000000))
begin
m <= {x[13:0],6'b000000};
n <= 4'b0111;
end
else if ((x[19:16] === 4'b0000))
begin
m <= {x[15:0],4'b0000};
n <= 4'b1000;
end
else if ((x[19:18] === 2'b00))
begin
m <= {x[17:0],2'b00};
n <= 4'b1001;
end
else
begin
m <= x;
n <= 4'b1010;
end
end
end //always
always @ (m ) begin
if ((m === 20'b00000000000000000000))
a <= {(9-0+1- 0){1'b0}};
else
a <= (consa - {2'b00,m[19:12]});
end //always
always @ (a ) begin
if ((a === 10'b0000000000))
b <= {(15-0+1- 0){1'b0}};
else
begin
rsqrt_1nd__b1 = (a[8:0] * a[8:0]);
rsqrt_1nd__b2 = (rsqrt_1nd__b1[17:9] * m[19:12]);
rsqrt_1nd__b3 = (consx[31:21] - rsqrt_1nd__b2[16:6]);
rsqrt_1nd__b4 = (rsqrt_1nd__b3 * a[8:0]);
b <= rsqrt_1nd__b4[19:4];
end
end //always
always @ (b ) begin
if ((b === 16'b0000000000000000))
c <= {(25-0+1- 0){1'b0}};
else
begin
rsqrt_3rd__c1 = (b[14:0] * b[14:0]);
rsqrt_3rd__c2 = (rsqrt_3rd__c1[29:14] * m[19:4]);
rsqrt_3rd__c3 = (consx[31:13] - rsqrt_3rd__c2[31:13]);
rsqrt_3rd__c4 = (rsqrt_3rd__c3 * b[14:0]);
c <= rsqrt_3rd__c4[33:8];
end
end //always
assign {zn}=n;
assign {zm}=c[24:5];
endmodule
|
3)平方根の逆数PartU
Z = 1/√X (但し X=0 の場合 Z=0) 正の整数 X 20 ビットの平方根の逆数をとる回路
出力は浮動小数点形式で指数部(ZN) 4 ビット,仮数部(ZM) 20 ビットです。
テストベンチは、網羅的に書きました。パートTとの違いは、精度です。
------------------------------------------------------------------------
-- Title Reverse Square-Root (1/sqr(X)) --
-- File RSQRT.vhd --
-- Entity RSQRT --
-- rev date coded contents --
-- 001 98/11/05 ueno Make Original --
-- 002 98/11/10 ueno 4th stage up --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all ;
use IEEE.std_logic_arith.all ;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity RSQRT is
port(
X : in std_logic_vector(19 downto 0) ; -- Input(20bit)
ZN : out std_logic_vector(3 downto 0) ; -- Exp(4bit)
ZM : out std_logic_vector(19 downto 0) -- Man(20bit)
);
end RSQRT ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of RSQRT is
--
-- 1st stages
-- 10bit calc
-- XX.XXXXXXXX
signal A : std_logic_vector(9 downto 0) ; --
constant CONSA : std_logic_vector(9 downto 0) := "1000000111" ; -- 2.02734375
--
-- 2nd stages
-- 16bit calc
-- XX.XXXXXXXXXXXXXXXX
signal B : std_logic_vector(15 downto 0) ; --
--
-- 3rd stages
-- 24bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXX
signal C : std_logic_vector(23 downto 0) ; --
--
-- 4th stages
-- 24bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXX
signal D : std_logic_vector(23 downto 0) ; --
--
-- Constant Value
constant CONSX : std_logic_vector(31 downto 0) := "11000000000000000000000000000000" ; -- 3.0
--
--
-- 0.XXXXXXXX
signal M : std_logic_vector(19 downto 0) ; -- Mantissa
signal N : std_logic_vector(3 downto 0) ; -- Expornent
begin
--------------------------------
-- Reverse Square-Root Argolizm
--
-- X = m x 4^n (m = 0.25~0.999999)
-- Z = 1/sqrt(X) = sqrt(m)/m x 2^-n
-- ^^^^^^^^^ |
-- ZM ZN
-- --1st stage (3.16bit)
-- a = (2.0275551-m) -- a = 1.78~1.02
-- --2nd stage (5.70bit) : 1000 LCs
-- b1 = (a*a) -- b1 = +3.17~+1.04
-- b2 = (m*b1) -- b2 = +0.813~+1.0208
-- b3 = (3-b2)/2 -- b3 = +0.99~+1.094
-- b4 = a*b3 -- b4 = +1.00~+1.98
-- b = b4
-- --3nd stage (10.82bit) : 2500 LCs
-- c1 = (b*b) -- c1 = +3.92~+1.00
-- c2 = (m*c1) -- c2 = +0.99~+1.01
-- c3 = (3-c2)/2 -- c3 = +0.99~+1.01
-- c4 = b*c3 -- c4 = +1.00~+1.99
-- c = c4
-- --4th stage (21.06bit) : 5000 LCs
-- d1 = (c*c) -- d1 = +3.98~+1.00
-- d2 = (m*d1) -- d2 = +0.99~+1.01
-- d3 = (3-d2)/2 -- d3 = +0.99~+1.01
-- d4 = c*d3 -- d4 = +1.00~+1.99
-- d = d4
--
-- ZM = g3
-- ZN = n
--------------------------------
-----------------------------------------------------------
-- Initialize --
-----------------------------------------------------------
RSQRT_INIT : process( X )
begin
if( X(19 downto 0) = "00000000000000000000" ) then
M <= (others=>'0') ;
N <= (others=>'0') ;
else
-- Generate M,N
if( X(19 downto 2) = "000000000000000000" ) then
M <= X(1 downto 0) & "000000000000000000" ;
N <= "0001" ;
elsif( X(19 downto 4) = "0000000000000000" ) then
M <= X(3 downto 0) & "0000000000000000" ;
N <= "0010" ;
elsif( X(19 downto 6) = "00000000000000" ) then
M <= X(5 downto 0) & "00000000000000" ;
N <= "0011" ;
elsif( X(19 downto 8) = "000000000000" ) then
M <= X(7 downto 0) & "000000000000" ;
N <= "0100" ;
elsif( X(19 downto 10) = "0000000000" ) then
M <= X(9 downto 0) & "0000000000" ;
N <= "0101" ;
elsif( X(19 downto 12) = "00000000" ) then
M <= X(11 downto 0) & "00000000" ;
N <= "0110" ;
elsif( X(19 downto 14) = "000000" ) then
M <= X(13 downto 0) & "000000" ;
N <= "0111" ;
elsif( X(19 downto 16) = "0000" ) then
M <= X(15 downto 0) & "0000" ;
N <= "1000" ;
elsif( X(19 downto 18) = "00" ) then
M <= X(17 downto 0) & "00" ;
N <= "1001" ;
else
M <= X ;
N <= "1010" ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- 1st stage --
-----------------------------------------------------------
RSQRT_1ST : process( M )
begin
if( M = "00000000000000000000" ) then
A <= (others=>'0') ;
else
-- A = 2.03-M
A <= CONSA - ("00" & M(19 downto 12)) ;
end if ;
end process ;
-----------------------------------------------------------
-- 2nd stage --
-----------------------------------------------------------
RSQRT_1ND : process( M, A )
variable B1 : std_logic_vector(17 downto 0); -- A(9bit)*A(9bit)
variable B2 : std_logic_vector(16 downto 0); -- M(8bit)*B1(9bit)
variable B3 : std_logic_vector(10 downto 0); -- 3-B2(11bit)
variable B4 : std_logic_vector(19 downto 0); -- A(9bit)*B3(11bit)
begin
if( A = "0000000000" ) then
B <= (others=>'0') ;
else
B1 := A(8 downto 0) * A(8 downto 0) ;
B2 := B1(17 downto 9) * M(19 downto 12) ;
B3 := CONSX(31 downto 21) - B2(16 downto 6) ;
B4 := B3 * A(8 downto 0) ;
B <= B4(19 downto 4) ;
end if ;
end process ;
-----------------------------------------------------------
-- 3rd stage --
-----------------------------------------------------------
RSQRT_3RD : process( M, B )
variable C1 : std_logic_vector(29 downto 0); -- B(15bit)*B(15bit)
variable C2 : std_logic_vector(31 downto 0); -- M(16bit)*C1(16bit)
variable C3 : std_logic_vector(18 downto 0); -- 3-C2(19bit)
variable C4 : std_logic_vector(33 downto 0); -- B(15bit)*C3(19bit)
begin
if( B = "0000000000000000" ) then
C <= (others=>'0') ;
else
C1 := B(14 downto 0) * B(14 downto 0) ;
C2 := C1(29 downto 14) * M(19 downto 4) ;
C3 := CONSX(31 downto 13) - C2(31 downto 13) ;
C4 := C3 * B(14 downto 0) ;
C <= C4(33 downto 10) ;
end if ;
end process ;
-----------------------------------------------------------
-- 4th stage --
-----------------------------------------------------------
RSQRT_4TH : process( M, C )
variable D1 : std_logic_vector(39 downto 0); -- C(20bit)*C(20bit)
variable D2 : std_logic_vector(39 downto 0); -- M(20bit)*D1(20bit)
variable D3 : std_logic_vector(23 downto 0); -- 3-D2(24bit)
variable D4 : std_logic_vector(43 downto 0); -- C(20bit)*D3(24bit)
begin
if( C = "000000000000000000000000" ) then
D <= (others=>'0') ;
else
D1 := C(22 downto 3) * C(22 downto 3) ;
D2 := D1(39 downto 20) * M(19 downto 0) ;
D3 := CONSX(31 downto 8) - D2(39 downto 16) ;
D4 := D3 * C(22 downto 3) ;
D <= D4(43 downto 20) ;
end if ;
end process ;
ZN <= N ;
--ZM <= A & "00000000000" ;
--ZM <= B & "0000" ;
--ZM <= C(22 downto 3) ;
ZM <= D(22 downto 3) ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// Title Reverse Square-Root (1/sqr(X)) --
// File RSQRT.vhd --
// Entity RSQRT --
// rev date coded contents --
// 001 98/11/05 ueno Make Original --
// 002 98/11/10 ueno 4th stage up --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module rsqrt ( x, zn, zm );
input [19:0] x ;
output [3:0] zn ;
output [19:0] zm ;
reg [17:0] rsqrt_1nd__b1;
reg [16:0] rsqrt_1nd__b2;
reg [10:0] rsqrt_1nd__b3;
reg [19:0] rsqrt_1nd__b4;
reg [29:0] rsqrt_3rd__c1;
reg [31:0] rsqrt_3rd__c2;
reg [18:0] rsqrt_3rd__c3;
reg [33:0] rsqrt_3rd__c4;
reg [39:0] rsqrt_4th__d1;
reg [39:0] rsqrt_4th__d2;
reg [23:0] rsqrt_4th__d3;
reg [43:0] rsqrt_4th__d4;
reg [9:0] a;
parameter [9:0] consa=10'b1000000111;
reg [15:0] b;
reg [23:0] c;
reg [23:0] d;
parameter [31:0] consx=32'b11000000000000000000000000000000;
reg [19:0] m;
reg [3:0] n;
wire [3:0] zn;
wire [19:0] zm;
always @ (x ) begin
if ((x[19:0] === 20'b00000000000000000000))
begin
m <= {(19-0+1- 0){1'b0}};
n <= {(3-0+1- 0){1'b0}};
end
else
begin
if ((x[19:2] === 18'b000000000000000000))
begin
m <= {x[1:0],18'b000000000000000000};
n <= 4'b0001;
end
else if ((x[19:4] === 16'b0000000000000000))
begin
m <= {x[3:0],16'b0000000000000000};
n <= 4'b0010;
end
else if ((x[19:6] === 14'b00000000000000))
begin
m <= {x[5:0],14'b00000000000000};
n <= 4'b0011;
end
else if ((x[19:8] === 12'b000000000000))
begin
m <= {x[7:0],12'b000000000000};
n <= 4'b0100;
end
else if ((x[19:10] === 10'b0000000000))
begin
m <= {x[9:0],10'b0000000000};
n <= 4'b0101;
end
else if ((x[19:12] === 8'b00000000))
begin
m <= {x[11:0],8'b00000000};
n <= 4'b0110;
end
else if ((x[19:14] === 6'b000000))
begin
m <= {x[13:0],6'b000000};
n <= 4'b0111;
end
else if ((x[19:16] === 4'b0000))
begin
m <= {x[15:0],4'b0000};
n <= 4'b1000;
end
else if ((x[19:18] === 2'b00))
begin
m <= {x[17:0],2'b00};
n <= 4'b1001;
end
else
begin
m <= x;
n <= 4'b1010;
end
end
end //always
always @ (m ) begin
if ((m === 20'b00000000000000000000))
a <= {(9-0+1- 0){1'b0}};
else
a <= (consa - {2'b00,m[19:12]});
end //always
always @ (m or a ) begin
if ((a === 10'b0000000000))
b <= {(15-0+1- 0){1'b0}};
else
begin
rsqrt_1nd__b1 = (a[8:0] * a[8:0]);
rsqrt_1nd__b2 = (rsqrt_1nd__b1[17:9] * m[19:12]);
rsqrt_1nd__b3 = (consx[31:21] - rsqrt_1nd__b2[16:6]);
rsqrt_1nd__b4 = (rsqrt_1nd__b3 * a[8:0]);
b <= rsqrt_1nd__b4[19:4];
end
end //always
always @ (m or b ) begin
if ((b === 16'b0000000000000000))
c <= {(23-0+1- 0){1'b0}};
else
begin
rsqrt_3rd__c1 = (b[14:0] * b[14:0]);
rsqrt_3rd__c2 = (rsqrt_3rd__c1[29:14] * m[19:4]);
rsqrt_3rd__c3 = (consx[31:13] - rsqrt_3rd__c2[31:13]);
rsqrt_3rd__c4 = (rsqrt_3rd__c3 * b[14:0]);
c <= rsqrt_3rd__c4[33:10];
end
end //always
always @ (m or c ) begin
if ((c === 24'b000000000000000000000000))
d <= {(23-0+1- 0){1'b0}};
else
begin
rsqrt_4th__d1 = (c[22:3] * c[22:3]);
rsqrt_4th__d2 = (rsqrt_4th__d1[39:20] * m[19:0]);
rsqrt_4th__d3 = (consx[31:8] - rsqrt_4th__d2[39:16]);
rsqrt_4th__d4 = (rsqrt_4th__d3 * c[22:3]);
d <= rsqrt_4th__d4[43:20];
end
end //always
assign {zn}=n;
assign {zm}=d[22:3];
endmodule
|
4)逆数PartT
Z = 1/X (但し X>0, X=0 の場合 Z=0) 正の整数 X 20 ビットの逆数をとる回路
出力は浮動小数点形式で指数部(ZN) 5 ビット,仮数部(ZM) 20 ビット です。
テストベンチです。
------------------------------------------------------------------------
-- Title Reverse X (1/X) --
-- File REVX.vhd --
-- Entity REVX --
-- rev date coded contents --
-- 001 98/11/10 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all ;
use IEEE.std_logic_arith.all ;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity REVX is
port(
X : in std_logic_vector(19 downto 0) ; -- Input(20bit)
ZN : out std_logic_vector(4 downto 0) ; -- Exp(5bit)
ZM : out std_logic_vector(19 downto 0) -- Man(20bit)
);
end REVX ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of REVX is
--
-- 1st stages
-- 10bit calc
-- XX.XXXXXXXX
signal A : std_logic_vector(9 downto 0) ; --
constant CONSA : std_logic_vector(9 downto 0) := "1100000000" ; -- 3
--
-- 2nd stages
-- 16bit calc
-- XX.XXXXXXXXXXXXXXXX
signal B : std_logic_vector(15 downto 0) ; --
--
-- 3rd stages
-- 24bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXX
signal C : std_logic_vector(23 downto 0) ; --
--
-- 4th stages
-- 24bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXX
signal D : std_logic_vector(23 downto 0) ; --
--
-- Constant Value
constant CONSX : std_logic_vector(31 downto 0) := "10000000000000000000000000000000" ; -- 2.0
--
--
-- 0.XXXXXXXX
signal M : std_logic_vector(19 downto 0) ; -- Mantissa
signal N : std_logic_vector(4 downto 0) ; -- Expornent
begin
--------------------------------
-- Reverse X Argolizm (X>0)
--
-- X = m x 2^n (m = 0.5~0.999999)
-- Z = 1/X = 1/m x 2^-n
-- | |
-- ZM ZN
-- --1st stage (3bit)
-- a = (3-2*m) -- a = 1~2 (3.00bit)
-- a = (723-482*m)/256 -- a = 1~2 (4.08bit)
-- --2nd stage (6bit) : xxxx LCs
-- b1 = (m*a) -- b1 = 1~1.125
-- b2 = (2-b1) -- b2 = 0.875~1
-- b3 = a*b2 -- b3 = 1~2
-- b = b3
-- --3nd stage (12bit) : xxxx LCs
-- c1 = (m*b) -- c1 = 0.98~1
-- c2 = (2-c1) -- c2 = 1~1.01
-- c3 = b*c2 -- c3 = 1~2
-- c = c4
-- --4th stage (24bit) : ???? LCs
-- d1 = (m*c) -- d1 = 0.99~1
-- d2 = (3-d1) -- d2 = 1~1.00
-- d3 = c*d2 -- d3 = 1~2
-- d = d4
--
-- ZM = d
-- ZN = n
--------------------------------
-----------------------------------------------------------
-- Initialize --
-----------------------------------------------------------
REVX_INIT : process( X )
begin
if( X(19 downto 0) = "00000000000000000000" ) then
M <= (others=>'0') ;
N <= (others=>'0') ;
else
-- Generate M,N
if( X(19 downto 1) = "0000000000000000000" ) then
M <= X(0) & "0000000000000000000" ;
N <= "00001" ;
elsif( X(19 downto 2) = "000000000000000000" ) then
M <= X(1 downto 0) & "000000000000000000" ;
N <= "00010" ;
elsif( X(19 downto 3) = "00000000000000000" ) then
M <= X(2 downto 0) & "00000000000000000" ;
N <= "00011" ;
elsif( X(19 downto 4) = "0000000000000000" ) then
M <= X(3 downto 0) & "0000000000000000" ;
N <= "00100" ;
elsif( X(19 downto 5) = "000000000000000" ) then
M <= X(4 downto 0) & "000000000000000" ;
N <= "00101" ;
elsif( X(19 downto 6) = "00000000000000" ) then
M <= X(5 downto 0) & "00000000000000" ;
N <= "00110" ;
elsif( X(19 downto 7) = "0000000000000" ) then
M <= X(6 downto 0) & "0000000000000" ;
N <= "00111" ;
elsif( X(19 downto 8) = "000000000000" ) then
M <= X(7 downto 0) & "000000000000" ;
N <= "01000" ;
elsif( X(19 downto 9) = "00000000000" ) then
M <= X(8 downto 0) & "00000000000" ;
N <= "01001" ;
elsif( X(19 downto 10) = "0000000000" ) then
M <= X(9 downto 0) & "0000000000" ;
N <= "01010" ;
elsif( X(19 downto 11) = "000000000" ) then
M <= X(10 downto 0) & "000000000" ;
N <= "01011" ;
elsif( X(19 downto 12) = "00000000" ) then
M <= X(11 downto 0) & "00000000" ;
N <= "01100" ;
elsif( X(19 downto 13) = "0000000" ) then
M <= X(12 downto 0) & "0000000" ;
N <= "01101" ;
elsif( X(19 downto 14) = "000000" ) then
M <= X(13 downto 0) & "000000" ;
N <= "01110" ;
elsif( X(19 downto 15) = "00000" ) then
M <= X(14 downto 0) & "00000" ;
N <= "01111" ;
elsif( X(19 downto 16) = "0000" ) then
M <= X(15 downto 0) & "0000" ;
N <= "10000" ;
elsif( X(19 downto 17) = "000" ) then
M <= X(16 downto 0) & "000" ;
N <= "10001" ;
elsif( X(19 downto 18) = "00" ) then
M <= X(17 downto 0) & "00" ;
N <= "10010" ;
elsif( X(19) = '0' ) then
M <= X(18 downto 0) & '0' ;
N <= "10011" ;
else
M <= X ;
N <= "10100" ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- 1st stage --
-----------------------------------------------------------
REVX_1ST : process( M )
begin
if( M = "00000000000000000000" ) then
A <= (others=>'0') ;
else
-- A = 3-2*M
A <= CONSA - ('0' & M(19 downto 11)) ;
end if ;
end process ;
-----------------------------------------------------------
-- 2nd stage --
-----------------------------------------------------------
REVX_1ND : process( M, A )
variable B1 : std_logic_vector(19 downto 0); -- M(10bit)*A(10bit) XX.XX....
variable B2 : std_logic_vector(11 downto 0); -- 2-B1(12bit) X.XX....
variable B3 : std_logic_vector(21 downto 0); -- A(10bit)*B2(12bit) XXX.XX....
begin
if( A = "0000000000" ) then
B <= (others=>'0') ;
else
B1 := M(19 downto 10) * A ;
B2 := CONSX(30 downto 19) - B1(18 downto 7) ;
B3 := B2 * A ;
B <= B3(20 downto 5) ;
end if ;
end process ;
-----------------------------------------------------------
-- 3rd stage --
-----------------------------------------------------------
REVX_3RD : process( M, B )
variable C1 : std_logic_vector(31 downto 0); -- M(16bit)*B(16bit) XX.XX...
variable C2 : std_logic_vector(19 downto 0); -- 2-C1(20bit) X.XX...
variable C3 : std_logic_vector(35 downto 0); -- B(16bit)*C2(20bit) XXX.XX...
begin
if( B = "0000000000000000" ) then
C <= (others=>'0') ;
else
C1 := B * M(19 downto 4) ;
C2 := CONSX(30 downto 11) - C1(30 downto 11) ;
C3 := C2 * B ;
C <= C3(34 downto 11) ;
end if ;
end process ;
-----------------------------------------------------------
-- 4th stage --
-----------------------------------------------------------
REVX_4TH : process( M, C )
variable D1 : std_logic_vector(39 downto 0); -- M(20bit)*C(20bit) XX.XX...
variable D2 : std_logic_vector(23 downto 0); -- 2-D1(24bit) X.XX...
variable D3 : std_logic_vector(43 downto 0); -- C(20bit)*D2(24bit) XXX.XX...
begin
if( C = "000000000000000000000000" ) then
D <= (others=>'0') ;
else
D1 := C(23 downto 4) * M ;
D2 := CONSX(30 downto 7) - D1(38 downto 15) ;
D3 := D2 * C(23 downto 4) ;
D <= D3(42 downto 19) ;
end if ;
end process ;
ZN <= N ;
--ZM <= A & "0000000000" ;
--ZM <= B & "0000" ;
ZM <= C(23 downto 4) ;
--ZM <= D(23 downto 4) ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// Title Reverse X (1/X) --
// File REVX.vhd --
// Entity REVX --
// rev date coded contents --
// 001 98/11/10 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module revx ( x, zn, zm );
input [19:0] x ;
output [4:0] zn ;
output [19:0] zm ;
reg [19:0] revx_1nd__b1;
reg [11:0] revx_1nd__b2;
reg [21:0] revx_1nd__b3;
reg [31:0] revx_3rd__c1;
reg [19:0] revx_3rd__c2;
reg [35:0] revx_3rd__c3;
reg [39:0] revx_4th__d1;
reg [23:0] revx_4th__d2;
reg [43:0] revx_4th__d3;
reg [9:0] a;
parameter [9:0] consa=10'b1100000000;
reg [15:0] b;
reg [23:0] c;
reg [23:0] d;
parameter [31:0] consx=32'b10000000000000000000000000000000;
reg [19:0] m;
reg [4:0] n;
wire [4:0] zn;
wire [19:0] zm;
always @ (x ) begin
if ((x[19:0] === 20'b00000000000000000000))
begin
m <= {(19-0+1- 0){1'b0}};
n <= {(4-0+1- 0){1'b0}};
end
else
begin
if ((x[19:1] === 19'b0000000000000000000))
begin
m <= {x[0],19'b0000000000000000000};
n <= 5'b00001;
end
else if ((x[19:2] === 18'b000000000000000000))
begin
m <= {x[1:0],18'b000000000000000000};
n <= 5'b00010;
end
else if ((x[19:3] === 17'b00000000000000000))
begin
m <= {x[2:0],17'b00000000000000000};
n <= 5'b00011;
end
else if ((x[19:4] === 16'b0000000000000000))
begin
m <= {x[3:0],16'b0000000000000000};
n <= 5'b00100;
end
else if ((x[19:5] === 15'b000000000000000))
begin
m <= {x[4:0],15'b000000000000000};
n <= 5'b00101;
end
else if ((x[19:6] === 14'b00000000000000))
begin
m <= {x[5:0],14'b00000000000000};
n <= 5'b00110;
end
else if ((x[19:7] === 13'b0000000000000))
begin
m <= {x[6:0],13'b0000000000000};
n <= 5'b00111;
end
else if ((x[19:8] === 12'b000000000000))
begin
m <= {x[7:0],12'b000000000000};
n <= 5'b01000;
end
else if ((x[19:9] === 11'b00000000000))
begin
m <= {x[8:0],11'b00000000000};
n <= 5'b01001;
end
else if ((x[19:10] === 10'b0000000000))
begin
m <= {x[9:0],10'b0000000000};
n <= 5'b01010;
end
else if ((x[19:11] === 9'b000000000))
begin
m <= {x[10:0],9'b000000000};
n <= 5'b01011;
end
else if ((x[19:12] === 8'b00000000))
begin
m <= {x[11:0],8'b00000000};
n <= 5'b01100;
end
else if ((x[19:13] === 7'b0000000))
begin
m <= {x[12:0],7'b0000000};
n <= 5'b01101;
end
else if ((x[19:14] === 6'b000000))
begin
m <= {x[13:0],6'b000000};
n <= 5'b01110;
end
else if ((x[19:15] === 5'b00000))
begin
m <= {x[14:0],5'b00000};
n <= 5'b01111;
end
else if ((x[19:16] === 4'b0000))
begin
m <= {x[15:0],4'b0000};
n <= 5'b10000;
end
else if ((x[19:17] === 3'b000))
begin
m <= {x[16:0],3'b000};
n <= 5'b10001;
end
else if ((x[19:18] === 2'b00))
begin
m <= {x[17:0],2'b00};
n <= 5'b10010;
end
else if ((x[19] === 1'b0))
begin
m <= {x[18:0],1'b0};
n <= 5'b10011;
end
else
begin
m <= x;
n <= 5'b10100;
end
end
end //always
always @ (m ) begin
if ((m === 20'b00000000000000000000))
a <= {(9-0+1- 0){1'b0}};
else
a <= (consa - {1'b0,m[19:11]});
end //always
always @ (m or a ) begin
if ((a === 10'b0000000000))
b <= {(15-0+1- 0){1'b0}};
else
begin
revx_1nd__b1 = (m[19:10] * a);
revx_1nd__b2 = (consx[30:19] - revx_1nd__b1[18:7]);
revx_1nd__b3 = (revx_1nd__b2 * a);
b <= revx_1nd__b3[20:5];
end
end //always
always @ (m or b ) begin
if ((b === 16'b0000000000000000))
c <= {(23-0+1- 0){1'b0}};
else
begin
revx_3rd__c1 = (b * m[19:4]);
revx_3rd__c2 = (consx[30:11] - revx_3rd__c1[30:11]);
revx_3rd__c3 = (revx_3rd__c2 * b);
c <= revx_3rd__c3[34:11];
end
end //always
always @ (m or c ) begin
if ((c === 24'b000000000000000000000000))
d <= {(23-0+1- 0){1'b0}};
else
begin
revx_4th__d1 = (c[23:4] * m);
revx_4th__d2 = (consx[30:7] - revx_4th__d1[38:15]);
revx_4th__d3 = (revx_4th__d2 * c[23:4]);
d <= revx_4th__d3[42:19];
end
end //always
assign {zn}=n;
assign {zm}=c[23:4];
endmodule
|
5)逆数PartU
Z = 1/X (但し X>0, X=0 の場合 Z=0) 正の整数 X 20 ビットの逆数をとる回路
出力は浮動小数点形式で指数部(ZN) 5 ビット,仮数部(ZM) 20 ビット です。
テストベンチです。パートTとの違いは、精度です。
------------------------------------------------------------------------
-- Title Reverse X (1/X) --
-- File REVX.vhd --
-- Entity REVX --
-- rev date coded contents --
-- 001 98/11/10 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all ;
use IEEE.std_logic_arith.all ;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity REVX is
port(
X : in std_logic_vector(19 downto 0) ; -- Input(20bit)
ZN : out std_logic_vector(4 downto 0) ; -- Exp(5bit)
ZM : out std_logic_vector(19 downto 0) -- Man(20bit)
);
end REVX ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of REVX is
--
-- 1st stages
-- 10bit calc
-- XX.XXXXXXXX
signal A : std_logic_vector(9 downto 0) ; --
constant CONSA : std_logic_vector(9 downto 0) := "1100000000" ; -- 3
--
-- 2nd stages
-- 16bit calc
-- XX.XXXXXXXXXXXXXXXX
signal B : std_logic_vector(15 downto 0) ; --
--
-- 3rd stages
-- 24bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXX
signal C : std_logic_vector(23 downto 0) ; --
--
-- 4th stages
-- 24bit calc
-- XX.XXXXXXXXXXXXXXXXXXXXXX
signal D : std_logic_vector(23 downto 0) ; --
--
-- Constant Value
constant CONSX : std_logic_vector(31 downto 0) := "10000000000000000000000000000000" ; -- 2.0
--
--
-- 0.XXXXXXXX
signal M : std_logic_vector(19 downto 0) ; -- Mantissa
signal N : std_logic_vector(4 downto 0) ; -- Expornent
begin
--------------------------------
-- Reverse X Argolizm (X>0)
--
-- X = m x 2^n (m = 0.5~0.999999)
-- Z = 1/X = 1/m x 2^-n
-- | |
-- ZM ZN
-- --1st stage (3bit)
-- a = (3-2*m) -- a = 1~2 (3.00bit)
-- a = (723-482*m)/256 -- a = 1~2 (4.08bit)
-- --2nd stage (6bit) : xxxx LCs
-- b1 = (m*a) -- b1 = 1~1.125
-- b2 = (2-b1) -- b2 = 0.875~1
-- b3 = a*b2 -- b3 = 1~2
-- b = b3
-- --3nd stage (12bit) : xxxx LCs
-- c1 = (m*b) -- c1 = 0.98~1
-- c2 = (2-c1) -- c2 = 1~1.01
-- c3 = b*c2 -- c3 = 1~2
-- c = c4
-- --4th stage (24bit) : ???? LCs
-- d1 = (m*c) -- d1 = 0.99~1
-- d2 = (3-d1) -- d2 = 1~1.00
-- d3 = c*d2 -- d3 = 1~2
-- d = d4
--
-- ZM = d
-- ZN = n
--------------------------------
-----------------------------------------------------------
-- Initialize --
-----------------------------------------------------------
REVX_INIT : process( X )
begin
if( X(19 downto 0) = "00000000000000000000" ) then
M <= (others=>'0') ;
N <= (others=>'0') ;
else
-- Generate M,N
if( X(19 downto 1) = "0000000000000000000" ) then
M <= X(0) & "0000000000000000000" ;
N <= "00001" ;
elsif( X(19 downto 2) = "000000000000000000" ) then
M <= X(1 downto 0) & "000000000000000000" ;
N <= "00010" ;
elsif( X(19 downto 3) = "00000000000000000" ) then
M <= X(2 downto 0) & "00000000000000000" ;
N <= "00011" ;
elsif( X(19 downto 4) = "0000000000000000" ) then
M <= X(3 downto 0) & "0000000000000000" ;
N <= "00100" ;
elsif( X(19 downto 5) = "000000000000000" ) then
M <= X(4 downto 0) & "000000000000000" ;
N <= "00101" ;
elsif( X(19 downto 6) = "00000000000000" ) then
M <= X(5 downto 0) & "00000000000000" ;
N <= "00110" ;
elsif( X(19 downto 7) = "0000000000000" ) then
M <= X(6 downto 0) & "0000000000000" ;
N <= "00111" ;
elsif( X(19 downto 8) = "000000000000" ) then
M <= X(7 downto 0) & "000000000000" ;
N <= "01000" ;
elsif( X(19 downto 9) = "00000000000" ) then
M <= X(8 downto 0) & "00000000000" ;
N <= "01001" ;
elsif( X(19 downto 10) = "0000000000" ) then
M <= X(9 downto 0) & "0000000000" ;
N <= "01010" ;
elsif( X(19 downto 11) = "000000000" ) then
M <= X(10 downto 0) & "000000000" ;
N <= "01011" ;
elsif( X(19 downto 12) = "00000000" ) then
M <= X(11 downto 0) & "00000000" ;
N <= "01100" ;
elsif( X(19 downto 13) = "0000000" ) then
M <= X(12 downto 0) & "0000000" ;
N <= "01101" ;
elsif( X(19 downto 14) = "000000" ) then
M <= X(13 downto 0) & "000000" ;
N <= "01110" ;
elsif( X(19 downto 15) = "00000" ) then
M <= X(14 downto 0) & "00000" ;
N <= "01111" ;
elsif( X(19 downto 16) = "0000" ) then
M <= X(15 downto 0) & "0000" ;
N <= "10000" ;
elsif( X(19 downto 17) = "000" ) then
M <= X(16 downto 0) & "000" ;
N <= "10001" ;
elsif( X(19 downto 18) = "00" ) then
M <= X(17 downto 0) & "00" ;
N <= "10010" ;
elsif( X(19) = '0' ) then
M <= X(18 downto 0) & '0' ;
N <= "10011" ;
else
M <= X ;
N <= "10100" ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- 1st stage --
-----------------------------------------------------------
REVX_1ST : process( M )
begin
if( M = "00000000000000000000" ) then
A <= (others=>'0') ;
else
-- A = 3-2*M
A <= CONSA - ('0' & M(19 downto 11)) ;
end if ;
end process ;
-----------------------------------------------------------
-- 2nd stage --
-----------------------------------------------------------
REVX_1ND : process( M, A )
variable B1 : std_logic_vector(19 downto 0); -- M(10bit)*A(10bit) XX.XX....
variable B2 : std_logic_vector(11 downto 0); -- 2-B1(12bit) X.XX....
variable B3 : std_logic_vector(21 downto 0); -- A(10bit)*B2(12bit) XXX.XX....
begin
if( A = "0000000000" ) then
B <= (others=>'0') ;
else
B1 := M(19 downto 10) * A ;
B2 := CONSX(30 downto 19) - B1(18 downto 7) ;
B3 := B2 * A ;
B <= B3(20 downto 5) ;
end if ;
end process ;
-----------------------------------------------------------
-- 3rd stage --
-----------------------------------------------------------
REVX_3RD : process( M, B )
variable C1 : std_logic_vector(31 downto 0); -- M(16bit)*B(16bit) XX.XX...
variable C2 : std_logic_vector(19 downto 0); -- 2-C1(20bit) X.XX...
variable C3 : std_logic_vector(35 downto 0); -- B(16bit)*C2(20bit) XXX.XX...
begin
if( B = "0000000000000000" ) then
C <= (others=>'0') ;
else
C1 := B * M(19 downto 4) ;
C2 := CONSX(30 downto 11) - C1(30 downto 11) ;
C3 := C2 * B ;
C <= C3(34 downto 11) ;
end if ;
end process ;
-----------------------------------------------------------
-- 4th stage --
-----------------------------------------------------------
REVX_4TH : process( M, C )
variable D1 : std_logic_vector(39 downto 0); -- M(20bit)*C(20bit) XX.XX...
variable D2 : std_logic_vector(23 downto 0); -- 2-D1(24bit) X.XX...
variable D3 : std_logic_vector(43 downto 0); -- C(20bit)*D2(24bit) XXX.XX...
begin
if( C = "000000000000000000000000" ) then
D <= (others=>'0') ;
else
D1 := C(23 downto 4) * M ;
D2 := CONSX(30 downto 7) - D1(38 downto 15) ;
D3 := D2 * C(23 downto 4) ;
D <= D3(42 downto 19) ;
end if ;
end process ;
ZN <= N ;
--ZM <= A & "0000000000" ;
--ZM <= B & "0000" ;
--ZM <= C(23 downto 4) ;
ZM <= D(23 downto 4) ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// Title Reverse X (1/X) --
// File REVX.vhd --
// Entity REVX --
// rev date coded contents --
// 001 98/11/10 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module revx ( x, zn, zm );
input [19:0] x ;
output [4:0] zn ;
output [19:0] zm ;
reg [19:0] revx_1nd__b1;
reg [11:0] revx_1nd__b2;
reg [21:0] revx_1nd__b3;
reg [31:0] revx_3rd__c1;
reg [19:0] revx_3rd__c2;
reg [35:0] revx_3rd__c3;
reg [39:0] revx_4th__d1;
reg [23:0] revx_4th__d2;
reg [43:0] revx_4th__d3;
reg [9:0] a;
parameter [9:0] consa=10'b1100000000;
reg [15:0] b;
reg [23:0] c;
reg [23:0] d;
parameter [31:0] consx=32'b10000000000000000000000000000000;
reg [19:0] m;
reg [4:0] n;
wire [4:0] zn;
wire [19:0] zm;
always @ (x ) begin
if ((x[19:0] === 20'b00000000000000000000))
begin
m <= {(19-0+1- 0){1'b0}};
n <= {(4-0+1- 0){1'b0}};
end
else
begin
if ((x[19:1] === 19'b0000000000000000000))
begin
m <= {x[0],19'b0000000000000000000};
n <= 5'b00001;
end
else if ((x[19:2] === 18'b000000000000000000))
begin
m <= {x[1:0],18'b000000000000000000};
n <= 5'b00010;
end
else if ((x[19:3] === 17'b00000000000000000))
begin
m <= {x[2:0],17'b00000000000000000};
n <= 5'b00011;
end
else if ((x[19:4] === 16'b0000000000000000))
begin
m <= {x[3:0],16'b0000000000000000};
n <= 5'b00100;
end
else if ((x[19:5] === 15'b000000000000000))
begin
m <= {x[4:0],15'b000000000000000};
n <= 5'b00101;
end
else if ((x[19:6] === 14'b00000000000000))
begin
m <= {x[5:0],14'b00000000000000};
n <= 5'b00110;
end
else if ((x[19:7] === 13'b0000000000000))
begin
m <= {x[6:0],13'b0000000000000};
n <= 5'b00111;
end
else if ((x[19:8] === 12'b000000000000))
begin
m <= {x[7:0],12'b000000000000};
n <= 5'b01000;
end
else if ((x[19:9] === 11'b00000000000))
begin
m <= {x[8:0],11'b00000000000};
n <= 5'b01001;
end
else if ((x[19:10] === 10'b0000000000))
begin
m <= {x[9:0],10'b0000000000};
n <= 5'b01010;
end
else if ((x[19:11] === 9'b000000000))
begin
m <= {x[10:0],9'b000000000};
n <= 5'b01011;
end
else if ((x[19:12] === 8'b00000000))
begin
m <= {x[11:0],8'b00000000};
n <= 5'b01100;
end
else if ((x[19:13] === 7'b0000000))
begin
m <= {x[12:0],7'b0000000};
n <= 5'b01101;
end
else if ((x[19:14] === 6'b000000))
begin
m <= {x[13:0],6'b000000};
n <= 5'b01110;
end
else if ((x[19:15] === 5'b00000))
begin
m <= {x[14:0],5'b00000};
n <= 5'b01111;
end
else if ((x[19:16] === 4'b0000))
begin
m <= {x[15:0],4'b0000};
n <= 5'b10000;
end
else if ((x[19:17] === 3'b000))
begin
m <= {x[16:0],3'b000};
n <= 5'b10001;
end
else if ((x[19:18] === 2'b00))
begin
m <= {x[17:0],2'b00};
n <= 5'b10010;
end
else if ((x[19] === 1'b0))
begin
m <= {x[18:0],1'b0};
n <= 5'b10011;
end
else
begin
m <= x;
n <= 5'b10100;
end
end
end //always
always @ (m ) begin
if ((m === 20'b00000000000000000000))
a <= {(9-0+1- 0){1'b0}};
else
a <= (consa - {1'b0,m[19:11]});
end //always
always @ (m or a ) begin
if ((a === 10'b0000000000))
b <= {(15-0+1- 0){1'b0}};
else
begin
revx_1nd__b1 = (m[19:10] * a);
revx_1nd__b2 = (consx[30:19] - revx_1nd__b1[18:7]);
revx_1nd__b3 = (revx_1nd__b2 * a);
b <= revx_1nd__b3[20:5];
end
end //always
always @ (m or b ) begin
if ((b === 16'b0000000000000000))
c <= {(23-0+1- 0){1'b0}};
else
begin
revx_3rd__c1 = (b * m[19:4]);
revx_3rd__c2 = (consx[30:11] - revx_3rd__c1[30:11]);
revx_3rd__c3 = (revx_3rd__c2 * b);
c <= revx_3rd__c3[34:11];
end
end //always
always @ (m or c ) begin
if ((c === 24'b000000000000000000000000))
d <= {(23-0+1- 0){1'b0}};
else
begin
revx_4th__d1 = (c[23:4] * m);
revx_4th__d2 = (consx[30:7] - revx_4th__d1[38:15]);
revx_4th__d3 = (revx_4th__d2 * c[23:4]);
d <= revx_4th__d3[42:19];
end
end //always
assign {zn}=n;
assign {zm}=d[23:4];
endmodule
|
6)自然対数
Z = log(X) (但し X>0, X=0 の場合 Z=0) 正の整数 X 20 ビットの自然対数をとる回路 出力は固定小数点形式で整数部 4 ビット,小数部 16 ビット
------------------------------------------------------------------------
-- Title Logalizm X (log(X)) --
-- File LOG.vhd --
-- Entity LOG --
-- rev date coded contents --
-- 001 98/11/17 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all ;
use IEEE.std_logic_arith.all ;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity LOG is
port(
-- XXXXXXXXXXXXXXXXXXXX. Integer Value
X : in std_logic_vector(19 downto 0) ; -- Input(20bit)
-- XXXX.XXXXXXXXXXXXXXXX Fixed Point Value
Z : out std_logic_vector(19 downto 0) -- Output(20bit)
);
end LOG ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of LOG is
-- log(2)
-- .XXXXXXXXXXXXXXXX
constant LOG2V : std_logic_vector(15 downto 0) := "1011000101110010" ;
-- 1/2 = shift1
-- 1/3
constant CONS3 : std_logic_vector(15 downto 0) := "0101010101010101" ; -- 4bit
-- 1/4 = shift2
-- 1/5
-- 1/6 = 1/3&shift
-- 1/7
constant CONS5 : std_logic_vector(15 downto 0) := "0011001100110011" ; -- 7bit
constant CONS7 : std_logic_vector(15 downto 0) := "0010010010010010" ; -- 9bit
-- 1/8 = shift3
-- 1/9
-- 1/10 = 1/5&shift
-- 1/11
-- 1/12 = 1/3&shift2
-- 1/13
-- 1/14 = 1/7&shift2
-- 1/15
constant CONS9 : std_logic_vector(15 downto 0) := "0001110001110001" ; -- 11bit
constant CONS11 : std_logic_vector(15 downto 0) := "0001011101000101" ; -- 14bit
constant CONS13 : std_logic_vector(15 downto 0) := "0001001110110001" ; -- 16bit
constant CONS15 : std_logic_vector(15 downto 0) := "0001000100010001" ; -- 18bit
--
-- .XXXXXXXXXXXXXXXX
signal Y : std_logic_vector(15 downto 0) ; -- Log( M )
--
signal F : std_logic_vector(20 downto 0) ; -- N*log(2)
signal G : std_logic_vector(20 downto 0) ; -- temp Z
--
-- 0.XXXXXXXX
signal M : std_logic_vector(19 downto 0) ; -- Mantissa
signal N : std_logic_vector(4 downto 0) ; -- Expornent
begin
--------------------------------
-- Reverse X Argolizm (X>0)
--
-- X = m x 2^n (m = 0.5~0.999999)
-- m = 1-h
-- Z = log(2)*n+log(m)
-- log(2)*n-(h+h^2/2+h^3/3+h^4/4+ ....)
--
--------------------------------
-----------------------------------------------------------
-- Initialize --
-----------------------------------------------------------
FLOT_INIT : process( X )
begin
if( X(19 downto 0) = "00000000000000000000" ) then
M <= (others=>'0') ;
N <= (others=>'0') ;
else
-- Generate M,N
if( X(19 downto 1) = "0000000000000000000" ) then
M <= X(0) & "0000000000000000000" ;
N <= "00001" ;
elsif( X(19 downto 2) = "000000000000000000" ) then
M <= X(1 downto 0) & "000000000000000000" ;
N <= "00010" ;
elsif( X(19 downto 3) = "00000000000000000" ) then
M <= X(2 downto 0) & "00000000000000000" ;
N <= "00011" ;
elsif( X(19 downto 4) = "0000000000000000" ) then
M <= X(3 downto 0) & "0000000000000000" ;
N <= "00100" ;
elsif( X(19 downto 5) = "000000000000000" ) then
M <= X(4 downto 0) & "000000000000000" ;
N <= "00101" ;
elsif( X(19 downto 6) = "00000000000000" ) then
M <= X(5 downto 0) & "00000000000000" ;
N <= "00110" ;
elsif( X(19 downto 7) = "0000000000000" ) then
M <= X(6 downto 0) & "0000000000000" ;
N <= "00111" ;
elsif( X(19 downto 8) = "000000000000" ) then
M <= X(7 downto 0) & "000000000000" ;
N <= "01000" ;
elsif( X(19 downto 9) = "00000000000" ) then
M <= X(8 downto 0) & "00000000000" ;
N <= "01001" ;
elsif( X(19 downto 10) = "0000000000" ) then
M <= X(9 downto 0) & "0000000000" ;
N <= "01010" ;
elsif( X(19 downto 11) = "000000000" ) then
M <= X(10 downto 0) & "000000000" ;
N <= "01011" ;
elsif( X(19 downto 12) = "00000000" ) then
M <= X(11 downto 0) & "00000000" ;
N <= "01100" ;
elsif( X(19 downto 13) = "0000000" ) then
M <= X(12 downto 0) & "0000000" ;
N <= "01101" ;
elsif( X(19 downto 14) = "000000" ) then
M <= X(13 downto 0) & "000000" ;
N <= "01110" ;
elsif( X(19 downto 15) = "00000" ) then
M <= X(14 downto 0) & "00000" ;
N <= "01111" ;
elsif( X(19 downto 16) = "0000" ) then
M <= X(15 downto 0) & "0000" ;
N <= "10000" ;
elsif( X(19 downto 17) = "000" ) then
M <= X(16 downto 0) & "000" ;
N <= "10001" ;
elsif( X(19 downto 18) = "00" ) then
M <= X(17 downto 0) & "00" ;
N <= "10010" ;
elsif( X(19) = '0' ) then
M <= X(18 downto 0) & '0' ;
N <= "10011" ;
else
M <= X ;
N <= "10100" ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- logalizm calculate --
-----------------------------------------------------------
LOG_CONV : process( M )
variable TMP : std_logic_vector(19 downto 0); -- 1-m
variable H : std_logic_vector(15 downto 0); -- 1-m
variable B1 : std_logic_vector(15 downto 0); -- H
variable B2 : std_logic_vector(31 downto 0); -- H^2
variable B3 : std_logic_vector(31 downto 0); -- H^3
variable B4 : std_logic_vector(31 downto 0); -- H^4
variable B5 : std_logic_vector(31 downto 0); --
variable B6 : std_logic_vector(31 downto 0); --
variable B7 : std_logic_vector(31 downto 0); --
variable B8 : std_logic_vector(31 downto 0); --
variable B9 : std_logic_vector(31 downto 0); --
variable B10 : std_logic_vector(31 downto 0); --
variable B11 : std_logic_vector(31 downto 0); --
variable B12 : std_logic_vector(31 downto 0); --
variable B13 : std_logic_vector(31 downto 0); --
variable C1 : std_logic_vector(15 downto 0); -- H
variable C2 : std_logic_vector(15 downto 0); -- H^2
variable C3 : std_logic_vector(15 downto 0); -- H^3
variable C4 : std_logic_vector(15 downto 0); -- H^4
variable C5 : std_logic_vector(15 downto 0); --
variable C6 : std_logic_vector(15 downto 0); --
variable C7 : std_logic_vector(15 downto 0); --
variable C8 : std_logic_vector(15 downto 0); --
variable C9 : std_logic_vector(15 downto 0); --
variable C10 : std_logic_vector(15 downto 0); --
variable C11 : std_logic_vector(15 downto 0); --
variable C12 : std_logic_vector(15 downto 0); --
variable C13 : std_logic_vector(15 downto 0); --
variable D : std_logic_vector(15 downto 0); --
begin
if( M = "00000000000000000000" ) then
Y <= (others=>'0') ;
else
-- TMP = -M
TMP := "00000000000000000000" - M ;
H := TMP(19 downto 4) ;
-- BEKI
B1 := H ;
B2 := H*H ;
B3 := B2(31 downto 16)*H ;
B4 := B2(31 downto 16)*B2(31 downto 16) ;
B5 := B4(31 downto 16)*H ;
B6 := B4(31 downto 16)*B2(31 downto 16) ;
B7 := B4(31 downto 16)*B3(31 downto 16) ;
B8 := B4(31 downto 16)*B4(31 downto 16) ;
B9 := B8(31 downto 16)*H ;
B10 := B8(31 downto 16)*B2(31 downto 16) ;
B11 := B8(31 downto 16)*B3(31 downto 16) ;
B12 := B8(31 downto 16)*B4(31 downto 16) ;
B13 := B8(31 downto 16)*B5(31 downto 16) ;
-- KEISU
C1 := B1 ;
C2 := '0' & B2(31 downto 17) ;
B3 := B3(31 downto 16)*CONS3 ;
C3 := B3(31 downto 16) ;
C4 := "00" & B4(31 downto 18) ;
B5 := B5(31 downto 16)*CONS5 ;
C5 := B5(31 downto 16) ;
B6 := B6(31 downto 16)*CONS3 ;
C6 := '0' & B6(31 downto 17) ;
B7 := B7(31 downto 16)*CONS7 ;
C7 := B7(31 downto 16) ;
C8 := "000" & B8(31 downto 19) ;
B9 := B9(31 downto 16)*CONS9 ;
C9 := B9(31 downto 16) ;
B10 := B10(31 downto 16)*CONS5 ;
C10 := '0' & B10(31 downto 17) ;
B11 := B11(31 downto 16)*CONS11 ;
C11 := B11(31 downto 16) ;
B12 := B12(31 downto 16)*CONS3 ;
C12 := "00" & B12(31 downto 18) ;
B13 := B13(31 downto 16)*CONS13 ;
C13 := B13(31 downto 16) ;
-- KASAN
D := C1+C2+C3+C4+C5+C6+C7+C8+C9+C10+C11+C12+C13 ;
-- KEKKA
Y <= D ;
end if ;
end process ;
-----------------------------------------------------------
-- output calculate --
-----------------------------------------------------------
--Feb.14.2005 TAK
OUTPUT_CALC : process( M,G) -- N, Y )
begin
if( M = "00000000000000000000" ) then
Z <= (others=>'0') ;
else
-- F <= N * LOG2V ;
-- G <= F - ("00000" & Y) ;
Z <= G(19 downto 0) ;
end if ;
end process ;
F <= N * LOG2V ;
G <= F - ("00000" & Y) ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// Title Logalizm X (log(X)) --
// File LOG.vhd --
// Entity LOG --
// rev date coded contents --
// 001 98/11/17 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module log ( x, z );
input [19:0] x ;
output [19:0] z ;
reg [19:0] log_conv__tmp;
reg [15:0] log_conv__h;
reg [15:0] log_conv__b1;
reg [31:0] log_conv__b2;
reg [31:0] log_conv__b3;
reg [31:0] log_conv__b4;
reg [31:0] log_conv__b5;
reg [31:0] log_conv__b6;
reg [31:0] log_conv__b7;
reg [31:0] log_conv__b8;
reg [31:0] log_conv__b9;
reg [31:0] log_conv__b10;
reg [31:0] log_conv__b11;
reg [31:0] log_conv__b12;
reg [31:0] log_conv__b13;
reg [15:0] log_conv__c1;
reg [15:0] log_conv__c2;
reg [15:0] log_conv__c3;
reg [15:0] log_conv__c4;
reg [15:0] log_conv__c5;
reg [15:0] log_conv__c6;
reg [15:0] log_conv__c7;
reg [15:0] log_conv__c8;
reg [15:0] log_conv__c9;
reg [15:0] log_conv__c10;
reg [15:0] log_conv__c11;
reg [15:0] log_conv__c12;
reg [15:0] log_conv__c13;
reg [15:0] log_conv__d;
parameter [15:0] log2v=16'b1011000101110010;
parameter [15:0] cons3=16'b0101010101010101;
parameter [15:0] cons5=16'b0011001100110011;
parameter [15:0] cons7=16'b0010010010010010;
parameter [15:0] cons9=16'b0001110001110001;
parameter [15:0] cons11=16'b0001011101000101;
parameter [15:0] cons13=16'b0001001110110001;
parameter [15:0] cons15=16'b0001000100010001;
reg [15:0] y;
wire [20:0] f;
wire [20:0] g;
reg [19:0] m;
reg [4:0] n;
reg [19:0] z;
always @ (x ) begin
if ((x[19:0] === 20'b00000000000000000000))
begin
m <= {(19-0+1- 0){1'b0}};
n <= {(4-0+1- 0){1'b0}};
end
else
begin
if ((x[19:1] === 19'b0000000000000000000))
begin
m <= {x[0],19'b0000000000000000000};
n <= 5'b00001;
end
else if ((x[19:2] === 18'b000000000000000000))
begin
m <= {x[1:0],18'b000000000000000000};
n <= 5'b00010;
end
else if ((x[19:3] === 17'b00000000000000000))
begin
m <= {x[2:0],17'b00000000000000000};
n <= 5'b00011;
end
else if ((x[19:4] === 16'b0000000000000000))
begin
m <= {x[3:0],16'b0000000000000000};
n <= 5'b00100;
end
else if ((x[19:5] === 15'b000000000000000))
begin
m <= {x[4:0],15'b000000000000000};
n <= 5'b00101;
end
else if ((x[19:6] === 14'b00000000000000))
begin
m <= {x[5:0],14'b00000000000000};
n <= 5'b00110;
end
else if ((x[19:7] === 13'b0000000000000))
begin
m <= {x[6:0],13'b0000000000000};
n <= 5'b00111;
end
else if ((x[19:8] === 12'b000000000000))
begin
m <= {x[7:0],12'b000000000000};
n <= 5'b01000;
end
else if ((x[19:9] === 11'b00000000000))
begin
m <= {x[8:0],11'b00000000000};
n <= 5'b01001;
end
else if ((x[19:10] === 10'b0000000000))
begin
m <= {x[9:0],10'b0000000000};
n <= 5'b01010;
end
else if ((x[19:11] === 9'b000000000))
begin
m <= {x[10:0],9'b000000000};
n <= 5'b01011;
end
else if ((x[19:12] === 8'b00000000))
begin
m <= {x[11:0],8'b00000000};
n <= 5'b01100;
end
else if ((x[19:13] === 7'b0000000))
begin
m <= {x[12:0],7'b0000000};
n <= 5'b01101;
end
else if ((x[19:14] === 6'b000000))
begin
m <= {x[13:0],6'b000000};
n <= 5'b01110;
end
else if ((x[19:15] === 5'b00000))
begin
m <= {x[14:0],5'b00000};
n <= 5'b01111;
end
else if ((x[19:16] === 4'b0000))
begin
m <= {x[15:0],4'b0000};
n <= 5'b10000;
end
else if ((x[19:17] === 3'b000))
begin
m <= {x[16:0],3'b000};
n <= 5'b10001;
end
else if ((x[19:18] === 2'b00))
begin
m <= {x[17:0],2'b00};
n <= 5'b10010;
end
else if ((x[19] === 1'b0))
begin
m <= {x[18:0],1'b0};
n <= 5'b10011;
end
else
begin
m <= x;
n <= 5'b10100;
end
end
end //always
always @ (m ) begin
if ((m === 20'b00000000000000000000))
y <= {(15-0+1- 0){1'b0}};
else
begin
log_conv__tmp = (20'b00000000000000000000 - m);
log_conv__h = log_conv__tmp[19:4];
log_conv__b1 = log_conv__h;
log_conv__b2 = (log_conv__h * log_conv__h);
log_conv__b3 = (log_conv__b2[31:16] * log_conv__h);
log_conv__b4 = (log_conv__b2[31:16] * log_conv__b2[31:16]);
log_conv__b5 = (log_conv__b4[31:16] * log_conv__h);
log_conv__b6 = (log_conv__b4[31:16] * log_conv__b2[31:16]);
log_conv__b7 = (log_conv__b4[31:16] * log_conv__b3[31:16]);
log_conv__b8 = (log_conv__b4[31:16] * log_conv__b4[31:16]);
log_conv__b9 = (log_conv__b8[31:16] * log_conv__h);
log_conv__b10 = (log_conv__b8[31:16] * log_conv__b2[31:16]);
log_conv__b11 = (log_conv__b8[31:16] * log_conv__b3[31:16]);
log_conv__b12 = (log_conv__b8[31:16] * log_conv__b4[31:16]);
log_conv__b13 = (log_conv__b8[31:16] * log_conv__b5[31:16]);
log_conv__c1 = log_conv__b1;
log_conv__c2 = {1'b0,log_conv__b2[31:17]};
log_conv__b3 = (log_conv__b3[31:16] * cons3);
log_conv__c3 = log_conv__b3[31:16];
log_conv__c4 = {2'b00,log_conv__b4[31:18]};
log_conv__b5 = (log_conv__b5[31:16] * cons5);
log_conv__c5 = log_conv__b5[31:16];
log_conv__b6 = (log_conv__b6[31:16] * cons3);
log_conv__c6 = {1'b0,log_conv__b6[31:17]};
log_conv__b7 = (log_conv__b7[31:16] * cons7);
log_conv__c7 = log_conv__b7[31:16];
log_conv__c8 = {3'b000,log_conv__b8[31:19]};
log_conv__b9 = (log_conv__b9[31:16] * cons9);
log_conv__c9 = log_conv__b9[31:16];
log_conv__b10 = (log_conv__b10[31:16] * cons5);
log_conv__c10 = {1'b0,log_conv__b10[31:17]};
log_conv__b11 = (log_conv__b11[31:16] * cons11);
log_conv__c11 = log_conv__b11[31:16];
log_conv__b12 = (log_conv__b12[31:16] * cons3);
log_conv__c12 = {2'b00,log_conv__b12[31:18]};
log_conv__b13 = (log_conv__b13[31:16] * cons13);
log_conv__c13 = log_conv__b13[31:16];
log_conv__d = ((((((((((((log_conv__c1 + log_conv__c2) + log_conv__c3) + log_conv__c4) + log_conv__c5) + log_conv__c6) + log_conv__c7) + log_conv__c8) + log_conv__c9) + log_conv__c10) + log_conv__c11) + log_conv__c12) + log_conv__c13);
y <= log_conv__d;
end
end //always
always @ (m or g ) begin
if ((m === 20'b00000000000000000000))
z <= {(19-0+1- 0){1'b0}};
else
z <= g[19:0];
end //always
assign {f}=(n * log2v);
assign {g}=(f - {5'b00000,y});
endmodule
|
7)Cordic
sin,cos,atan(y/x)の計算を行います。
テストベンチです。signedを使って素直に書けます。
//Feb.13.2005
//Feb.15.2005
//Tak.Sugawara
module cordic_bench_test;
parameter cos_sin_mode=1'b0,atan_mode=1'b1;
parameter integer bit_precision=10;//11 fails
parameter integer atan_precision=11;//12 fails
parameter integer precision=bit_precision;//
parameter real allowable_error=1.0/(2**precision);
parameter real allowable_error_atan=1.0/(2**atan_precision);
parameter integer scale_power=14;//bit
parameter integer scale=2**scale_power;//16384
parameter real max_test_angle_degree=91;//max of 100 degree
reg [15:0] in_x=0 ;
reg [15:0] in_y=0 ;
reg signed [15:0] in_angle=0 ;
reg in_start=0;
reg in_mode=cos_sin_mode;
reg clk=0;
reg enable=0;
reg xrst=0;
wire out_finish;
wire signed [15:0] out_x ;
wire signed [15:0] out_y ;
wire signed [15:0] out_z ;
//
real in_angle_r;
real max_in_angle_r;//
real hard_sin,hard_cos;//
real max_angle_r;
real h_sin_limit,l_sin_limit;
real h_cos_limit,l_cos_limit;
integer i;
real work,work1;
real x_r,y_r,hard_z,angle_z;
always #10 clk=~clk;
cordic dut ( in_x, in_y, in_angle, in_start, in_mode, clk, enable, xrst, out_finish, out_x, out_y, out_z );
initial begin
//sin/cos test
//test 0->90degree
repeat(2) @(posedge clk);
@(negedge clk);
xrst=1;
in_start=1;
enable=1;
begin :for_loop1
for (i=0; 1;i=i+1) begin
in_angle=i;
@(negedge clk) in_start=0;
repeat(3) @(negedge clk);
wait (out_finish);//wait hardware calculation
in_angle_r=$itor(in_angle)/$itor(scale);
hard_sin=$itor(out_y)/$itor(scale);
hard_cos=$itor(out_x)/$itor(scale);
work=$sin(in_angle_r);
work1=allowable_error;
h_sin_limit=$sin(in_angle_r)+allowable_error;//evaluate as output-bit-precision
l_sin_limit=$sin(in_angle_r)-allowable_error;
h_cos_limit=$cos(in_angle_r)+allowable_error;
l_cos_limit=$cos(in_angle_r)-allowable_error;
if (h_sin_limit < hard_sin)begin
$display("sin max error detected %g %g",h_sin_limit,hard_sin);
$stop;
end
if (l_sin_limit > hard_sin) begin
$display("sin min error detected %g %g",l_sin_limit,hard_sin);
end
if (h_cos_limit < hard_cos)begin
$display("cos max error detected %g %g",h_cos_limit,hard_sin);
$stop;
end
if (l_cos_limit > hard_cos) begin
$display("cos min error detected %g %g",l_cos_limit,hard_sin);
end
if (i%1000==0)
$display("i=%d in_angle_r=%g sin=%g hadware_result=%g",i,in_angle_r,$sin(in_angle_r),hard_sin);
max_angle_r=max_test_angle_degree/180.*$M_PI;
if (max_angle_r < in_angle_r) disable for_loop1;//exit test loop
@(negedge clk) in_start=1;
end
end //for loop
//test 0->-90degree
@(negedge clk);
in_start=1;
enable=1;
begin :for_loop2
for (i=0; 1;i=i+1) begin
in_angle=-i;
@(negedge clk) in_start=0;
repeat(3) @(negedge clk);
wait (out_finish);//wait hardware calculation
in_angle_r=$itor(in_angle)/$itor(scale);
hard_sin=$itor(out_y)/$itor(scale);
hard_cos=$itor(out_x)/$itor(scale);
work=$sin(in_angle_r);
work1=allowable_error;
h_sin_limit=$sin(in_angle_r)+allowable_error;//evaluate as output-bit-precision
l_sin_limit=$sin(in_angle_r)-allowable_error;
h_cos_limit=$cos(in_angle_r)+allowable_error;
l_cos_limit=$cos(in_angle_r)-allowable_error;
if (h_sin_limit < hard_sin)begin
$display("sin max error detected %g %g",h_sin_limit,hard_sin);
$stop;
end
if (l_sin_limit > hard_sin) begin
$display("sin min error detected %g %g",l_sin_limit,hard_sin);
end
if (h_cos_limit < hard_cos)begin
$display("cos max error detected %g %g",h_cos_limit,hard_sin);
$stop;
end
if (l_cos_limit > hard_cos) begin
$display("cos min error detected %g %g",l_cos_limit,hard_sin);
end
if (i%1000==0)
$display("i=%d in_angle_r=%g sin=%g hadware_result=%g",i,in_angle_r,$sin(in_angle_r),hard_sin);
max_angle_r=max_test_angle_degree/180.*$M_PI;
if (-max_angle_r > in_angle_r) disable for_loop2;//exit test loop
@(negedge clk) in_start=1;
end
end //for loop
$display("Cordic sin/cos test passed");
//atan (y/x)
//test scheme
// 1>=x>0 assuming x**2+y**2=1 y=sqrt(1-xx*2);
//
xrst=0;
repeat(2) @(negedge clk);
@(negedge clk);
in_start=1;
enable=1;
xrst=1;
in_mode=atan_mode;
for (i=0;i<= scale;i=i+1) begin
in_x=i;//Start, with given in_x and in_y
x_r=$itor(i)/scale;
work=1.0-x_r**2;
y_r=$sqrt(work);
work1=y_r*scale;
in_y=$rtoi(work1);
@(negedge clk) in_start=0;//deassert _instart
repeat(3) @(negedge clk);
wait (out_finish);//wait hardware calculation
@(negedge clk);
hard_z=$itor(out_z)/scale;//get hardware result.
if (i==0) angle_z=$M_PI/2.0;
else if (i==scale) angle_z=0.0;
else angle_z=$atan(y_r/x_r);
if (hard_z > angle_z+allowable_error_atan) begin
$display("Error Detected atan max");
$stop;//assert(0);
end
if (hard_z < angle_z-allowable_error_atan) begin
$display("Error Detected atan min");
$stop;//assert(0);
end
@(negedge clk) in_start=1;
end
$display("atan(y/x) test passed");
$finish;
end
endmodule
|
実行結果です。
F:\vhdl 演算\cordic_test.v(4)::cordic_bench_test
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------
i= 0 in_angle_r=0 sin=0 hadware_result=0.000244141
i= 1000 in_angle_r=0.0610352 sin=0.0609973 hadware_result=0.0609131
i= 2000 in_angle_r=0.12207 sin=0.121767 hadware_result=0.121948
i= 3000 in_angle_r=0.183105 sin=0.182084 hadware_result=0.18219
i= 4000 in_angle_r=0.244141 sin=0.241723 hadware_result=0.241943
i= 5000 in_angle_r=0.305176 sin=0.300461 hadware_result=0.300415
i= 6000 in_angle_r=0.366211 sin=0.35808 hadware_result=0.357971
i= 7000 in_angle_r=0.427246 sin=0.414366 hadware_result=0.414246
i= 8000 in_angle_r=0.488281 sin=0.469109 hadware_result=0.469177
i= 9000 in_angle_r=0.549316 sin=0.522104 hadware_result=0.521973
i= 10000 in_angle_r=0.610352 sin=0.573156 hadware_result=0.573181
i= 11000 in_angle_r=0.671387 sin=0.622072 hadware_result=0.622009
i= 12000 in_angle_r=0.732422 sin=0.668672 hadware_result=0.668701
i= 13000 in_angle_r=0.793457 sin=0.712782 hadware_result=0.712769
i= 14000 in_angle_r=0.854492 sin=0.754238 hadware_result=0.754395
i= 15000 in_angle_r=0.915527 sin=0.792884 hadware_result=0.79303
i= 16000 in_angle_r=0.976563 sin=0.828578 hadware_result=0.828491
i= 17000 in_angle_r=1.0376 sin=0.861186 hadware_result=0.861328
i= 18000 in_angle_r=1.09863 sin=0.890586 hadware_result=0.890686
i= 19000 in_angle_r=1.15967 sin=0.91667 hadware_result=0.91687
i= 20000 in_angle_r=1.2207 sin=0.939341 hadware_result=0.93927
i= 21000 in_angle_r=1.28174 sin=0.958513 hadware_result=0.958435
i= 22000 in_angle_r=1.34277 sin=0.974115 hadware_result=0.974121
i= 23000 in_angle_r=1.40381 sin=0.98609 hadware_result=0.986145
i= 24000 in_angle_r=1.46484 sin=0.994392 hadware_result=0.994324
i= 25000 in_angle_r=1.52588 sin=0.998991 hadware_result=0.999023
i= 26000 in_angle_r=1.58691 sin=0.99987 hadware_result=0.999573
i= 0 in_angle_r=0 sin=0 hadware_result=0.000244141
i= 1000 in_angle_r=-0.0610352 sin=-0.0609973 hadware_result=-0.0606689
i= 2000 in_angle_r=-0.12207 sin=-0.121767 hadware_result=-0.121582
i= 3000 in_angle_r=-0.183105 sin=-0.182084 hadware_result=-0.181946
i= 4000 in_angle_r=-0.244141 sin=-0.241723 hadware_result=-0.241943
i= 5000 in_angle_r=-0.305176 sin=-0.300461 hadware_result=-0.300415
i= 6000 in_angle_r=-0.366211 sin=-0.35808 hadware_result=-0.358032
i= 7000 in_angle_r=-0.427246 sin=-0.414366 hadware_result=-0.414307
i= 8000 in_angle_r=-0.488281 sin=-0.469109 hadware_result=-0.468872
i= 9000 in_angle_r=-0.549316 sin=-0.522104 hadware_result=-0.52179
i= 10000 in_angle_r=-0.610352 sin=-0.573156 hadware_result=-0.573181
i= 11000 in_angle_r=-0.671387 sin=-0.622072 hadware_result=-0.622009
i= 12000 in_angle_r=-0.732422 sin=-0.668672 hadware_result=-0.668701
i= 13000 in_angle_r=-0.793457 sin=-0.712782 hadware_result=-0.712769
i= 14000 in_angle_r=-0.854492 sin=-0.754238 hadware_result=-0.754395
i= 15000 in_angle_r=-0.915527 sin=-0.792884 hadware_result=-0.792908
i= 16000 in_angle_r=-0.976563 sin=-0.828578 hadware_result=-0.828369
i= 17000 in_angle_r=-1.0376 sin=-0.861186 hadware_result=-0.861206
i= 18000 in_angle_r=-1.09863 sin=-0.890586 hadware_result=-0.890564
i= 19000 in_angle_r=-1.15967 sin=-0.91667 hadware_result=-0.91687
i= 20000 in_angle_r=-1.2207 sin=-0.939341 hadware_result=-0.93927
i= 21000 in_angle_r=-1.28174 sin=-0.958513 hadware_result=-0.958435
i= 22000 in_angle_r=-1.34277 sin=-0.974115 hadware_result=-0.974121
i= 23000 in_angle_r=-1.40381 sin=-0.98609 hadware_result=-0.986023
i= 24000 in_angle_r=-1.46484 sin=-0.994392 hadware_result=-0.994324
i= 25000 in_angle_r=-1.52588 sin=-0.998991 hadware_result=-0.999023
i= 26000 in_angle_r=-1.58691 sin=-0.99987 hadware_result=-0.999451
Cordic sin/cos test passed
atan(y/x) test passed
Info: $finishコマンドを実行します。time=24962940
|
オリジナルソースとトランスレート後です。
------------------------------------------------------------------------
-- Title CORDIC calculater sin(x), cos(x), atan(y/x) --
-- File CORDIC.vhd --
-- Entity CORDIC --
-- rev date coded contents --
-- 001 99/01/06 ueno Make Original --
------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
--use IEEE.std_logic_signed.all ;
--use IEEE.std_logic_arith.all ;
------------------------------------------------------------------------
-- entity --
------------------------------------------------------------------------
entity CORDIC is
port(
-- Input/Output Data format = Fixed Point Value
-- range -1.99994 to 1.99994 2's complement
-- 15 14 . 13 12 11 10 09 08 07 06 05 04 03 02 01 00
-- Sign ^point
--
IN_X : in std_logic_vector(15 downto 0) ; -- atan(y/X) -0.15 to 1.00
IN_Y : in std_logic_vector(15 downto 0) ; -- atan(Y/x) -1.00 to 1.00
IN_ANGLE : in std_logic_vector(15 downto 0) ; -- angle(thita) -1.74 to 1.74
IN_START : in std_logic ; -- convert start
IN_MODE : in std_logic ; -- 1=atan/0=sin,cos
CLK : in std_logic ; -- System Clock
ENABLE : in std_logic ; -- Clock Enable
XRST : in std_logic ; -- Reset
OUT_FINISH : out std_logic ; -- Convert end
OUT_X : out std_logic_vector(15 downto 0) ; -- Calculate X
OUT_Y : out std_logic_vector(15 downto 0) ; -- Calculate Y
OUT_Z : out std_logic_vector(15 downto 0) -- Calculate Z
);
end CORDIC ;
------------------------------------------------------------------------
-- architecture --
------------------------------------------------------------------------
architecture RTL of CORDIC is
--constant ENABLE : std_logic := '1' ;
-----------------------------------------------------------
-- Constants --
-----------------------------------------------------------
constant VAL0 : std_logic_vector(15 downto 0) := "0000000000000000" ; -- 0.000000000
constant VALX : std_logic_vector(15 downto 0) := "0010011011011101" ; -- 0.607252935
constant ATAN00 : std_logic_vector(15 downto 0) := "0011001001000100" ; -- atan(1/1)
constant ATAN01 : std_logic_vector(15 downto 0) := "0001110110101100" ; -- atan(1/2)
constant ATAN02 : std_logic_vector(15 downto 0) := "0000111110101110" ; -- atan(1/4)
constant ATAN03 : std_logic_vector(15 downto 0) := "0000011111110101" ; -- atan(1/8)
constant ATAN04 : std_logic_vector(15 downto 0) := "0000001111111111" ; -- atan(1/16)
constant ATAN05 : std_logic_vector(15 downto 0) := "0000001000000000" ; -- atan(1/32)
constant ATAN06 : std_logic_vector(15 downto 0) := "0000000100000000" ; -- atan(1/64)
constant ATAN07 : std_logic_vector(15 downto 0) := "0000000010000000" ; -- atan(1/128)
constant ATAN08 : std_logic_vector(15 downto 0) := "0000000001000000" ; -- atan(1/256)
constant ATAN09 : std_logic_vector(15 downto 0) := "0000000000100000" ; -- atan(1/512)
constant ATAN10 : std_logic_vector(15 downto 0) := "0000000000010000" ; -- atan(1/1024)
constant ATAN11 : std_logic_vector(15 downto 0) := "0000000000001000" ; -- atan(1/2048)
constant ATAN12 : std_logic_vector(15 downto 0) := "0000000000000100" ; -- atan(1/4096)
constant ATAN13 : std_logic_vector(15 downto 0) := "0000000000000010" ; -- atan(1/8192)
constant ATAN14 : std_logic_vector(15 downto 0) := "0000000000000001" ; -- atan(1/16384)
constant ATAN15 : std_logic_vector(15 downto 0) := "0000000000000000" ; -- atan(1/32768)
-----------------------------------------------------------
-- Signals --
-----------------------------------------------------------
signal REG_X : std_logic_vector(15 downto 0) ; -- Xn Register
signal REG_Y : std_logic_vector(15 downto 0) ; -- Yn Register
signal REG_Z : std_logic_vector(15 downto 0) ; -- Zn Register
signal REG_J : std_logic_vector(3 downto 0) ; -- 0 to 15 counter
signal AX : std_logic_vector(15 downto 0) ; -- Ballel Shift X
signal BX : std_logic_vector(15 downto 0) ; -- Ballel Shift X
signal CX : std_logic_vector(15 downto 0) ; -- Ballel Shift X
signal DX : std_logic_vector(15 downto 0) ; -- Ballel Shift X
signal AY : std_logic_vector(15 downto 0) ; -- Ballel Shift Y
signal BY : std_logic_vector(15 downto 0) ; -- Ballel Shift Y
signal CY : std_logic_vector(15 downto 0) ; -- Ballel Shift Y
signal DY : std_logic_vector(15 downto 0) ; -- Ballel Shift Y
signal TAB_Z : std_logic_vector(15 downto 0) ; -- Table Select Z
signal INIT_LOAD : std_logic ; -- X,Y,Z Initialize
signal NOW_CONVERT : std_logic ; -- Now Conveting for CORDIC
signal ADD_SUB : std_logic ; -- Next Calculate '1'=ADD/'0'=SUB
-----------------------------------------------------------
-- Architectures --
-----------------------------------------------------------
begin
-----------------------------------------------------------
-- Flag Control --
-----------------------------------------------------------
INIT_FLAG : process( CLK, XRST )
begin
if( XRST='0' ) then
INIT_LOAD <= '0' ;
elsif( CLK'event and CLK='1' ) then
if( ENABLE='1' ) then
if( IN_START='1' and INIT_LOAD='0' and NOW_CONVERT='0' ) then
INIT_LOAD <= '1' ;
else
INIT_LOAD <= '0' ;
end if ;
end if ;
end if ;
end process ;
CONVERT_FLAG : process( CLK, XRST )
begin
if( XRST='0' ) then
NOW_CONVERT <= '0' ;
elsif( CLK'event and CLK='1' ) then
if( ENABLE='1' ) then
if( INIT_LOAD='1' ) then
NOW_CONVERT <= '1' ;
elsif( REG_J="1111" ) then
NOW_CONVERT <= '0' ;
end if ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- Sequence Counter --
-----------------------------------------------------------
COUNTER_GEN : process( CLK, XRST )
begin
if( XRST='0' ) then
REG_J <= "0000" ;
elsif( CLK'event and CLK='1' ) then
if( ENABLE='1' ) then
if( NOW_CONVERT='1' ) then
REG_J <= REG_J + 1 ;
end if ;
end if ;
end if ;
end process ;
-----------------------------------------------------------
-- ADD/SUB Flag --
-----------------------------------------------------------
SELECT_ADD_SUB : ADD_SUB <= not REG_Y(15) when IN_MODE='1' else REG_Z(15) ;
-----------------------------------------------------------
-- Ballel Shifter --
-----------------------------------------------------------
BALLEL_AX : process( REG_X, REG_J )
begin
if( REG_J(3)='1' ) then
AX <= REG_X(15) & REG_X(15) & REG_X(15) & REG_X(15) & REG_X(15) & REG_X(15) & REG_X(15) & REG_X(15) & REG_X(15 downto 8);
else
AX <= REG_X ;
end if ;
end process ;
BALLEL_BX : process( AX, REG_J )
begin
if( REG_J(2)='1' ) then
BX <= AX(15) & AX(15) & AX(15) & AX(15) & AX(15 downto 4);
else
BX <= AX ;
end if ;
end process ;
BALLEL_CX : process( BX, REG_J )
begin
if( REG_J(1)='1' ) then
CX <= BX(15) & BX(15) & BX(15 downto 2);
else
CX <= BX ;
end if ;
end process ;
BALLEL_DX : process( CX, REG_J )
begin
if( REG_J(0)='1' ) then
DX <= CX(15) & CX(15 downto 1);
else
DX <= CX ;
end if ;
end process ;
BALLEL_AY : process( REG_Y, REG_J )
begin
if( REG_J(3)='1' ) then
AY <= REG_Y(15) & REG_Y(15) & REG_Y(15) & REG_Y(15) & REG_Y(15) & REG_Y(15) & REG_Y(15) & REG_Y(15) & REG_Y(15 downto 8);
else
AY <= REG_Y ;
end if ;
end process ;
BALLEL_BY : process( AY, REG_J )
begin
if( REG_J(2)='1' ) then
BY <= AY(15) & AY(15) & AY(15) & AY(15) & AY(15 downto 4);
else
BY <= AY ;
end if ;
end process ;
BALLEL_CY : process( BY, REG_J )
begin
if( REG_J(1)='1' ) then
CY <= BY(15) & BY(15) & BY(15 downto 2);
else
CY <= BY ;
end if ;
end process ;
BALLEL_DY : process( CY, REG_J )
begin
if( REG_J(0)='1' ) then
DY <= CY(15) & CY(15 downto 1);
else
DY <= CY ;
end if ;
end process ;
TABLE_Z : process( REG_J )
begin
case REG_J is
when "0000" => TAB_Z <= ATAN00 ;
when "0001" => TAB_Z <= ATAN01 ;
when "0010" => TAB_Z <= ATAN02 ;
when "0011" => TAB_Z <= ATAN03 ;
when "0100" => TAB_Z <= ATAN04 ;
when "0101" => TAB_Z <= ATAN05 ;
when "0110" => TAB_Z <= ATAN06 ;
when "0111" => TAB_Z <= ATAN07 ;
when "1000" => TAB_Z <= ATAN08 ;
when "1001" => TAB_Z <= ATAN09 ;
when "1010" => TAB_Z <= ATAN10 ;
when "1011" => TAB_Z <= ATAN11 ;
when "1100" => TAB_Z <= ATAN12 ;
when "1101" => TAB_Z <= ATAN13 ;
when "1110" => TAB_Z <= ATAN14 ;
when "1111" => TAB_Z <= ATAN15 ;
when others => TAB_Z <= VAL0 ;
end case ;
end process ;
-----------------------------------------------------------
-- Calculate --
-----------------------------------------------------------
CALC_X : process( CLK, XRST )
begin
if( XRST='0') then
REG_X <= (others=>'0') ;
elsif( CLK'event and CLK='1' ) then
if( ENABLE='1' ) then
-- Initial Value
if( INIT_LOAD = '1' ) then
if( IN_MODE='1' ) then
-- Atan Mode
REG_X <= IN_X ;
else
-- Sin/Cos Mode
REG_X <= VALX ;
end if ;
elsif( NOW_CONVERT='1' ) then
if( ADD_SUB='1' ) then
REG_X <= REG_X + DY ;
else
REG_X <= REG_X - DY ;
end if ;
end if ;
end if ;
end if ;
end process ;
CALC_Y : process( CLK, XRST )
begin
if( XRST='0') then
REG_Y <= (others=>'0') ;
elsif( CLK'event and CLK='1' ) then
if( ENABLE='1' ) then
-- Initial Value
if( INIT_LOAD = '1' ) then
if( IN_MODE='1' ) then
-- Atan Mode
REG_Y <= IN_Y ;
else
-- Sin/Cos Mode
REG_Y <= VAL0 ;
end if ;
elsif( NOW_CONVERT='1' ) then
if( ADD_SUB='1' ) then
REG_Y <= REG_Y - DX ;
else
REG_Y <= REG_Y + DX ;
end if ;
end if ;
end if ;
end if ;
end process ;
CALC_Z : process( CLK, XRST )
begin
if( XRST='0') then
REG_Z <= (others=>'0') ;
elsif( CLK'event and CLK='1' ) then
if( ENABLE='1' ) then
-- Initial Value
if( INIT_LOAD = '1' ) then
if( IN_MODE='1' ) then
-- Atan Mode
REG_Z <= VAL0 ;
else
-- Sin/Cos Mode
REG_Z <= IN_ANGLE ;
end if ;
elsif( NOW_CONVERT='1' ) then
if( ADD_SUB='1' ) then
REG_Z <= REG_Z + TAB_Z ;
else
REG_Z <= REG_Z - TAB_Z ;
end if ;
end if ;
end if ;
end if ;
end process ;
OUT_FINISH <= not NOW_CONVERT ;
OUT_X <= REG_X ;
OUT_Y <= REG_Y ;
OUT_Z <= REG_Z ;
end RTL ;
------------------------------------------------------------------------
-- End of File --
------------------------------------------------------------------------
|
//-------------------------------------------------------------------
//
// This file is automatically generated by VHDL to Verilog Translator.
// Ver.1.08 Build Mar.6.2004
// www.sugawara-systems.com
// tech-support@sugawara-systems.com
// See Original Copyright Notice for property of the file .( somewhere in this file.)
//
//--------------------------------------------------------------------
//----------------------------------------------------------------------
// Title CORDIC calculater sin(x), cos(x), atan(y/x) --
// File CORDIC.vhd --
// Entity CORDIC --
// rev date coded contents --
// 001 99/01/06 ueno Make Original --
//----------------------------------------------------------------------
`timescale 1ns/1ns
`define ns 1
`define us (1000*`ns)
`define ms (1000*`us)
`define sec (1000*`ms)
module cordic ( in_x, in_y, in_angle, in_start, in_mode, clk, enable, xrst, out_finish, out_x, out_y, out_z );
input [15:0] in_x ;
input [15:0] in_y ;
input [15:0] in_angle ;
input in_start;
input in_mode;
input clk;
input enable;
input xrst;
output out_finish;
output [15:0] out_x ;
output [15:0] out_y ;
output [15:0] out_z ;
parameter [15:0] val0=16'b0000000000000000;
parameter [15:0] valx=16'b0010011011011101;
parameter [15:0] atan00=16'b0011001001000100;
parameter [15:0] atan01=16'b0001110110101100;
parameter [15:0] atan02=16'b0000111110101110;
parameter [15:0] atan03=16'b0000011111110101;
parameter [15:0] atan04=16'b0000001111111111;
parameter [15:0] atan05=16'b0000001000000000;
parameter [15:0] atan06=16'b0000000100000000;
parameter [15:0] atan07=16'b0000000010000000;
parameter [15:0] atan08=16'b0000000001000000;
parameter [15:0] atan09=16'b0000000000100000;
parameter [15:0] atan10=16'b0000000000010000;
parameter [15:0] atan11=16'b0000000000001000;
parameter [15:0] atan12=16'b0000000000000100;
parameter [15:0] atan13=16'b0000000000000010;
parameter [15:0] atan14=16'b0000000000000001;
parameter [15:0] atan15=16'b0000000000000000;
reg [15:0] reg_x;
reg [15:0] reg_y;
reg [15:0] reg_z;
reg [3:0] reg_j;
reg [15:0] ax;
reg [15:0] bx;
reg [15:0] cx;
reg [15:0] dx;
reg [15:0] ay;
reg [15:0] by;
reg [15:0] cy;
reg [15:0] dy;
reg [15:0] tab_z;
reg init_load;
reg now_convert;
wire add_sub;
wire out_finish;
wire [15:0] out_x;
wire [15:0] out_y;
wire [15:0] out_z;
always @ (posedge clk or negedge xrst ) begin
if ((xrst === 1'b0))
init_load <= 1'b0;
else
begin
if ((enable === 1'b1))
begin
if ((((in_start === 1'b1) & (init_load === 1'b0)) & (now_convert === 1'b0)))
init_load <= 1'b1;
else
init_load <= 1'b0;
end
end
end //always
always @ (posedge clk or negedge xrst ) begin
if ((xrst === 1'b0))
now_convert <= 1'b0;
else
begin
if ((enable === 1'b1))
begin
if ((init_load === 1'b1))
now_convert <= 1'b1;
else if ((reg_j === 4'b1111))
now_convert <= 1'b0;
end
end
end //always
always @ (posedge clk or negedge xrst ) begin
if ((xrst === 1'b0))
reg_j <= 4'b0000;
else
begin
if ((enable === 1'b1))
begin
if ((now_convert === 1'b1))
reg_j <= (reg_j + 1);
end
end
end //always
assign {add_sub}=(in_mode === 1'b1) ?
~ (reg_y[15])
: reg_z[15];
always @ (reg_x or reg_j ) begin
if ((reg_j[3] === 1'b1))
ax <= {{{{{{{{reg_x[15],reg_x[15]},reg_x[15]},reg_x[15]},reg_x[15]},reg_x[15]},reg_x[15]},reg_x[15]},reg_x[15:8]};
else
ax <= reg_x;
end //always
always @ (ax or reg_j ) begin
if ((reg_j[2] === 1'b1))
bx <= {{{{ax[15],ax[15]},ax[15]},ax[15]},ax[15:4]};
else
bx <= ax;
end //always
always @ (bx or reg_j ) begin
if ((reg_j[1] === 1'b1))
cx <= {{bx[15],bx[15]},bx[15:2]};
else
cx <= bx;
end //always
always @ (cx or reg_j ) begin
if ((reg_j[0] === 1'b1))
dx <= {cx[15],cx[15:1]};
else
dx <= cx;
end //always
always @ (reg_y or reg_j ) begin
if ((reg_j[3] === 1'b1))
ay <= {{{{{{{{reg_y[15],reg_y[15]},reg_y[15]},reg_y[15]},reg_y[15]},reg_y[15]},reg_y[15]},reg_y[15]},reg_y[15:8]};
else
ay <= reg_y;
end //always
always @ (ay or reg_j ) begin
if ((reg_j[2] === 1'b1))
by <= {{{{ay[15],ay[15]},ay[15]},ay[15]},ay[15:4]};
else
by <= ay;
end //always
always @ (by or reg_j ) begin
if ((reg_j[1] === 1'b1))
cy <= {{by[15],by[15]},by[15:2]};
else
cy <= by;
end //always
always @ (cy or reg_j ) begin
if ((reg_j[0] === 1'b1))
dy <= {cy[15],cy[15:1]};
else
dy <= cy;
end //always
always @ (reg_j ) begin
case (reg_j)
4'b0000 :
tab_z <= 16'b0011001001000100;
4'b0001 :
tab_z <= 16'b0001110110101100;
4'b0010 :
tab_z <= 16'b0000111110101110;
4'b0011 :
tab_z <= 16'b0000011111110101;
4'b0100 :
tab_z <= 16'b0000001111111111;
4'b0101 :
tab_z <= 16'b0000001000000000;
4'b0110 :
tab_z <= 16'b0000000100000000;
4'b0111 :
tab_z <= 16'b0000000010000000;
4'b1000 :
tab_z <= 16'b0000000001000000;
4'b1001 :
tab_z <= 16'b0000000000100000;
4'b1010 :
tab_z <= 16'b0000000000010000;
4'b1011 :
tab_z <= 16'b0000000000001000;
4'b1100 :
tab_z <= 16'b0000000000000100;
4'b1101 :
tab_z <= 16'b0000000000000010;
4'b1110 :
tab_z <= 16'b0000000000000001;
4'b1111 :
tab_z <= 16'b0000000000000000;
default :
tab_z <= 16'b0000000000000000;
endcase
end //always
always @ (posedge clk or negedge xrst ) begin
if ((xrst === 1'b0))
reg_x <= {(15-0+1- 0){1'b0}};
else
begin
if ((enable === 1'b1))
begin
if ((init_load === 1'b1))
begin
if ((in_mode === 1'b1))
reg_x <= in_x;
else
reg_x <= 16'b0010011011011101;
end
else if ((now_convert === 1'b1))
begin
if ((add_sub === 1'b1))
reg_x <= (reg_x + dy);
else
reg_x <= (reg_x - dy);
end
end
end
end //always
always @ (posedge clk or negedge xrst ) begin
if ((xrst === 1'b0))
reg_y <= {(15-0+1- 0){1'b0}};
else
begin
if ((enable === 1'b1))
begin
if ((init_load === 1'b1))
begin
if ((in_mode === 1'b1))
reg_y <= in_y;
else
reg_y <= 16'b0000000000000000;
end
else if ((now_convert === 1'b1))
begin
if ((add_sub === 1'b1))
reg_y <= (reg_y - dx);
else
reg_y <= (reg_y + dx);
end
end
end
end //always
always @ (posedge clk or negedge xrst ) begin
if ((xrst === 1'b0))
reg_z <= {(15-0+1- 0){1'b0}};
else
begin
if ((enable === 1'b1))
begin
if ((init_load === 1'b1))
begin
if ((in_mode === 1'b1))
reg_z <= 16'b0000000000000000;
else
reg_z <= in_angle;
end
else if ((now_convert === 1'b1))
begin
if ((add_sub === 1'b1))
reg_z <= (reg_z + tab_z);
else
reg_z <= (reg_z - tab_z);
end
end
end
end //always
assign {out_finish}=~ (now_convert);
assign {out_x}=reg_x;
assign {out_y}=reg_y;
assign {out_z}=reg_z;
endmodule
|
下記計画中の以下のプロジェクトは、現在休止しています。
.マイクロプログラムによるパターンジェネレータ
マイクロプログラムは、高度な順序制御器としての側面をもっています。
CPUでは遅すぎるし、ステートマシンでは複雑すぎる制御に好適です。意外と知られていないのでとりあげることにします。応用例としてパターンジェネレータを設計してみます。
.誤り訂正
CRCやビタビ、リードソロモン等のECCコアを設計してみます。また、YACCプロジェクトで、ガロア体ALUと演算命令を追加したYACCプロセッサでもC言語で記述してみます。
.サーボ制御
現代制御理論によるサーボ制御をVeritakシミュレータ上で実装制御してみます。ロボット制御等に使われる制御理論の基礎をとりあげます。
.DPLL
デジタルPLLについてとりあげます。
ソフトライブラリ( 9,10)
算術ライブラリ
Verilog2001のVPI(PLI Version2.0)を使ってCのMathライブラリを呼び出しました。Verilogと外部言語とIFするには、Cまたは、C++でDLLを作ってやるのが簡単です。この例では、C++で簡単に記述してみました。
Verilog2001になって従来のPLIは、保守扱いになっていますのでこれからVerilogとのIFを他の言語で書こうとする場合は、VPIをお勧めします。
ところが、VPIは、シミュレータの内部状態を極限まで制御できるようになっていて、汎用的な反面、抽象的でわかりずらい面があると思います。ソースのコメントを参考に雰囲気をつかんでいただけたら、と思います。
なお、本ライブラリは、Veritak Version1.02よりmath_vpi.dllとしてインストールパッケージに追加されています。
10.Verilogでアナログシミュレート?
PLL/サーボ系を含んだシステムでは、Verilogコーディング前にMatlabもしくはクローン、もしくはC/C++でシステムシミュレーションをするのが普通です。その後、デザインの最終段階であるVerilogではどうしているでしょうか?
LSIはデジタルでも現実の周辺は、アナログフィルタ、DCモータやVCM,あるいはOPAMPといったアナログで動く場合もあるでしょう。
Verilogですべてをモデリングすることも不可能ではないですが、シミュレーション効率から言って、あまり得策とは言えません。
(特にVeritakの場合、内部がインタプリタコードで、REALの実装もBITVECTORと同じ4値にしてしまっているのでREALが多いとシミュレーションスピードとメモリ効率が低下してしまいます。)
こんなときは、軽めのアナログシミュレータが使えると便利です。そこで、これもVPIを使って線形システムのシュミレータを実装してみました。
シミュレータは、状態空間型の行列を定義したテキストファイルを読み込んで、毎クロック$runge_kutta(..)で呼び出します。引数にREAL型アレーを記述してIFします。
SPICEのように非線形素子は扱えませんが、アナログフィルタの時間応答を見るとか、サーボ系の動作検証といった用途には使えると思います。また、VPIのサンプルとしてもよい例になっていると思います。
筆者の処理系は、VC7C++ですが、__int64をlong longとすれば、GCC系でもコンパイルできると思います。
なお、本ライブラリは、Veritak Version1.02よりmath_vpi.dllとしてインストールパッケージに追加されています。(Jan.6.2005
update)
VeriPad
Veritakに付属しているテキストエディタでVC++ソースです。オリジナルは、NYSLライセンスのGreenPadです。
Veritakとの連携を取るべく筆者がブレークポイント、ツールチップ、タグジャンプ、その他Veritak とのIFをGreenPadに追加し勝手にVeriPadとしてしましました。 その気のある方は、究極のカスタマイズが可能です。
オリジナルは、Super Tiny記述になっていて、EXEサイズが50KBという極小サイズを実現していましたが、筆者がSTLを使ってしまい普通のサイズになってしまいました。
好みのEditorのスクリプト等を使って、VeriPadもどきを実現したい方は、Windows通信のIFであるGpMain.cppから見てゆけばよいでしょう。
VeriPadソースのダウンロード(1MB) Jul.11.2005版
Release Note:
- Veritak Version 1.70Aに対応しています。
- オリジナルからの追加部には、”TAK”でコメントしています。
|
|