VHDLのgenericとconstantとfunction
VHDLでgenericのパラメータを使うことはよくあると思いますが、与えられたパラメータを加工してバスのビット幅にしたりする際に、条件判断が必要な式が必要になることがあります。
例えば、ADコンバータのAD9633(12bit)、AD9253(14bit)、AD9653(16bit)を使い分けるようなデザインを作りたい場合です。
データ出力のビット幅は、genericを使って、
entity adcblock is Generic ( ADC_BITS : integer range 0 to 16 := 12); Port ( adc_data_o : std_logic_vector(ADC_BITS-1 downto 0); ・・・・
と、可変長にできます。
もちろん、信号の宣言のところでは
signal adc_data : std_logic_vector(ADC_BITS-1 downto 0);
と、Genericで与えられたADC_BITSは自由に使えます。
問題は、このパラメータを、加減乗除だけではなく複雑な演算に使ったりしたい場合です。
AD9633などのADCはシリアルでデータを送ってくるので、ISERDESを使ってパラレルに変換しなければなりません。AD9633は6bitのシリアル2本で、AD9653は8bitのシリアル2本でデータを送ってきます。しかし、困ったことにAD9253は14bitのデータに"00"を詰めて8bit 2本に拡張して送ってきます。
ISERDESのビット幅は6,8,8なので、ADC_BITS/2とするわけにもいきません。
こんなときには、functionを使います。
VHDLのfunctionの文法はなかなか覚えにくいので、ここに例を書いておきます。
architecture Behavioral of adcblock is function GET_SERDEC_WIDTH (BITS : in integer ) return integer is variable temp : integer range 0 to 16; begin temp := 12; if(BITS = 12) then temp := 12; end if; if(BITS = 14) then temp := 16; end if; if(BITS = 16) then temp := 16; end if; return temp; end GET_SERDEC_WIDTH;
constant SERDEC_WIDTH : integer range 0 to 18 := GET_SERDEC_WIDTH(ADC_BITS);
つまり、SERDEC_WIDTHという変数を作りたいのですが、この変数をGET_SERDEC_WIDTHというfunctionで計算しているわけです。
functionはbeginの前、つまり、定数やsignalを定義する場所でも使えますので、こういう使い方ができます。
他に、ISERDESのためのクロック倍率を作るところでは、
function GET_MULT (BITS : in integer ) return real is
variable temp : real range 0.0 to 16.0;
begin
temp := 6.0;
if(ADC_BITS = 14) then temp := 8.0; end if;
if(ADC_BITS = 16) then temp := 8.0; end if;
return temp;
end GET_MULT;
constant BAIRITSU : real range 0.0 to 16.0 := GET_MULT(ADC_BITS);
としています。こうしてintegerからrealを作って、
mmcm_adv_inst : MMCME2_ADV generic map (BANDWIDTH => "OPTIMIZED", CLKOUT4_CASCADE => FALSE, COMPENSATION => "ZHOLD", STARTUP_WAIT => FALSE, DIVCLK_DIVIDE => 1, CLKFBOUT_MULT_F => BAIRITSU, CLKFBOUT_PHASE => 0.000, CLKFBOUT_USE_FINE_PS => FALSE, CLKOUT0_DIVIDE_F => BAIRITSU, CLKOUT0_PHASE => 0.000, CLKOUT0_DUTY_CYCLE => 0.500, CLKOUT0_USE_FINE_PS => FALSE, CLKOUT1_DIVIDE => 1, CLKOUT1_PHASE => 0.000, CLKOUT1_DUTY_CYCLE => 0.500, CLKOUT1_USE_FINE_PS => FALSE, CLKIN1_PERIOD => 10.000, REF_JITTER1 => 0.010) port map
・・・
このようにして使っています。
※VHDLでのrealは必ず小数点を付けなければならないようで、0.0のように書きます。
実際に、Cosmo-Zでやってみました。
AD9633(12bit)のADCのときのヒストグラム(AD変換結果のばらつき)は、
このように1LSB程度です。12bitの変換値は、ピタッと止まっていると言えます。
※緑のところが太いのはアナログフロントエンドの違いです。
AD9253(14bit)にすると、若干、広がりがでてきます。
ADCの分解能が4倍になったので、3LSBくらいの広がりが出ても不思議ではありません。事実、高速・高分解能ADCの変換値は常に揺れ動いています。
最近のコメント