« Cosmo-Zのデータ形式 | トップページ | 基板チョコレートを作りました! »

2017.01.26

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変換結果のばらつき)は、

Csz12bit_hist

このように1LSB程度です。12bitの変換値は、ピタッと止まっていると言えます。

緑のところが太いのはアナログフロントエンドの違いです。

AD9253(14bit)にすると、若干、広がりがでてきます。

Csz14bit_hist

拡大すると、

Csz14bit_hist_mag

ADCの分解能が4倍になったので、3LSBくらいの広がりが出ても不思議ではありません。事実、高速・高分解能ADCの変換値は常に揺れ動いています。

|

« Cosmo-Zのデータ形式 | トップページ | 基板チョコレートを作りました! »

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



« Cosmo-Zのデータ形式 | トップページ | 基板チョコレートを作りました! »