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
|