Welcome to Our Company
Home
Tutorial
Download
Opencores
F.A.Q.
Support
Purchase
Links

Information

このページでは、当社で開発した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
y2 y3 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 項目 仕様 単位 備考
Clock周波数 300 MHz Spartan3 限界?
Carrior周波数 75 MHz 4x Oversampling
Modulation Index 0.3 Bluetooth
BT 0.5 Bluetooth
転送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 項目 仕様 単位 備考
Clock周波数 200 MHz Sartan3 RAMのSpeedより
Carrior周波数 50 MHz 4x Oversampling
Modulation Index 0.3 Bluetooth
BT 0.5 Bluetooth
転送Rate 3.3 Mbps 50*0.01*2/0.3
Demodulator Slice数 100以下 乗算器2個は、専用。Demodulatorは、276MHzで動く能力
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 項目 仕様 単位 備考
Clock周波数 T.B.D. MHz Sartan3 RAMのSpeedより
Carrior周波数 T.B.D. MHz 1x Oversampling
Modulation Index 0.3 Bluetooth
BT 0.5 Bluetooth
転送Rate T.B.D. Mbps T.B.D.*0.01*2/0.3
Demodulator Slice数 80以下 乗算器2個は、専用。
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 項目 仕様 単位 備考
Clock周波数 50 MHz Sartan3 RAMのSpeedより
Carrior周波数 150 MHz 1x Oversampling
Modulation Index 0.3 Bluetooth
BT 0.5 Bluetooth
情報転送Rate 10 Mbps 150*0.01*2/0.3
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”でコメントしています。