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種類です。
0 | |
1 | |
x | 不定状態を表す。Variable型のシミュレーション開始時の初期値は、xになる。(ただし、REAL/REALTIMEは、0.0に初期化される。) |
z | ハイインピーダンス、ドライブされていないフローティング状態を表す。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 | 1 | x | 0 |
1 | 1 | 1 | 1 | 1 |
x | x | 1 | 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扱い | x | [:]宣言がないと1ビット | OK |
integer | signed | x | 処理系依存、少なくとも32ビット。LSBは0 | OK |
time | unsigned | x | 処理系依存、少なくとも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 |