7.データ型
7.1 レキシカルトークン
 トークンは、次の種別に分けられます。トークンとは、一文字以上のキャラクタからなる文字列です。通常コンパイラは、トークン単位で、構文解析します。

White space 文字通りホワイトスペースです。
Comment //は、VHDLの-- と同じです。/* Comment  */ はCに同じです。
Operator +-*/の他 << >> 等、色々あります。
Number 数字です。
String ” ” で囲まれた文字セットです。
Identifier 識別子 たとえば reg a; のaは識別子です。
Keyword たとえば、module、reg、です。

7.2数字
<number> ::= <DECIMAL_NUMBER>
||= <UNSIGNED_NUMBER>? <BASE> <UNSIGNED_NUMBER>
||= <DECIMAL_NUMBER>.<UNSIGNED_NUMBER>
||= <DECIMAL_NUMBER><.<UNSIGNED_NUMBER>>? E<DECIMAL_NUMBER>
||= <DECIMAL_NUMBER><.<UNSIGNED_NUMBER>>? e<DECIMAL_NUMBER>


*上記の他、Verilog2001では、符号付の拡張がなされています。

Verilogの基本データ型は、2番目です。即ち、最初にビット幅があって基数、その後が実際の定数を表します。ビット幅指定はオプションですが、できるだけビット幅は、明示するような癖をつけましょう。ビット幅が不定だと、ビット幅がOperationで一致しないときの拡張の仕方が違いますし、連接演算でもエラーになります。

<例>  
  659 //は10進で659です。ベースがない数字は、符号付(32ビット以上、実装依存)になります。
  ’h 837FF // は16進で837ffです。
  ’o7460 //は8進です。
  4af // は、エラーです。16進のつもりなら’hが必要です。
  4’b1001 //は、4ビットの2進表現です。
  5 ’D 3 // は、5ビット幅の10進で3です。
  3’b01x //は、3ビット幅でLSBがxです。
  12’hx // は12ビット幅のx(不定)です。
  16’hz // は、16ビット幅のz(ハイインピーダンス)です。
  8 ’d -6 //これはエラーです。-6はUNSIGNED_NUMBERではありません。
 -8 ’d 6 //8ビット幅の10進6の2の補数,
  4 ’shf // sが付いてVerilog2001仕様で、符号付4ビット1111を表します。o
 -4 ’sd15 // sが付いてVerilgo2001仕様で、符号付を表します。
.
  reg [11:0] a, b, c, d;
    initial begin
      a = ’h x; // aは、12'hxxxになります。
      b = ’h 3x; //bは、12'h03xになります。
      c = ’h z3; //cは12'hzz3になります。ビット幅不定だと0拡張されるとは限りません。この場合、zが拡張されます。
      d = ’h 0z3; //dは12'h0z3になります。
    end

   reg [84:0] e, f, g;
   e = 'h5; // は、 {82{1'b0},3'b101}になります。
   f = 'hx; // は、 {85{1'hx}}になります。
   g = 'hz; //は、 {85{1'hz}}になります。

//次の例は、_を入れてよい例です。VHDLと違い何個いれてもOKです。
   27_195_000
   16’b0011_0101_0001_1111
   32 ’h 12ab_f001
   27_195_000
   16’b0011_0101_0001_1111
   32 ’h 12ab_f001

7.3Data Types
値の種類は、次の4種類です。

不定状態を表す。Variable型のシミュレーション開始時の初期値は、xになる。(ただし、REAL/REALTIMEは、0.0に初期化される。)
ハイインピーダンス、ドライブされていないフローティング状態を表す。Net型の初期値は、シミュレーション開始時初期値はzになる。


7.4 Net型とvariable型

Verilogで使える型は、大きく分けてVariable型(reg型)とNet型があります。
Variable型は、Initial/Always中のLHSに使用することができる、記憶のある型です。一方Net型は、記憶がなく値を保持しません。(triregを除いて)従って物理的な接続のモデリングに使います。また、継続代入文のLHSに使用できます。

TYPE 種類
NET wire tri tri0 supply0
wand triand tri1 supply1
wor trior trireg
Variable reg integer time real realtime

(Veritakでは、triregをサポートしていません。)


7.4.1 NET型
NET型は、いろいろありますが、通常、殆どwireしか使いません。

wire とtriの文法的、意味的違いはありません。モデリング用途でのユーザ側の便宜の為に名前を分けています。wireは、一般にsingle drive、triは、multiple drive とされていますが、シミュレータ上では、区別がない為、multiple drive でも、wireでかまいません。

真理値表は下です。ドライバが、*/xなら、xが勝ち、0/1ならxになり、 01/zなら01が勝ち、誰もドライブしていないとき(zz)は、zになります。zが一番弱いです。

wire/tri 0 1 x z
0 0 x x 0
1 x 1 x 1
x x x x x
z 0 1 x z

wor/triorは、ワイヤードOR専用のNETです。違いはありません。wireと違うのは、1が強力になっていることです。

wor/trior 0 1 x z
0 0 x 0
1 1 1
x x x x
z 0 1 x z

wor/triorは、ワイヤードOR専用のNETです。違いはありません。wireと違うのは、0が強力になっていることです。

wand/triand 0 1 x z
0 0 0 0 0
1 0 1 x 1
x 0 x x x
z 0 1 x z

tri1,tri0は、pullup,pulldown付きのNETを現します。

tri0のwireとの違いは、zzが0になることです。

tri0 0 1 x z
0 0 x x 0
1 x 1 x 1
x x x x x
z 0 1 x 0

tri1のwireとの違いは、zzが1になることです。

tri0 0 1 x z
0 0 x x 0
1 x 1 x 1
x x x x x
z 0 1 x 1

supply0,supply1 は、その名の通り電源です。何をつないでも0は0、1は1です。

7.4.2 Variable型

符号 初期値 ビット幅 ビット・パートセレクト
reg signedが付かないとunsigned扱い [:]宣言がないと1ビット OK
integer signed 処理系依存、少なくとも32ビット。LSBは0 OK
time unsigned 処理系依存、少なくとも64ビット。LSBは0 OK
real/realtime signed 0.0 C言語のdouble相当の精度 NG

Note:

慣例的にintegerは、ハードウェアのモデリング以外に使われます。(for ループのインデックス変数など)
浮動小数点から整数への暗黙変換は、四捨五入です。ただし、$reatobitsは、切捨てになっています。

7.5 Array

例です。

reg [7:0] mema[0:255]; //8ビット幅256wordsメモリ
reg [7:0] memb[7:0][0:255]; //8ビット幅のマルチアレー
wire [7:0] w_array[7:0][5:0]; //wire宣言でのマルチアレー 
integer inta[1:64]; // integer 配列
time chng_hist[1:1000]; // time 配列
real rmem [0:100][1:100];//real の2次元メモリ

Arrayの場合、Element幅以下になるまで指定してやらないとエラーになります。

mema = 0; //NG 全体を指定してもだめ
memb[1] = 0; //NG 足りない
memb[1][12:31] = 0; //NG 
mema[1] = 0; //OK
memb[1][0] = 0; //OK
inta[4] = 33559; //OK
chng_hist[t_index] = $time; //OK
rmem[100]=0.1; //NG
rmem[100][1]=0.1;//OK


なお、次の例は、regとメモリが別物の例です。

reg [1:n] rega; //これと
reg mema [1:n]; //これは、別物です。


--内部実装の話ですが、メモリの場合は、アクセスを限定することで、不用意なメモリ消費を抑えているとも言えます。例えば、32MB のメモリ記述があったとして、always @(mem) という記述が許されたとすると、シミュレータのメモリは、破綻してしまいます。全メモリセルの変化をWatchしなければいけないからです。そこで、always @(i) data=mem[i]; と書かせれば、(現実のメモリもそういうアクセスしか許されません。)i という変数の変化だけをWatchしておけばよいことになりシミュレータのメモリの消費を抑えられます。実際、メモリとregの内部実装は、全く異なるclassで書いています。

7.5 parameter
parameter は、variable 型でもNet型でもありません。実行時は、定数です。コンパイル時は、モジュールインスタンス化の際に変更することができます。(パラメータオーバライド) defparamで変えることもできますが、(筆者の意見ですが、)Verilog2001では、推奨しません。 逆に、インスタンス化の際の、パラメータオーバライドは、ある程度規模が大きくなってくると必須の手法だと思います。なお、parameterの宣言について、Verilog2001LRMのBNFは、間違っています。(パーサを書いていたら矛盾に気づきました。)Verilog3.1aでは、修正されているのでそちらをご参照ください。

 例です。

parameter msb = 7; //定数7を定義します。
parameter e = 25, f = 9; //リストにすることもできます。
parameter [3:0] a=4'b000,b=4'b0001,c=4'b0010;//レンジ付きのリストにする事も出来ます。RHSに係わりなく4ビット幅になります。
parameter r = 5.7; //rはrealになります。
parameter real rr=5; //real を明示することもできます。rr=5.0になります。
parameter integer ip=5;//integer を明示することもできます。
parameter integer iip=func(ip);//constant function を呼ぶこともできます。
parameter byte_size = 8,byte_mask = byte_size - 1;
parameter average_delay = (r + f) / 2;
parameter signed [3:0] mux_selector = 0;//RHSに関係なく符号付になります。
parameter [31:0] dec_const = 1’b1; //32ビットレンジになります。
parameter newconst = 3’h4; //3ビットレンジになります。
parameter newconst = 4; //少なくとも32ビットレンジになります。


localparamについて
上記例を localparmと置き換えても全く同じです。違うのは、パラメータオーバライドとdefparamが利かない(変更できない)ことです。parameterと使い分けることで、可読性の向上につながるでしょう。

parameterに関して、少し長い例を挙げます。使い方の参考になるかと思います。ハードウェア設計において、Speedと演算語長はトレードオフの関係にあります。COST/SPEEDの両観点から、最適な演算語長は、最終の論理合成をしてみるまで判断がつかない場合があります。そのような場合は、あらかじめparameter 化しておいて、インスタンス化の際に指定できるようにしておきます。そうすると簡単に、後から演算語長を変えられる(パラメタライズ)訳です。
また、ファイル名をパラメータにするのもBlackBox化に有効な手段です。 同じだけどちょっとだけ違うといったときには、違うところをparameterで吸収するのがよいでしょう。

//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