ラベル verilog の投稿を表示しています。 すべての投稿を表示
ラベル verilog の投稿を表示しています。 すべての投稿を表示

2023年7月2日日曜日

verilog : SystemVerilog での記述

目的:

SystemVerilog で 追加された 合成可能な論理記述について記す

概要:

追加された項目としては、主に以下の様なものがある。
  1. .<ポート名> や .* による ポート宣言
  2. 数値記述
    1. bit幅の省略
    2. 可変長リテラル
  3. logic 変数
  4. 用途別 always 文
  5. 多次元配列
  6. enum
  7. typedef
  8. 構造体(struct)
  9. その他
  10. 共用体(union)
    interface
    package
    $clog2(), $bits()
    キャスティング

詳細:

  1. .<ポート名> や .* による ポート宣言
  2. モジュール呼び出し時、ポート名とネット名が同じ場合は .<ポート名> で接続できる。
    また。ポート名も .* で 省略できる。

    .<ポート名>での 宣言 (ネット名を省略)
    module1 i_module1 (
      .rst,
      .clk,
      .sig1,
      .sig2,
      .sig3(signal_3)
    ) ;
    sig3以外はネット名を省略。
    .* での 宣言 ( ポート名を省略 )
    module1 i_module1 (
      .*,
      .sig3(signal_3)
    ) ;
    sig3以外は * で省略。
    どちらも、sig3 以外は ネット名 と ポート名が同じ 場合に使用できる。
    但し、.* での接続は 回路記述では 推奨されないらしい。

  3. 数値記述
    1. bit幅の省略
    2. 'd30 の様に bit幅 を省略して記述できる。
      例えば、bit幅を P_BW のようにパラメータとした場合に '1' を設定する場合、
      data <= {{(P_BW-1){1'b0}},1'b1}
      の様にして bit幅を合わせて数値を記述/代入していたが、
      data <= 'd1 ;
      で良いとのこと。
      * Verilog では bit幅を省略すると 32bit とみなされ、合成はできるが spyglass 等のチェックで Warning が発生する。

    3. 可変長リテラル
    4. '0 や '1 で all '0' や all '1' を 表す。
      例えば、bit幅を P_BW とした場合に all '1' を設定する場合、
      data <= '1 ;
      で良い。

  4. logic 変数
  5. reg , wire の代わりに logic で宣言可能。
    (全て logic 宣言で良い。assign文, always文 のどちらにも使用できる。)
    但し、以下のwire の 様な 宣言と同時に代入を行うことはできない。
    wire  signal_1 = signal_2 ; <-- OK
    logic signal_1 = signal_2 ; <-- NG
    尚、icarus, vivado では コンパイル時にはエラーにならないが、シミュレーションでは代入されていない。
    会社で使用している環境ではコンパイル時にエラーになった。

  6. 用途別 always 文
  7. always文 を always_ff, always_comb,  always_latch で使い分けることができるようになった。
    1. always_ff
      always 文 で 順序回路(FF) を作る場合に使用する。
      従来の always での 順序回路記述と同様。
    2. always_comb
      always 文 で 組み合わせ回路 を作る場合に使用する。
      以下の様に、センシビリティリストは不要。
      always_comb
        if  (a)  dt = b ;
        else     dt = c ;
      Verilog の always @(*) と同様。
      case 文, if文 等で、条件を網羅していない場合は、ラッチが生成される。
    3. always_latch
      ラッチ生成用。詳細不明。

  8. 多次元配列
    1. unpacked の 多次元配列
      以下の記述は、Verilog でも 内部信号(メモリ等)には使用できたが、Systemverilog では ポートにも使用可能。
      [7:0] data[0:3] ;
      SystemVerilog では 以下の様に記述することも可能。
      [7:0] data[4] ;
      但し、unpacked の場合、data[0] ~ data[3] は 連続空間ではない為、以下の様に 32bit のデータを代入することはできない。
      wire [7:0] data [0:3] ;
      wire [31:0] data2 ;
      assign data = data2 ;  <--- NG
    2. packed の 多次元配列
      SystemVerilog では 以下の様に記述すると packed となる。
      [3:0][7:0] data :
      この場合、data[3] ~ data[0] は 連続空間となり、以下の様に 32bit幅のデータを assign することが可能。
      wire [31:0] data2 ;
      assign data = data2 ;
    3. 高次元配列
      以下の様な 3次元以上の配列も可能。
      [15:0][11:0][3:0][7:0] data : // 4次元配列の場合

  9. enum
  10. 列挙(enumeration)型。
    値を名前で定義できる。
    例 : ステートマシンの ステート定義
    enum logic [1:0] {STATE_0, STATE_1, STATE_3, STATE_4} state ;
    この場合、記述した名前に左から順に0から値が振られる。
    ( STATE_0=2'd0, STATE_1=2'd1, STATE_3=2'd2, STATE_4=2'd3 )
    値を指定したい場合は、
    enum logic [1:0] {STATE_0='d3, STATE_1='d2, STATE_3='d1, STATE_4='d0} state ;
    の様に指定する。
    同様のことを verilog で行う場合、以下の様に parameter で 値を 名前 に定義する。
    wire [1:0] state ;
    parameter STATE_0 = 2'd0 ;
    parameter STATE_1 = 2'd1 ;
    parameter STATE_2 = 2'd2 ;
    parameter STATE_3 = 2'd3 ;
    尚、enum から logic 等 への 代入はできるが、logic から enum への 代入は できない。( 但し、icarus では 代入できる )

  11. typedef
  12. データのタイプ名を新たに定義することができる。
    例えば、
    typedef enum logic [1:0] {ST_0,ST_1,ST_2,ST_3} t_stat ;
    t_stat stat ;
    t_stat next_stat ;
    の様に使用できる。

  13. 構造体(struct)
  14. 構造体
    以下の様に、複数の信号を 1つの名前に纏めることができる。
    struct {
      logic        we   ;
      logic [ 7:0] adr  ;
      logic [15:0] data ;
    } bus_sig ;
    struct にも packed と unpacked があり、指定しなければ unpacked となる。
    以下の様に packed と した場合、struct に 値を代入できる。
    struct packed {
      logic        we   ;
      logic [ 7:0] adr  ;
      logic [15:0] data ;
    } bus_sig ;

    assign bus_sig = 'h1234567 ;
    この場合、
       bus_sig.we   = 'b1
      bus_sib.adr  = 'h23
      bus_sib_data = 'h4567
    が入る。

  15. その他
  16. その他、
    • 共用体(union)
    • interface
    • package
    • $clog2(), $bits()
    • キャスティング
    等があるが、詳細は未調査。

2023年6月23日金曜日

verilog : Icarus verilog のオプション

目的:

Icarus Verilog での コンパイル時の オプションを 記す。

オプション:

オプションとして以下の様なものがある。
(詳細は、 こちら を参照。)

-o <File名> : 出力ファイル(コンパイルしたファイル)の名前を指定する。
(デフォルト は a.out)

-c <File名> : コマンドファイルを指定する。
(ソースファイル(テストベンチ,rtl等)のリスト等)

-I <Path> : インクルードファイルが存在するディレクトリを指定する。
-g <Flag> : verilog のバージョンを指定する。
バージョンは 1995, 2001, 2005, 2009, 2012 等。
-g 2012 で SystemVerilog に対応。

-s <Top module> : トップモジュールを明示的に指定する。
デフォルトではどのモジュールからも呼び出されていないものがトップと認識される。

-W <警告クラス> : どの警告(ワーニング)を出すかを指定。
-W all ですべてのワーニングがレポートされる。
警告クラスには以下の様なものがある。
anachronisms, implicit, implicit-dimensions
macro-replacement, portbind, select-range
timescale, sensitivity-entire-array

-v : 冗長指定。
著作権情報、進行状況メッセージ、各コンパイル段階のタイミング情報等を出力。

-V : バージョン情報を出力。
-V 時、コンパイルはスキップする。

例:

コンパイル

iverilog -o tst.o -c filelist.txt -g 2001 

ファイルリスト ( filelist.txt )

// test bench
testbench/testbench.sv

// rtl list
rtl/tst_module.v
rtl/tst_submod1.v
rtl/tst_submod2.v

2022年12月13日火曜日

verilog : Vivado (GUI) メモ

目的:

Vivado (GUI) でのシミュレーション 時のメモ を記す。
 ( 随時更新予定 )

TIPS:

  1.  シミュレーション実行手順
    Vivado GUI でのシミュレーション手順」参照

  2. 回路図表示
    左側にある「Flow Navigator」の
    RTL ANALYSYS
     Open Elaborated Design
      Schmatic
    を選択すると、RTL が どのような回路図になるかを確認できる。

  3. RTL を SystemVerilog として 扱う
    Sources ウインドウ の Design Sourdes にある RTL  を右クリック し、
    「Set File Type」を選択する。
    Set Type のウインドウが開くため、 File type を SystemVerilog に変更する。
    再シミュレーションを行うと、SystemVerilog として シミュレーションできる。




2022年11月26日土曜日

verilog : ビットシフト の記述

目的:

ビットシフトの記述の仕方について 記す

記述の仕方:

図のようなビットシフトを行う場合、次の様な記述の仕方がある。
  1. シフト演算子でシフト
    シフト演算子 ( << や >> ) を用いてシフトを行う。
  2. シフトした信号を定義してセレクト
    1bit づつシフトした信号を定義し、シフト量に応じて選択する。

通常は、シフト演算子でビットシフトを行う。
但し、下図の様に シフト量+元データ長 が シフト結果 のデータ長より長い場合、lintチェック等で Warning が 報告される。
はみ出した分は捨てられるのみで、合成は正常にできる為問題は無いが、Warning を減らしたい場合は 2. の記述をする。

また、下図の様に 元データ以外が '0' でない場合も 2. の記述で対応できる。


記述例:

シフトするデータを dat[2:0] (3bit), シフト結果を sft_data[7:0] (8bit),
シフト量を sft[3:0] (4bit) とし、左シフトする場合の記述例を示す。

  1. シフト演算子でシフト
    assign sft_data = dat << sft ;
  2. シフトした信号を定義してセレクト
    // シフトした信号の定義
    wire [7:0] sft_dt[0:8] ;
    assign sft_dt[0] = { 5'd0, dat } ;
    assign sft_dt[1] = { 4'd0, dat, 1'd0 } ;
    assign sft_dt[2] = { 3'd0, dat, 2'd0 } ;
    assign sft_dt[3] = { 2'd0, dat, 3'd0 } ;
    assign sft_dt[4] = { 1'd0, dat, 4'd0 } ;
    assign sft_dt[5] = { dat, 5'd0 } ;
    assign sft_dt[6] = { dat[1:0], 6'd0 } ;
    assign sft_dt[7] = { dat[0], 7'd0 } ;
    assign sft_dt[8] = 8'd0 ;
    // ビットシフト
    assign sft_data = (sft < 8) sft_dt[sft] : sft_dt[8] ;

各データ長をパラメータ化した場合の 2. の記述例を以下に示す。
 ( 1. の場合は パラメータ化しても 変わらない )

// パラメータ定義
parameter P_DT_BW    = 8 ;    // 元データ ビット幅
parameter P_SFTDT_BW = 128 ;  // シフト結果データ ビット幅
parameter P_SFT_BW   = 8 ;    // シフト量 ビット幅 (MAX 256)

// 各データの定義
wire [P_DT_BW-1:0]    dat ;      // 元データ
wire [P_SFTDT_BW-1:0] sft_data ; // シフト後のデータ
wire [P_SFT_BW-1:0]   sft ;      // シフト量

// シフトした信号の定義
wire  [P_SFTDT_BW-1:0]  sft_dt[0:P_SFTDT_BW]     ;
genvar i ;
generate
  for(i=0;i<P_SFTDT_BW-P_DT_BW;i=i+1) begin
    assign sft_dt[i] =
            {{(P_SFTDT_BW-P_DT_BW-i){1'b0}},dat,{(i){1'b0}}}  ;
  end
  for(i=0;i<P_DT_BW;i=i+1) begin
    assign sft_dt[P_SFTDT_BW-P_DT_BW+i] =
            {dat[P_DT_BW-i-1:0],{(P_SFTDT_BW-(P_DT_BW-i)){1'b0}}} ;
  end
  assign sft_dt[P_SFTDT_BW] = {(P_SFTDT_BW){1'b0}} ;
endgenerate
assign sft_data = (sft < P_SFTDT_BW) ? sft_dt[sft] :
                                       sft_dt[P_SFTDT_BW]  ;

元データ以外が base_data の場合 (パラメータ化)
// パラメータ定義
parameter P_DT_BW    = 8 ;    // 元データ ビット幅
parameter P_SFTDT_BW = 128 ;  // シフト結果データ ビット幅
parameter P_SFT_BW   = 8 ;    // シフト量 ビット幅 (MAX 256)

// 各データの定義
wire [P_DT_BW-1:0]    dat ;       // 元データ
wire [P_SFTDT_BW-1:0] sft_data ;  // シフト後のデータ
wire [P_SFTDT_BW-1:0] base_data ; // base_data
wire [P_SFT_BW-1:0]   sft ;       // シフト量

// シフトした信号の定義
wire  [P_SFTDT_BW-1:0]  sft_dt[0:P_SFTDT_BW]     ;
genvar i ;
generate
  assign sft_dt[0] = {base_data[P_SFTDT_BW-1:P_DT_BW], dat}  ;
  for(i=1;i<P_SFTDT_BW-P_DT_BW;i=i+1) begin
    assign sft_dt[i] =
             {base_data[P_SFTDT_BW1:P_DT_BW+i], dat, base_data[i-1:0]} ;
  end
  for(i=0;i<P_DT_BW;i=i+1) begin
    assign sft_dt[P_SFTDT_BW-P_DT_BW+i] =
             {dat[P_DT_BW-i-1:0], base_data[P_SFTDT_BW-P_DT_BW+i-1:0]} ;
  end
  assign sft_dt[P_SFTDT_BW] = base_data ;
endgenerate
assign sft_data = (sft < P_SFTDT_BW) ? sft_dt[sft] :
                                       sft_dt[P_SFTDT_BW]  ;

2022年11月23日水曜日

WSL : Verilator の インストール

目的:

Verilator をインストールする。

Verilator について:

Verilator は Verilog, SystemVerilog のシミュレータ である。
Verilator は 論理回路(論理合成可能なVerilogの記述) を C++ や SystemC 等にコンパイルし、シミュレーションを実行する。
シミュレーション用の記述は C++ や SystemC で 記述する。
また Lint チェックを行うことができる。

今回、Lint チェック を試すために インストールを行う。
 (文法チェック/記述チェック で使用できるか 確認。)

インストール手順:

参考URL : VERIPOOL ホームページ
apt で インストールできるようであるが、バージョンが少し古い為、ソースからビルドを行う事とした。

  1. Verilator をビルドするために必要なパッケージを インストールする。
    $sudo apt-get install git perl python3 make autoconf g++ flex bison ccache
    $sudo apt-get install libgoogle-perftools-dev numactl perl-doc
    $sudo apt-get install libfl2
    $sudo apt-get install libfl-dev
    $sudo apt-get install zlibc zlib1g zlib1g-dev
  2. 適当なディレクトリに移動し、git リポジトリからソースを取得する。
    $git clone https://github.com/verilator/verilator
  3. veerilator ディレクトリに移動する
    $cd verilator
  4. 以下の様に 環境変数を設定しておく。(SYSTEMC インストール済みの場合。設定値は一例。 ~/.bashrc に追加し、source する )
    export SYSTEMC=/usr/local/systemc/2.3.3
    export SYSTEMC_INCLUDE=$SYSTEMC/include
    export SYSTEMC_LIBDIR=$SYSTEMC/lib-linux64
    export SYSTEMC_ARCH=linux64
  5. 構成スクリプトを作成する。
    $autoconf
  6. 設定を行う。
    $./configure
  7. make 実行
    $make -j2
  8. 念のため、チェック実行
    $make test
  9. インストール 実行
    $sudo make install

動作確認 (Lint チェック):

Lint チェックを実行して見る。
Lintチェックは、

$verilator --lint-only -Wall  [RTL ファイル名]
で実行できる。
使用オプションは以下の通り。
--lint-only     Lint, but do not make output
 -Wall          Enable all style warnings

always 文 (FF) で
  data_1 <= #1 data ;
のように 遅延時間を指定していると
%Error-NEEDTIMINGOPT: test.v:64:25: Use --timing or --no-timing to specify how timing controls should be handled
の様なエラーが報告される。
メッセージにあるように
verilator --lint-only -Wall --timing  [RTL ファイル名]
とすると このエラー が報告されなくなる。
--no-timing を付けると、Warning 報告となる。
--timing        Enable timing support
--no-timing     Disable timing support


Lint チェックを実行して見た結果、処理は早く、rtl 記述後にまずは verilator で Lint チェックでデバッグ(記述チェック)するのが良いように思える。
但し、bit幅の不整合などで、実質問題ない記述でもWarning が出る為、煩わしく感じるかもしれない。
とはいえ、問題のある記述の場合もある為、ちゃんと 全数確認する必要がある。


2022年11月17日木曜日

verilog : セレクタ(マルチプレクサ) の記述 いろいろ

目的

セレクタの記述の仕方について 記す

記述の仕方

  1. 3項演算子で記述
    最もよく使用する記述。
  2. 配列のインデックス(添え字) で選択
    選択数が多い場合は、この方法で記述。
  3. case文 で記述
    function 文 や always 文 内で使用する。
    セレクタを使いまわす場合は function で記述する。
  4. if文 で記述
    function 文 や always 文 内で使用する。
    セレクト条件が複数の信号の組み合わせでも記述できる。
    但し、複雑な条件となると
     可読性か悪くなる
     シミュレーション時に条件成立が判りにくい
    等の問題がある。
    セレクト条件は assign 文で 1信号 にしてから使用した方がよい。
以下に記述例を示す。

記述例

図の様なセレクタを記述する例を示す。
  1. 3項演算子で記述
    assign sel_data  = (sel == 4'd0)  ?  data_0 :
                       (sel == 4'd1)  ?  data_1 :
                       (sel == 4'd2)  ?  data_2 :
                       (sel == 4'd3)  ?  data_3 :
                                          8'd0 ;

  2. 配列のインデックス(添え字) で選択
    reg [7:0] all_data[0:15] ;   //選択対象の 2次元配列データ
    assign sel_data = all_data[sel] ;  //セレクタ
    選択対象が配列になっていない場合、以下のように データを 2次元配列に代入する。
     ( 16 x 8bit の 配列に 4つのデータを代入し、残り 12個を 8'd0 で埋める場合。)
    wire [7:0] all_data[0:15] ;     // 2次元配列データ
    assign all_data[0] = data_0 ;
    assign all_data[1] = data_1 ;
    assign all_data[2] = data_2 ;
    assign all_data[3] = data_3 ;
    genvar i ;
    generate
      for (i=4; i<16; i=i+1) begin
        assign all_data[i] = 8'd0 ;
      end
    endgenerate

  3. case文 で記述
    function 文 で選択の場合
    function [7:0] data_sel (
    input [3:0] select,
    input [7:0] in_data0,
    input [7:0] in_data1,
    input [7:0] in_data2,
    input [7:0] in_data3
    ) ;
      begin
        case (sel)
          4'd0    : sel_data = in_data0 ;
          4'd1    : sel_data = in_data1 ;
          4'd2    : sel_data = in_data2 ;
          4'd3    : sel_data = in_data3 ;
          default : sel_data = 8'd0     ;
        endcase
      end
    endfunction

    assign sel_data = data_sel(.select(sel),.in_data0(data_0),.in_data1(data_1),
                               .in_data2(data_2),.in_data3(data_3)) ;
    always 文 で選択の場合
    always @(*) begin
      case (sel)
        4'd0    : sel_data = data_0 ;
        4'd1    : sel_data = data_1 ;
        4'd2    : sel_data = data_2 ;
        4'd3    : sel_data = data_3 ;
        default : sel_data = 8'd0   ;
      endcase
    end

  4. if文 で記述
    always 文 で選択の場合
    always @(*) begin
      if      (sel == 4'd0)  sel_dt5 = data_0 ;
      else if (sel == 4'd1)  sel_dt5 = data_1 ;
      else if (sel == 4'd2)  sel_dt5 = data_2 ;
      else if (sel == 4'd3)  sel_dt5 = data_3 ;
      else                   sel_dt5 = 8'd0   ;
    end



2021年10月25日月曜日

verilog : 多ビット信号の配列(二次元配列)と入出力ポート

目的:

入出力ポートには2次元配列を使用できない為、2次元配列を1次元配列にアサインする。

記述例:

内部信号
  reg  [P_BW-1:0]  r_rise_pos[0:6] ;
を 1次元の配列
  wire [P_BW*7-1:0] w_rise_pos ;
に アサイン する場合の記述例を以下に示す。

例1 :

assign  w_rise_pos = {r_rise_pos[6], r_rise_pos[5],r_rise_pos[4],r_rise_pos[3],
                      r_rise_pos[2], r_rise_pos[1],r_rise_pos[0] } ;

例2 :

generate
  for (i=0; i<7; i=i+1)
    begin : asin_1d
      assign w_rise_pos[(i+1)*P_BW-1:i*P_BW] = r_rise_pos[i] ;
    end
endgenerate

回路例:

この回路例は、レジスタブロック(pgen_reg)とパルス生成ブロック(pgen_plsgen)で構成。
7組の 立ち上げタイミング(r_rise_pos)と立ち下げタイミング(r_fall_pos)レジスタを持ち、スタートビット(r_cntstart) に '1' をライトする事で、設定したタイミングで ON/OFF する7つのパルスを出力する。
立ち上げ/たち下げタイミングを 2次元配列とし、ブロック間 を1次元配列として接続している。

RTL (Verilog)

レジスタブロック : 2次元配列→1次元配列 のアサインに 上述の 例1 と 例2 を使用。

// -----------------------------------------------------
//   2d-array Sample module 
//
//   Module Name : pgen_reg
//   Version     : 0.00
// -----------------------------------------------------
 
module pgen_reg #(                      // Module name : test
  parameter P_BW = 8                    // parameter list
) (                                     //
  clr,                                  // port list
  clk,
  adr,
  we,
  data,
  rd_data,
  cntstart,
  cntmax,
  rise_pos,
  fall_pos
) ;
 
// ====== port declaration ================
input                     clr      ;
input                     clk      ;
input            [3:0]    adr      ;
input                     we       ;
input       [P_BW-1:0]    data     ;
output      [P_BW-1:0]    rd_data  ;
output                    cntstart ;
output      [P_BW-1:0]    cntmax   ;
output reg  [7*P_BW-1:0]  rise_pos ;
output reg  [7*P_BW-1:0]  fall_pos ;
 
// ====== parameter declaration ===========
parameter   DLY = 1 ;
 
// ====== internal signal declaration =====
wire        [15:0]  sel        ;
wire        [15:0]  reg_wen    ;
wire  [7*P_BW-1:0]  w_rise_pos ;
wire  [7*P_BW-1:0]  w_fall_pos ;

reg              r_cntstart ;
reg  [P_BW-1:0]  r_cntmax     ; 
reg  [P_BW-1:0]  r_rise_pos[0:6] ;
reg  [P_BW-1:0]  r_fall_pos[0:6] ;

// variable for generate ----------
genvar i ;

// ====== logical description =============

// address decode -------------------------
assign sel = 16'd1 << adr ;

// write enable ---------------------------
assign reg_wen = sel & {16{we}} ;

// register -------------------------------

//   cntstart reg -----------------------
always @(posedge clk or posedge clr)
  if (clr) 
    r_cntstart  <= #DLY  1'b0 ;
  else if (reg_wen[0])
    r_cntstart  <= #DLY  data[0] ;

//   cntmax reg -------------------------
always @(posedge clk or posedge clr)
  if (clr) 
    r_cntmax    <= #DLY  {P_BW{1'b0}} ;
  else if (reg_wen[1])
    r_cntmax    <= #DLY  data ;

//   rise_pos, fall_pos reg -------------
generate
  for (i=0; i<7; i=i+1) 
    begin : pos_reg
      always @(posedge clk or posedge clr)
        if (clr)
          r_rise_pos[i]  <= #DLY  {P_BW{1'b0}} ;
        else if (reg_wen[i*2+2])
          r_rise_pos[i]  <= #DLY  data ;

      always @(posedge clk or posedge clr)
        if (clr) begin
          r_fall_pos[i]  <= #DLY  {P_BW{1'b0}} ;
          end
        else if (reg_wen[i*2+3])
          r_fall_pos[i]  <= #DLY  data ;
    end
endgenerate

// read data select -----------------------
assign rd_data = (sel[0])  ?  {{(P_BW-1){1'b0}},r_cntstart} :
                 (sel[1])  ?  r_cntmax :
                 (sel[2])  ?  r_rise_pos[0] :
                 (sel[3])  ?  r_fall_pos[0] :
                 (sel[4])  ?  r_rise_pos[1] :
                 (sel[5])  ?  r_fall_pos[1] :
                 (sel[6])  ?  r_rise_pos[2] :
                 (sel[7])  ?  r_fall_pos[2] :
                 (sel[8])  ?  r_rise_pos[3] :
                 (sel[9])  ?  r_fall_pos[3] :
                 (sel[10]) ?  r_rise_pos[4] :
                 (sel[11]) ?  r_fall_pos[4] :
                 (sel[12]) ?  r_rise_pos[5] :
                 (sel[13]) ?  r_fall_pos[5] :
                 (sel[14]) ?  r_rise_pos[6] :
                 (sel[15]) ?  r_fall_pos[6] : {P_BW{1'b1}} ;

// 2d_array -> 1d_array --------------------
// EX.1 ------------
assign  w_rise_pos =   { r_rise_pos[6], 
                         r_rise_pos[5],
                         r_rise_pos[4],
                         r_rise_pos[3],
                         r_rise_pos[2],
                         r_rise_pos[1],
                         r_rise_pos[0] } ;
// EX.2 ------------
generate
  for (i=0; i<7; i=i+1)
    begin : asin_1d
      assign w_fall_pos[(i+1)*P_BW-1:i*P_BW] = r_fall_pos[i] ;
    end
endgenerate


// output signal ---------------------------
assign cntstart  = r_cntstart ; 
assign cntmax    = r_cntmax ;

always @(posedge clk or posedge clr)
  if (clr)
    rise_pos <= #DLY  {(7*P_BW){1'b0}} ;
  else
    rise_pos <= #DLY  w_rise_pos  ;

always @(posedge clk or posedge clr)
  if (clr)
    fall_pos <= #DLY {(7*P_BW){1'b0}} ;
  else
    fall_pos <= #DLY  w_fall_pos ;

endmodule

パルス生成ブロック : 1次元配列→2次元配列 のアサインに 上述の 例2 と同様の記述を使用。

// -----------------------------------------------------
//   2d-array Sample module 
//
//   Module Name : pgen_plsgen
//   Version     : 0.00
// -----------------------------------------------------
 
module pgen_plsgen #(              // Module name : test_plsgen
  parameter P_BW = 8               // parameter list
) (                                //
  clr,                             // port list
  clk,
  cntstart,
  cntmax,
  rise_pos,
  fall_pos,
  pls_0,
  pls_1,
  pls_2,
  pls_3,
  pls_4,
  pls_5,
  pls_6
) ;
 
// ====== port declaration ================
input                clr ;
input                clk ;
input                cntstart ;
input    [P_BW-1:0]  cntmax   ;
input  [7*P_BW-1:0]  rise_pos ;
input  [7*P_BW-1:0]  fall_pos ;
output               pls_0    ;
output               pls_1    ;
output               pls_2    ;
output               pls_3    ;
output               pls_4    ;
output               pls_5    ;
output               pls_6    ;
 
// ====== parameter declaration ===========
parameter   DLY = 1 ;
 
// ====== internal signal declaration =====
wire             w_start_pls  ;
wire  [P_BW-1:0] w_rise_pos[0:6] ;
wire  [P_BW-1:0] w_fall_pos[0:6] ;
wire             w_pls[0:6]  ;
wire             w_valid ;

reg              r_start_dl ;
reg  [P_BW-1:0]  r_count ;
reg              r_pls[0:6]  ;

// variable for generate ----------
genvar i ;

// ====== logical description =============

// input array -> 2d array assign ---------
generate
  for (i=0; i<7; i=i+1) 
    begin : asin_2d
      assign w_rise_pos[i] = rise_pos[(i+1)*P_BW-1:i*P_BW] ;
      assign w_fall_pos[i] = fall_pos[(i+1)*P_BW-1:i*P_BW] ;
    end
endgenerate

// generate start pulse -------------------
always @(posedge clk or posedge clr)
  if (clr)
    r_start_dl  <= #DLY  1'b0 ;
  else
    r_start_dl  <= #DLY  cntstart ;

assign w_start_pls = cntstart & ~r_start_dl ;

// pulse counter  -------------------------
always @(posedge clk or posedge clr)
  if (clr)
    r_count  <= #DLY  {P_BW{1'b0}};
  else if (w_start_pls)
    r_count  <= #DLY  {{(P_BW-1){1'b0}},1'b1} ;
  else if ((r_count > 0) && (r_count < cntmax) )
    r_count  <= #DLY  r_count + 1 ;
  else if (r_count == cntmax)
    r_count  <= #DLY  {P_BW{1'b0}} ;

assign r_valid = r_count != 0 ;

// pulse generate -------------------------
generate
  for (i=0; i<7; i=i+1) 
    begin : pos_reg
      assign w_pls[i] = (w_rise_pos[i] <= r_count) && (r_count < w_fall_pos[i]) && r_valid ;

      always @(posedge clk or posedge clr)
        if (clr)
          r_pls[i]  <= #DLY  {P_BW{1'b0}} ;
        else
          r_pls[i]  <= #DLY  w_pls[i] ;
    end
endgenerate

// output signal ---------------------------
assign pls_0 = r_pls[0]   ; 
assign pls_1 = r_pls[1]   ; 
assign pls_2 = r_pls[2]   ; 
assign pls_3 = r_pls[3]   ; 
assign pls_4 = r_pls[4]   ; 
assign pls_5 = r_pls[5]   ; 
assign pls_6 = r_pls[6]   ; 
 
endmodule

トップブロック : レジスタブロックとパルス生成ブロックの上位ブロック

// -----------------------------------------------------
//   2d-array Sample module 
//
//   Module Name : pgen
//   Version     : 0.00
// -----------------------------------------------------
 
module pgen(
  clr,                                  // port list
  clk,
  adr,
  we,
  data,
  rd_data,
  pls_0,
  pls_1,
  pls_2,
  pls_3,
  pls_4,
  pls_5,
  pls_6
) ;

// ====== port declaration ================
input                clr ;
input                clk ;
input         [3:0]  adr ;
input                we  ;
input    [     7:0]  data     ;
output   [     7:0]  rd_data  ;
output               pls_0    ;
output               pls_1    ;
output               pls_2    ;
output               pls_3    ;
output               pls_4    ;
output               pls_5    ;
output               pls_6    ;
 
// ====== internal signal declaration =====
wire               cntstart ;
wire   [     7:0]  cntmax   ;
wire [7*8   -1:0]  rise_pos ;
wire [7*8   -1:0]  fall_pos ;
 
// ====== logical description =============

pgen_reg #(            
  .P_BW  (8)  
)i_test_reg(                    
  .clr        ( clr          ),                 
  .clk        ( clk          ),
  .adr        ( adr          ),
  .we         ( we           ),
  .data       ( data         ),
  .rd_data    ( rd_data      ),
  .cntstart   ( cntstart     ),
  .cntmax     ( cntmax       ),
  .rise_pos   ( rise_pos     ),
  .fall_pos   ( fall_pos     )
) ;
 
pgen_plsgen #(
  .P_BW (8)
)i_test_plsgen(                  
  .clr          ( clr      ),               
  .clk          ( clk      ),
  .cntstart     ( cntstart ),
  .cntmax       ( cntmax   ),
  .rise_pos     ( rise_pos ),
  .fall_pos     ( fall_pos ),
  .pls_0        ( pls_0    ),
  .pls_1        ( pls_1    ),
  .pls_2        ( pls_2    ),
  .pls_3        ( pls_3    ),
  .pls_4        ( pls_4    ),
  .pls_5        ( pls_5    ),
  .pls_6        ( pls_6    )
) ;

endmodule

シミュレーション用のテストベンチ

// ----------------------------------------------------------
//   test bench
//
//     for pgen.v
// ----------------------------------------------------------

`timescale 1ns / 1ps

module testbench ;

// testbench logic -------------------
logic         clr;
logic         clk;
logic  [ 3:0] adr     ;
logic         we      ;
logic  [ 7:0] data    ;
logic  [ 7:0] rd_data ;
logic         pls_0   ;
logic         pls_1   ;
logic         pls_2   ;
logic         pls_3   ;
logic         pls_4   ;
logic         pls_5   ;
logic         pls_6   ;

// parameter -------------------------
parameter  MAX_SIM_TIME = 20000 ;

// target module ---------------------
pgen i_pgen (
  .clr           ( clr        ),
  .clk           ( clk        ),
  .adr           ( adr        ),
  .we            ( we         ),
  .data          ( data       ),
  .rd_data       ( rd_data    ),
  .pls_0         ( pls_0      ),
  .pls_1         ( pls_1      ),
  .pls_2         ( pls_2      ),
  .pls_3         ( pls_3      ),
  .pls_4         ( pls_4      ),
  .pls_5         ( pls_5      ),
  .pls_6         ( pls_6      )
) ;

// clock, reset generate -------------
initial begin
  clk = 0 ;
  clr = 1 ;
  #10 clr = 0 ;
  forever begin
    #10 clk = ~clk ;
  end
end

// scenario --------------------------
initial begin
  $dumpfile("wave.vcd");
  $dumpvars(0,testbench) ;

  adr         =  4'h0   ;
  we          =  1'b0   ;
  data        =  8'h0   ;

  #MAX_SIM_TIME
  $display(" SIM TIME OUT !!") ;
  $finish ;

  end

// include test patteern  ------------

initial begin

  $display (" ") ;
  #200

  @(posedge clk) #1
  adr    = 4'h2   ;     // rise_pos 0
  data   = 8'h10  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h3   ;     // fall_pos 0
  data   = 8'h14  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h4   ;     // rise_pos 1
  data   = 8'h20  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h5   ;     // fall_pos 1
  data   = 8'h28  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h6   ;     // rise_pos 2
  data   = 8'h30  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h7   ;     // fall_pos 2
  data   = 8'h3f  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h8   ;     // rise_pos 3
  data   = 8'h12  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h9   ;     // fall_pos 3
  data   = 8'h38  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'ha   ;     // rise_pos 4
  data   = 8'h3e  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'hb   ;     // fall_pos 4
  data   = 8'h3f  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'hc   ;     // rise_pos 5
  data   = 8'h0f  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'hd   ;     // fall_pos 5
  data   = 8'h10  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'he   ;     // rise_pos 6
  data   = 8'h20  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'hf   ;     // fall_pos 7
  data   = 8'h21  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h1   ;     // count max 
  data   = 8'h50  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h0   ;     // count start on
  data   = 8'h01  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h0   ;     // count start off
  data   = 8'h00  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  repeat(100) @(posedge clk)  ;

  $display ("test_END");

  $finish ;
end

// include assertion bind list -------
//`include "bind.list"
//`include "bind_sva.sv"
//`include "sva_1.sv"

endmodule

シミュレーション結果を以下に示す。
コマンドラインからの VCD出力では 2次元配列の信号が表示されなかった為、vivado GUI でのシミュレーション波形を表示。pls0 のみ レジスタブロックとパルス生成ブロックの2次元配列を表示。(他は パルス生成ブロックのみ)


 

2021年10月13日水曜日

verilog : Vivado GUI でのシミュレーション手順

目的:

 Vivado (GUI) での シミュレーション手順を記す。

手順:

  1. vivado 起動
  2. プロジェクトの作成
    1. Create Project  又は  File → Project → New を押下
    2. 「Create a New Vivado Project」 ウィンドウが開いたら Next 押下
    3. 「Project Name」 ウィンドウで Project 名 と 保存先 を入力して Next 押下
    4. 「Project Type」 ウィンドウで "RTL Project" を選択 して Next 押下
    5. 「AddSources」 ウィンドウでは そのまま Next 押下。
        (ソースは後で追加/作成)
    6. 「Add Constraints(optional) 」 ウィンドウでは そのまま Next 押下。
        (制約は後で作成)
    7. 「Default Part」 ウィンドウで 使用する FPGA を選択し、Next を押下。
    8. 「New Project Summary 」 ウィンドウで 内容を確認し、Finish を押下する。
  3. ソースコードの作成/追加
    1. Flow Navigator (左側) の  "PROJECT MANAGER" 内の Add Sources  をクリック
    2. 「Add Sources」ウィンドウで Add or create design sources を選択して Next を押下
      既にシミュレーション用のソースがある場合
      1. "Add Files" を押下
      2. 「Add Source File」 ウィンドウで RTL を選択し、OK を押下する。
      3. "Copy sources into project" 等、必要に応じてチェックし、Finish を押下する。
      新規にソースを作成する場合
      1. "Create Files" を押下
      2. 「Create Source File」ウィンドウで File name を 入力し、OK を押下
      3. Finish を押下
      4. 「Define Module」ウィンドウ で Module name, I/O ポートを入力し、OKを押下。(I/O ポートは、最低限(clk,rstのみ)で可。無しでも可。後でソース修正。)
  4. テストベンチの作成/追加
    1. Flow Navigator (左側) の  "PROJECT MANAGER" 内の Add Sources  をクリック
    2. Add Sources」ウィンドウで Add or create simulation sources を選択して Next を押下
      既にシミュレーション用のソースがある場合
      1. Add Files を押下
      2. 「Add Source File」 ウィンドウで RTL を選択し、OK を押下する。
      3. "Copy sources into project" 等、必要に応じてチェックし、Finish を押下する
      新規にソースを作成する場合
      1. "Create Files" を押下
      2. 「Create Source File」ウィンドウで File name を 入力し、OK を押下
      3. Finish を押下
      4. 「Define Module」ウィンドウ で Module name, I/O ポートを入力し、OKを押下。(I/O ポートは、最低限(clk,rstのみ)で可。無しでも可。後でソース修正。)
  5. 論理シミュレーション
    シミュレーションの実行
    1. シミュレーション実行
      Flow Navigator (左側) の  "SIMULATION" 内の Run Simulation  をクリックし、
      "Run Behavioral Simulaion" を選択
      • シミュレーションが規定時間分 実行される。( default 1000 nS )
        規定時間は、"Tools"-"Settings…" の 左側 "Simulation" を選択し、右側 "simulation"タブの
        "xsim.simulate.runtime" で 設定する。
      • コンパイル等でエラーが発生した場合、画面下方の 「Tcl Consoke 」を選択してエラー内容の確認/修正を行い、保存後、再度  "Run Behavioral Simulation" を実行する。
      • シミュレーションが実行されると、画面右側に波形が表示される。
        ( $finish()等で停止した場合は ソースコードが表示される。
        この場合、Untitled タブを選択すると 波形が表示される )
    2. 最後まで実行
      "Run All" (メニュバー "Run"  又は アイコン) で 最後まで シミュレーションを実行する。
    その他、シミュレーションについて
    • 表示波形の追加
      Scope ウィンドウで 表示したいモジュールを選択し、Objects ウィンドウで 信号を選択して ドラッグアンドドロップ で 波形ウィンドウに追加する。
      追加した信号の波形表示をする為には再度シミュレーションを実行する必要がある。
    • シミュレーション再実行
      "Restart " (メニュバー "Run"  又は アイコン) で シミュレーション結果をクリアし、
      "Run All" (メニュバー "Run"  又は アイコン) で 最後まで シミュレーションを実行する。
    • 波形表示信号の保存
      "Save Waveform Configuration" (アイコン) で 波形表示設定ファイルを保存する。
    • 再コンパイル
      ソースコードやテストベンチ修正して、再度コンパイルを実行する場合
      "Relaunch simulation " (メニュバー "Run"  又は アイコン) で コンパイルから再実行する。
    • シミュレーション結果がおかしい場合
      ソースコードを修正したり、ソースファイルを削除した後等に 削除したはずの信号が残っている等、結果がおかしい場合、
      "Settings" の 左側 "Simulation" を選択し、右側 "Advanded"タブの
      "Enable incremental compilation" のチェックを外し、再コンパイルしてみる。

2021年10月8日金曜日

verilog : Vivado ML (2021.1) で source が 開けない

現象:

Vivado ML (2021.1) で ソースコードを開こうとすると 動作が異常に遅くなる。

状況等:

ソースコードを開こうとすると、
"Initializing Language Server and Opening ……"
のウィンドウのまま 処理が進まない (以上に遅くなる)。
ソースコードが開いても、動作が異常の遅い。(ほとんど動かない)

原因:

Vivado 2021.1 の 問題らしい。
Xilinxのフォーラムに回避策が書いてあるとのこと。

回避策:

回避策1 : 下記のファイルを削除して Vivadoを起動する。

C:\ユーザー\<ユーザ名>\AppData\Roaming\Xilinx\Vivado\tclapp\mainfest.tcl
  → 試してみたが、Vivado 起動時に ファイルが生成され、改善できなかった

回避策2 : Vivado の 設定 変更。

以下の設定を変更する。
メニューバー の Tools から  "Settings" 選択。
開いたウィンドウの 左側 にある Tool Settings の Text Editor  を展開し、
"Syntax Checking"  を 選択。
右側の Syntax checking の ドロップダウンリストで Sigasi から Vivado に変更。
"OK" で 終了後、vivado を 終了し、再度立ち上げる。


上述の 回避策2 で 普通に動作するようになった。



2021年9月11日土曜日

Windows : WSL (Debian) にVivado ML をインストールする。

目的:

WSL (Debian) に Vivado ML (スタンダード) を インストールする。

以前、Vivado  (2020.1) をインストールしたが、最新版(Vivado ML スタンダード) のインストールを行い、動作を確認する。

インストール手順:

今回は、GUI にて インストールできた。手順を以下に記す。
  1. インストーラをダウンロードする ( Windows )
    Xilinx のサイトから、「ザイリンクス統合インストーラー 2021.1: Linux 用自己解凍型ウェブ インストーラー (BIN - 301.28 MB) 」を 任意のディレクトリにダウンロードする。 (アカウントが必用。なければ、作成する)
  2. Xサーバーを起動 するWindows 上で Xサーバーを起動する。
  3. インストーラ を実行する
    必要に応じ、sudo apt update, sudo apt upgrade を実行しておく。
    WSL (Debian) の 端末から、インストーラを実行する。
     ダウンロードしたディレクトリ : D:\download\xilinx
     ダウンロードしたファイル名  : Xilinx_Unified_2021.1_0610_2318_Lin64.bin
    の場合、
     cd /mnt/d/download/xilinx
     ./Xilinx_Unified_2021.1_0610_2318_Lin64.bin
    を実行すると、インストーラのウィンドウが立ち上がる。
    1. Welcom の 画面 :
      next を押下
    2. Select Install Typw の画面 :
      E-mail Address, password を入力し、
      "Download and Install Now" が選択されていることを確認し、
      next を押下
    3. Select Product to Install の画面:
      vivad を選択し、next を押下
    4. Select Edition to Install の画面:
      Viado ML Standard を選択し、 next を押下
    5. Vivado ML Standard の画面:
      インストール内容を確認し、next を押下
    6.  Accept License Agreements
      全て(3か所) の "I Agree" にチェックを付け、next を押下
    7. Select Destination Directory の画面
      インストール先のディレクトリを指定する。
      各インストール先、ディスク容量等を確認し、next を押下
    8. Installation Summary の画面
      インストールの内容を確認し、Install を押下
    インストール終了まで待つ

Vivado の実行:

以下の様に、インストールディレクトリの settings64.sh を ソースし、vivado を実行する。( インストール先 : /tools/Xilinx, Ver 2021.1 の場合 )
 source /tools/Xilinx/Vivado/2020.1/settings64.sh
 vivado
vivado の実行で GUI の画面が立ち上がる。

コマンドラインで使用する場合も、2021.1 の settings64.sh を source した後に使用する。
以前のバージョン (2020.1) を使用する場合は、2020.1 の settings64.sh を source することで、以前のバージョンが使用できる。

普段使用するバージョンの settings64.sh を .bashrc に 記載しておくのが良いと思う。


 

2021年1月28日木曜日

verilog : 擬似乱数生成

 目的: 

疑似乱数の生成方法、RTLについて記す。

仕様:

本疑似乱数生成は、
  1. 9bit LFSR (線形帰還シフトレジスタ) をベースに生成する。
  2. 出力は 9bit 疑似乱数で 0x001~0x1ff を出力。
  3. 開始パルスで初期値を設定し、イネーブル信号で疑似乱数を更新する。

疑似乱数生成方法:

9bit LFSR

9bit LFSRのブロック図を以下に示す。
これは、多項式 X^9+X^5+1 の ガロアLFSR(線形帰還シフトレジスタ) で、
2^9=512 通り の内、0 を除いた 511通りの値を周期的に変化する。
512番目の値が最初の値と同じになる。
これを書き換えると以下の様に書ける。

出力 Q[9:1] は、初期値を 0x1FF とすると、
 0x1FF, 0x1EF, 0x1E7, 0x1E3, 0x1E1, 0x1E0, 0x0F0, 0x078, 0x03C, 0x01E, ……
 (511) (495) (487) (483) (481) (480) (240) (120) (60)  (30)  

の様に変化し、512番目で 0x1FF に戻る。
このままでも 疑似乱数ではあるが、隣り合う値の多くのビットは 1bit シフトした値の為、似た様なビットパターンとなる。

疑似乱数の生成

上述の為、下図の様に ビットシフトとEOR 部分(LSF) を 9段重ね、ビットシフトが1周したデータ(9個置きの値)を取得する様にする。

出力 Q[9:1] は、初期値を 0x1FF とすると、
 0x1FF, 0x01E, 0x1C3, 0x1B9, 0x090, 0x099, 0x1A2, 0x1FC, 0x07B, ……
 (511) ( 30) (451) (441) (144) (153) (418) (508) (123)
の様に変化し、512番目で 0x1FF に戻る。
尚、この疑似乱数には 0 は含まれない。FF の出力が 0 となると、以降、FF出力は 0のまま変化しなくなる。

0を含んだ疑似乱数が必要な場合、1bit 削ることで0を含む疑似乱数を得ることができる。
例えば、8bit の 疑似乱数を取得する場合、上の出力 Q の 下位 8bit (Q[8:1]) を取り出す。
但し、この場合、511  データ中に 0 が 1回、1~255 が 2回づつ発生となり、0の発生回数が他よりも少ない。
或いは、外部回路で 適用な位置に '0' を挿入する必要がある。


ブロック図:

疑似乱数生成回路のブロック図を以下に示す。
本回路は、上述の疑似乱数生成回路に以下を追加したものとなる。
  1. 初期値(SEED値) を設定できるようにする。
  2. イネーブルを追加し、イネーブルが 'H' の期間のみ出力を更新する。

RTL:

上述のブロック図 2 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Pseudo-Random Number
//
//   Module Name : prn
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module prn (                            // Module name : prn
  CLR,                                  // port list
  CLK,
  seed,
  load,
  enable,
  prn
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [ 8:0] seed     ;
input              load     ;
input              enable   ;
output      [ 8:0] prn      ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire [9:1]  lsf0        ;
wire [9:1]  lsf1        ;
wire [9:1]  lsf2        ;
wire [9:1]  lsf3        ;
wire [9:1]  lsf4        ;
wire [9:1]  lsf5        ;
wire [9:1]  lsf6        ;
wire [9:1]  lsf7        ;
wire [9:1]  lsf8        ;

reg  [9:1]  Q           ;

// logical description -------------

assign lsf0 = {Q[1],Q[9:7],(Q[1]^Q[6]),Q[5:2]} ;
assign lsf1 = {lsf0[1],lsf0[9:7],(lsf0[1]^lsf0[6]),lsf0[5:2]} ;
assign lsf2 = {lsf1[1],lsf1[9:7],(lsf1[1]^lsf1[6]),lsf1[5:2]} ;
assign lsf3 = {lsf2[1],lsf2[9:7],(lsf2[1]^lsf2[6]),lsf2[5:2]} ;
assign lsf4 = {lsf3[1],lsf3[9:7],(lsf3[1]^lsf3[6]),lsf3[5:2]} ;
assign lsf5 = {lsf4[1],lsf4[9:7],(lsf4[1]^lsf4[6]),lsf4[5:2]} ;
assign lsf6 = {lsf5[1],lsf5[9:7],(lsf5[1]^lsf5[6]),lsf5[5:2]} ;
assign lsf7 = {lsf6[1],lsf6[9:7],(lsf6[1]^lsf6[6]),lsf6[5:2]} ;
assign lsf8 = {lsf7[1],lsf7[9:7],(lsf7[1]^lsf7[6]),lsf7[5:2]} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    Q <= #P_DLY 9'h1ff  ;
  else if (load)
    Q <= #P_DLY seed ;
  else if (enable)
    Q <= #P_DLY lsf8 ;

assign prn = Q[9:1] ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。


2021年1月10日日曜日

verilog : 除算器2( 商を 固定小数点化 )

目的: 

商を固定小数点とした除算器の構成、RTLについて記す。

仕様:

本除算器は、
  1. 演算は 16bit ÷ 16bit の符号なし整数の除算で、出力は 32bit 固定小数点(u16.16) の商
  2. 複数クロックを使用して演算を行う。
  3. 開始パルスで演算を開始し、演算終了で終了信号を出力する。

除算方法:

除算器 と同様。
違いは、
  1. 商の bit幅を 32bit に拡張 (整数部 16bit, 小数部 16bit の 固定小数点 )
  2. 繰り返し回数を 32回に増加 (商が 32bit の為)
  3. 剰余は削除
のみ。

ブロック図:

除算器のブロック図を以下に示す。

RTL:

上述のブロック図 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Divider 
//
//   Module Name : divid
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module divid (                          // Module name : divid
  CLR,                                  // port list
  CLK,
  a,
  b,
  start,
  division,
  complete
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [15:0] a        ;
input       [15:0] b        ;
input              start    ;
output reg  [31:0] division   ;
output reg         complete ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire        op_cnt_en   ;
wire        borrow      ;
wire [17:0] sub         ;
wire        div_en      ;

reg   [5:0] op_cnt      ;
reg  [32:0] div_ref     ;
reg  [31:0] div_val     ;

// logical description -------------

assign op_cnt_en = (op_cnt < 6'd32) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    op_cnt <= #P_DLY 6'd63 ;
  else if (start)
    op_cnt <= #P_DLY 6'd0 ;
  else if (op_cnt_en)
    op_cnt <= #P_DLY op_cnt + 6'd1 ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_ref <= #P_DLY 32'd0 ;
  else if (start)
    div_ref <= #P_DLY {16'b0,a} ;
  else if (~borrow & div_en)
    div_ref <= #P_DLY {sub[15:0],div_ref[14:0],1'b0} ;
  else if (div_en)
    div_ref <= #P_DLY div_ref << 1 ;

assign sub = {1'b0,div_ref[31:15]} - {2'b0,b} ;
assign borrow = sub[17] ;

assign div_en = (op_cnt <= 6'd31) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_val <= #P_DLY 32'd0 ;
  else if (start)
    div_val <= #P_DLY 32'd0 ;
  else if (div_en)
    div_val <= #P_DLY {div_val[30:0],~borrow} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    complete <= #P_DLY 1'b0 ;
  else 
    complete <= #P_DLY (op_cnt == 6'd32) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    division <= #P_DLY 32'd0 ;
  else 
    division <= #P_DLY div_val ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。

除算結果(商) は 整数部 16bit, 少数部 16bit の為、1/2^16 = 0.00001526 の誤差がある。
255/1023 の シミュレーション結果は 0.249252 で 計算値 0.249266862 とは
0.000014862 の差があるが、これは誤差範囲内。



2021年1月6日水曜日

verilog : 除算器

目的: 

除算器の構成、RTLについて記す。

仕様:

本除算器は、
  1. 演算は 16bit ÷ 16bit の符号なし整数 の 除算で、出力は 商と剰余 各16bit
  2. 複数クロックを使用して演算を行う。
  3. 開始パルスで演算を開始し、演算終了で終了信号を出力する。

除算方法:

除算は、回復法により行う。
除算の方法を下図に示す。
除算の手順は、
  1. 被除数の上位に除数のbit数分の 0 拡張を、除数に 1bit の 0拡張を行う。
  2. 被除数の上位bit から 除数 を減算する。
  3. 減算できる場合 (ボローが発生しない場合) は、減算した結果で被除数の上位bit を置き換えて 1bit 左シフトし、減算できない場合(ボローが発生した場合) は 被除数の上位 bit の置き換えは行わずに 1bit 左シフトを行う。
  4. また、商(初期値 0) を 1bit 左シフトし、最下位bit を ボローの反転値 とする。
  5. 2~5 を 被除数のbit数(拡張前) 分繰り返して商を得る。
  6. また、繰り返し終了後の被除数の拡張部分の値が 剰余となる。
被除数 3bit, 除数 3bit で 5÷2 を演算した場合の例を以下に示す。
被除数 3bit の為、3回繰り返して 商と剰余を得る。
右側に対応する 2進数での 割り算 の筆算 を示している。

ブロック図:

除算器のブロック図を以下に示す。

動作は、上述の除算方法の通り。

RTL:

上述のブロック図 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Divider 
//
//   Module Name : divid
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module divid (                          // Module name : divid
  CLR,                                  // port list
  CLK,
  a,
  b,
  start,
  division,
  remainder,
  complete
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [15:0] a        ;
input       [15:0] b        ;
input              start    ;
output reg  [15:0] division   ;
output reg  [15:0] remainder  ;
output reg         complete ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire        op_cnt_en   ;
wire        borrow      ;
wire [17:0] sub         ;
wire        div_en      ;

reg   [4:0] op_cnt      ;
reg  [32:0] div_ref     ;
reg  [15:0] div_val     ;

// logical description -------------

assign op_cnt_en = (op_cnt < 6'd16) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    op_cnt <= #P_DLY 5'd31 ;
  else if (start)
    op_cnt <= #P_DLY 5'd0 ;
  else if (op_cnt_en)
    op_cnt <= #P_DLY op_cnt + 5'd1 ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_ref <= #P_DLY 32'd0 ;
  else if (start)
    div_ref <= #P_DLY {16'b0,a} ;
  else if (~borrow & div_en)
    div_ref <= #P_DLY {sub[15:0],div_ref[14:0],1'b0} ;
  else if (div_en)
    div_ref <= #P_DLY div_ref << 1 ;

assign sub = {1'b0,div_ref[31:15]} - {2'b0,b} ;
assign borrow = sub[17] ;

assign div_en = (op_cnt <= 5'd15) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_val <= #P_DLY 16'd0 ;
  else if (start)
    div_val <= #P_DLY 16'd0 ;
  else if (div_en)
    div_val <= #P_DLY {div_val[14:0],~borrow} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    complete <= #P_DLY 1'b0 ;
  else 
    complete <= #P_DLY (op_cnt == 5'd16) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    division <= #P_DLY 16'd0 ;
  else 
    division <= #P_DLY div_val ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    remainder <= #P_DLY 16'd0 ;
  else 
    remainder <= #P_DLY div_ref[31:16] ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。


2020年12月27日日曜日

verilog : 乗算器

 目的: 

乗算器の構成、RTLについて記す。

仕様:

本乗算器は、
  1. 演算は 16bit X 16bit の符号なしの乗算で、出力は 32bit
  2. 複数クロックを使用して演算を行い、回路規模、遅延時間の削減を図る。
  3. 開始パルスで演算を開始し、演算終了で終了信号を出力する。

ブロック図:

乗算器のブロック図を以下に示す。

ブロック図 1

16x16 乗算器_1

本回路の動作は以下の通り。
被乗数(a) に 乗数(b) を掛ける。
b の 各bit(桁) と a を掛けた(AND)結果(pd)を、各bit(桁)に応じてシフトし、1サイクル毎に加算していく。
op_cnt は pd を選択する為のカウンタで start 入力によりカウントを開始し、1サイクル毎に 加算する pd を選択する。
start から 乗数(b)のビット数分のカウントを行う間、加算のイネーブル(add_en)を生成して pd の加算を繰り返す。
乗数(b)のビット数分の加算が終了したら終了信号(complete) を出力する。

ブロック図 2

16x16 乗算器_2

本回路は、上のブロック図 1 の 回路規模削減を目指した修正版。
動作はブロック図 1と同様。
サイクル毎の選択は 乗数(b)のbit(桁) 選択を行い、選択後に 被定数(a)との乗算(AND) を行うことで AND 回路を 削減。
加算は乗算結果のbit数に1bitのbit拡張したbit数で行うことで 加算器の bit数を削減。
加算結果は 1bit シフトしながら FF に記憶していく。

RTL:

上述のブロック図 2 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//   16 x 16 bit Multiplier 
//
//   Module Name : mult_16
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module mult_16 (                        // Module name : mult_16
  CLR,                                  // port list
  CLK,
  a,
  b,
  start,
  result,
  complete
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [15:0] a        ;
input       [15:0] b        ;
input              start    ;
output reg  [31:0] result   ;
output             complete ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire        op_cnt_en   ;
wire        op_cnt_last ;
wire        pb          ;
wire [15:0] add_val     ;
wire [16:0] pval        ;

reg   [4:0] op_cnt      ;
reg         add_en      ;
 
// logical description -------------

assign op_cnt_en   = op_cnt <  5'd16 ; 
assign op_cnt_last = op_cnt == 5'd15 ; 

always @(posedge CLK or posedge CLR)
  if (CLR) 
    op_cnt  <= #P_DLY  5'h1f ;
  else if (start)
    op_cnt  <= #P_DLY  5'h0  ;
  else if (op_cnt_en)
    op_cnt  <= #P_DLY  op_cnt + 5'd1 ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    add_en <= #P_DLY 1'b0 ;
  else if (op_cnt_last)
    add_en <= #P_DLY 1'b0 ;
  else if (start)
    add_en <= #P_DLY 1'b1 ;

assign pb   = (op_cnt == 5'd0  ) ? b[0] :
              (op_cnt == 5'd1  ) ? b[1] : 
              (op_cnt == 5'd2  ) ? b[2] : 
              (op_cnt == 5'd3  ) ? b[3] : 
              (op_cnt == 5'd4  ) ? b[4] : 
              (op_cnt == 5'd5  ) ? b[5] : 
              (op_cnt == 5'd6  ) ? b[6] : 
              (op_cnt == 5'd7  ) ? b[7] : 
              (op_cnt == 5'd8  ) ? b[8] : 
              (op_cnt == 5'd9  ) ? b[9] : 
              (op_cnt == 5'd10 ) ? b[10]: 
              (op_cnt == 5'd11 ) ? b[11]: 
              (op_cnt == 5'd12 ) ? b[12]: 
              (op_cnt == 5'd13 ) ? b[13]: 
              (op_cnt == 5'd14 ) ? b[14]: 
              (op_cnt == 5'd15 ) ? b[15]: 1'bx ;

assign add_val = a & {16{pb}} ;

assign pval = {1'b0,result[31:16]} + {1'b0, add_val} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    result <= #P_DLY 32'h0 ;
  else if (start)
    result <= #P_DLY 32'h0 ;
  else if (add_en)
    result <= #P_DLY {pval,result[15:1]} ;

assign complete = op_cnt == 5'd16 ;


endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。




2020年9月5日土曜日

verilog : Vivado で SVA(アサーション) を試す 2

目的:

Vivado で SVA を使用した時の 波形表示 や 発火回数 表示 ができるようにする。

概要:

一案として、アサーション記述に Pass/Fail 時の処理を記述し、波形表示を行った。
また、シミュレーション終了時に 発火回数 と FAIL 回数の表示を行った。
Vivado で SVA(アサーション) を試す」のサンプルを修正して確認を行った。

波形表示:

少し面倒ではあるが、アサーション記述に以下の様な処理を記述することで波形に表示できることを確認した。(「Vivado で SVA(アサーション) を試す」の sva_1.sv を修正)
// -----------------------------------------------------
//   Sample module
//
//   Module Name : sva_1
//   Version     : 0.00
// -----------------------------------------------------

module sva_1 ( clk, clr, start, en, outpls) ;
  input clk ;
  input clr ;
  input start ;
  input en ;
  input outpls ;

  // internal signal declaration ---------
  logic [15:0] a_test1_fire ;
  logic [15:0] a_test1_pass = 0 ;
  logic [15:0] a_test1_fail = 0 ;

  assign a_test1_fire = a_test1_pass + a_test1_fail ;

  // sequence description ----------------
  sequence S1 ;
    outpls[*4] ##1 !outpls[*5] ;
  endsequence

  // property description ---------------
  property p_test1 ;
    @(posedge clk ) disable iff(clr)
      $rose(start) |-> ##1 S1[*6] ;
  endproperty

  // assertion description
//  a_test1 : assert property ( p_test1 ) $display("a_test1 : OK") ;
  a_test1 : assert property ( p_test1 ) begin
              a_test1_pass = a_test1_pass + 1 ;
              $display("a_test1 : OK") ;
            end
            else begin
              a_test1_fail = a_test1_fail + 1 ;
              $display("a_test1 : FALE") ;
            end
  endmodule
発火回数、PASS回数、FAIL回数 の変数(信号)を定義し、アサーション記述で PASS回数、FAIL回数をカウントし、「OK」,「FAIL」の画面表示を行う。
発火回数は、PASS回数 + FAIL 回数 とする。
シミュレーション実行後、各回数の変数(信号) が波形で表示でき、値の変化点が PASS, FAIL の ポイント となる。
sva_2.sv も同様に修正する。

終了時の発火等回数の表示:

テストパターンの終了時、各アサーションの発火等の回数を $display で表示する。
// +-------------------------------------------------------------------------+
// | test pattern                                                            |
// |                                                                         |
// |   test name : test_1                                                    |
// +-------------------------------------------------------------------------+
//

initial begin
  #200
  // H:4clk,L:5clk  x 5cycle -----
  @(posedge clk) #1
      pls_start    = 1'b1  ;
      h_width      = 8'd4  ;
      l_width      = 8'd5  ;
      pls_num      = 8'h5  ;
  @(posedge clk) #1
      pls_start    = 1'b0  ;
  @(negedge i_plsgen.plsen)
  #100
  // H:4clk,L:5clk  x 6cycle -----
  @(posedge clk) #1
      pls_start    = 1'b1  ;
      h_width      = 8'd4  ;
      l_width      = 8'd5  ;
      pls_num      = 8'h6  ;
  @(posedge clk) #1
      pls_start    = 1'b0  ;
  @(negedge i_plsgen.plsen)
  #100
  // H:4clk,L:5clk  x 7cycle -----
  @(posedge clk) #1
      pls_start    = 1'b1  ;
      h_width      = 8'd4  ;
      l_width      = 8'd5  ;
      pls_num      = 8'h7  ;
  @(posedge clk) #1
      pls_start    = 1'b0  ;

  @(negedge i_plsgen.plsen)
  #100

  // test end -------------------
  $display ("") ;
  $display ("---- assertion result ------") ;
  $display ("[SVA] a_test1 : fire = %d , FAIL = %d",
                testbench.i_plsgen.i_sva_1.a_test1_fire,
                testbench.i_plsgen.i_sva_1.a_test1_fail ) ;
  $display ("[SVA] a_test2 : fire = %d , FAIL = %d",
                testbench.i_plsgen.i_sva_2.a_test2_fire,
                testbench.i_plsgen.i_sva_2.a_test2_fail ) ;

  $finish ;
  end
終了時に $display で表示する為、最後までシミュレーションが実行されないと回数表示はされない。

出力結果:

 実行結果の波形を以下に示す。
 発火 (PASS, FAIL) したタイミングが波形で判る。

実行結果の LOG を以下に示す。
****** xsim v2020.1 (64-bit)
  **** SW Build 2902540 on Wed May 27 19:54:35 MDT 2020
  **** IP Build 2902112 on Wed May 27 22:43:36 MDT 2020
    ** Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.

source xsim.dir/test_1/xsim_script.tcl
# xsim {test_1} -autoloadwcfg -runall
Vivado Simulator 2020.1
Time resolution is 1 ps
run -all

Time: 1140 ns Started: 220 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:36
a_test1 : FALE

Time: 2340 ns Started: 1260 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:36
a_test1 : OK

Time: 2360 ns Started: 1260 ns Scope: /testbench/i_plsgen/i_sva_2 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_2.sv Line:36
a_test2 : OK

Time: 3560 ns Started: 2480 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:36
a_test1 : OK

Time: 3580 ns Started: 2480 ns Scope: /testbench/i_plsgen/i_sva_2 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_2.sv Line:36
a_test2 : FALE

---- assertion result ------
[SVA] a_test1 : fire =     3 , FAIL =     1
[SVA] a_test2 : fire =     2 , FAIL =     1
$finish called at time : 3841 ns : File "/mnt/d/UserData/hobby/logic/study/test3/testbench/tp.sv" Line 52
exit
INFO: [Common 17-206] Exiting xsim at Fri Sep  4 01:02:27 2020...
~
~

最後に発火回数 と FAIL 回数 が表示されている。

2020年8月16日日曜日

verilog : Vivado で SVA(アサーション) を試す

目的:

Vivado で SVA を使用してみる。

結果:

Vivado で SVA 並列アサーション を記述し、アサーションができることを確認した。
  • 2021/11/4 追記
    とくに問題なくアサーションできている。
  • 2020/10/16 追記
    前回から30日以上経過しているが、アサーション結果表示できている。
  • 2020/09/04 追記
    再実行で アサーションの表示が また 出力されるようになった。
    先日、Windows版の vivado を Update したが、この影響か ?
  • 2020/08/29 追記
    再実行したところ、アサーションの表示が 出力されない。
    WEB PACK ではサポートされず、30日間無償評価で使用できていたと思われる。
但し、
  1.  property に 引数 を付けるとエラー が発生する。
  2. アサーションの結果は 波形には表示されない。
  3. アサーションの結果は Fail 時 のみ ログ, ディスプレイ に表示される。
    ( 特に処理の記述を行わない場合 )
となる。
以下のパターンで試しただけなので、他にも注意点があるかもしれないし、上の点も 設定, 記述方法等があるかもしれないが、SVA は使用可能。
(尚、波形への表示については「Vivado で SVA(アサーション) を試す 2」を参照。)

SVA 適用手順:

Vivado の コマンドラインでのシミュレーション環境 をベースに SVA を適用した。
( SVA 適用後の サンプルは こちら を参照。)
  1. ディレクトリ構成
    アサーション格納用として assertion ディレクトリを作成
  2. アサーション用ファイルの作成
    アサーション用ファイルとして
    1. SVA ファイル ( アサーション記述のモジュール )
    2. bind ファイル ( SVA のモジュールを rtl に接続する記述 )
    3. bind リスト ( bind ファイルを インクルードする為の リスト )
    を作成する。
  3. bind ファイルのインクルード
    テストベンチに 上 の bind リスト を インクルードする。
  4. プロジェクトファイル (vlog.prj) 修正
    vlog.prj に SVA ファイル を追加する。
以上で、SVA が適用される。

SVA 適用例:

SVA 適用例を以下に示す。
  1. テストベンチ ( Vivado の コマンドラインでのシミュレーション環境からの差分 )
      end
    
    // include test patteern  ------------
    `include "tp.sv"
    
    // include assertion bind list -------
    `include "./assertion/bind.list"
    
    
    endmodule
    

  2. bind リスト
    `include "./assertion/bind_sva.sv"
    
    bind ファイルのインクルード文を記述する。
     
  3. bind ファイル
    bind testbench.i_plsgen sva_1 i_sva_1(
      .clk    (clk),
      .clr    (clr),
      .start  (pls_start),
      .en     (plsen),
      .outpls (output_pls)
    ) ;
    
    bind testbench.i_plsgen sva_2 i_sva_2(
      .clk    (clk),
      .clr    (clr),
      .start  (pls_start),
      .en     (plsen),
      .outpls (output_pls)
    ) ;
    
    ここでは、 2つのアサーションファイルをバインドしている。
    それぞれ RTL (i_plsgen) にバインド
    testbench には バインドできない ?
     
  4. SVA ファイル
    アサーションファイルを以下に示す。
    尚、アサーションの適不適は不問とする。
    ( RTL は パルス生成回路 )
    // -----------------------------------------------------
    //   Sample module
    //
    //   Module Name : sva_1
    //   Version     : 0.00
    // -----------------------------------------------------
    
    module sva_1 ( clk, clr, start, en, outpls) ;
      input clk ;
      input clr ;
      input start ;
      input en ;
      input outpls ;
    
      // sequence description ----------------
      sequence S1 ;
        outpls[*4] ##1 !outpls[*5] ;
      endsequence
    
      // property description ---------------
      property p_test1 ;
        @(posedge clk ) disable iff(clr)
          $rose(start) |-> ##1 S1[*6] ;
      endproperty
    
      // assertion description
      a_test1 : assert property ( p_test1 ) ;
    
      endmodule
    
    sva_1 は、 start 信号の立ち上がりの次クロックから、"H 4サイクル, L 5サイクル"のシーケンスを 6回繰り返すことをチェックする。
     
    // -----------------------------------------------------
    //   Sample module
    //
    //   Module Name : sva_2
    //   Version     : 0.00
    // -----------------------------------------------------
    
    module sva_2 ( clk, clr, start, en, outpls) ;
      input clk ;
      input clr ;
      input start ;
      input en ;
      input outpls ;
    
      // sequence description ----------------
      sequence S1 ;
        outpls[*4] ##1 !outpls[*5] ;
      endsequence
    
      // property description ---------------
      property p_test2 ;
        @(posedge clk ) disable iff(clr)
          $rose(start) |-> ##1 S1[*6] |-> ##1 $fell(en) ;
      endproperty
    
      // assertion description ---------------
      a_test2 : assert property ( p_test2 ) ;
    
      endmodule
    
    sva_2 は、 start 信号の立ち上がりの次クロックから、"H 4サイクル, L 5サイクル"のシーケンスを 6回繰り返した後、次サイクルで en が 立ち下がることをチェックする。
    尚、sva_1, sva_2 の 2ファイルに分ける必要は無いが (通常は 1つのファイル(モジュール) に a_test1 と a_test2 の 両方を記述する) 、サンプルの為 2つのファイルに分けている。
      
  5. プロジェクトファイル (vlog.prj)
    verilog xil_defaultlib  \
    "./rtl/plsgen.v" \
    "./rtl/D_CNT.v" \
    
    sv xil_defaultlib  \
    "./testbench/testbench.sv" \
    "./testbench/param.sv" \
    "./assertion/sva_1.sv" \
    "./assertion/sva_2.sv" \
    
    verilog xil_defaultlib "/tools/Xilinx/Vivado/2020.1/data/verilog/src/glbl.v"
    
    プロジェクトファイルに sva_1.sv, sva_2.sv を追加する。
     

SVA 適用結果:

SVA 適用後の シミュレーション実行結果を以下に示す。
****** xsim v2020.1 (64-bit)
  **** SW Build 2902540 on Wed May 27 19:54:35 MDT 2020
  **** IP Build 2902112 on Wed May 27 22:43:36 MDT 2020
    ** Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.

source xsim.dir/test_1/xsim_script.tcl
# xsim {test_1} -autoloadwcfg -runall
Vivado Simulator 2020.1
Time resolution is 1 ps
run -all
ERROR: Assertion failed.
Time: 1140 ns Started: 220 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:28
ERROR: Assertion failed.
Time: 3580 ns Started: 2480 ns Scope: /testbench/i_plsgen/i_sva_2 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_2.sv Line:28
$finish called at time : 3841 ns : File "/mnt/d/UserData/hobby/logic/study/test3/testbench/tp.sv" Line 42
exit
INFO: [Common 17-206] Exiting xsim at Sun Aug 16 15:08:32 2020...
この時の波形

テストパターンは、3回 パルスを生成。
1回目は "H" 4 クロック, "L" 5クロック を 5回繰り返し
 6回目の"H" が無い為、a_test1 が Fail
 a_test2 は 6回目 の "H" が無く 前提部が不成立の為、発火しない。(Fail しない)
2回目は H4 クロック, L5クロック を 6回繰り返し
 a_test1, a_test2 共に 発火し、Pass。

3回目は H4 クロック, L5クロック を 7回繰り返し
 6回目の "H" がある為、a_test1 は発火し、Pass
 6回目の "H"→"L" の後 7回目が開始し、en (plsen) が 立ち下がらない為、Fail
期待通り、1回目, 3回目 のパルス生成で Fail し、エラー出力されている。

発火確認:

上の結果では、Fail した場合は ERROR 表示されるが、Fail しない場合は 何も表示されない。
この為、Pass したのか 発火しなかったのかの区別がつかない。
発火した場合に表示する様に SVA ファイルを修正してみる。
  // assertion description
  a_test1 : assert property ( p_test1 ) $display("a_test1 : OK") ;

  endmodule
  // assertion description ---------------
  a_test2 : assert property ( p_test2 ) $display("a_test2 : OK") ;

  endmodule
assert文 に 処理 ($display 等) を追加する。
処理追加後の結果は下の通り。

****** xsim v2020.1 (64-bit)
  **** SW Build 2902540 on Wed May 27 19:54:35 MDT 2020
  **** IP Build 2902112 on Wed May 27 22:43:36 MDT 2020
    ** Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.

source xsim.dir/test_1/xsim_script.tcl
# xsim {test_1} -autoloadwcfg -runall
Vivado Simulator 2020.1
Time resolution is 1 ps
run -all
ERROR: Assertion failed.
Time: 1140 ns Started: 220 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:28

Time: 2340 ns Started: 1260 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:28
a_test1 : OK

Time: 2360 ns Started: 1260 ns Scope: /testbench/i_plsgen/i_sva_2 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_2.sv Line:28
a_test2 : OK

Time: 3560 ns Started: 2480 ns Scope: /testbench/i_plsgen/i_sva_1 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_1.sv Line:28
a_test1 : OK
ERROR: Assertion failed.
Time: 3580 ns Started: 2480 ns Scope: /testbench/i_plsgen/i_sva_2 File: /mnt/d/UserData/hobby/logic/study/test3/assertion/sva_2.sv Line:28
$finish called at time : 3841 ns : File "/mnt/d/UserData/hobby/logic/study/test3/testbench/tp.sv" Line 42
exit
INFO: [Common 17-206] Exiting xsim at Sun Aug 16 16:19:29 2020...

実行結果は、
1回目 (started: 220nS) は a_test1 Fail し、a_test2 は発火なし。
2回目 (started: 1260nS) は a_test1, a_test2 共に発火し、Fail なし。
3回目 (Started: 2480nS) は a_test1 は発火して Failなし, a_test2 は Fail。
となり、発火したことを確認できる。

できれば、波形に 表示されるといいのだが、、、
 → 表示案 : Vivado で SVA(アサーション) を試す 2 

2020年8月14日金曜日

verilog : Vivado の コマンドラインでのシミュレーション環境

目的:

Vivado のシミュレーション をコマンドラインで 実行する環境を作る 。
 ( Icarus Verilog と同様な環境でシミュレーションできるようにする )


概要:

Ivarus Verilog 用に作成した環境と同様の環境とする。

ディレクトリ構成

以下の様にディレクトリを分ける。
rtl         : 論理合成可能な RTL を格納する
testbench   : テストベンチ を格納する
testpattern : テストパターン を格納する。
log         : コンパイル,シミュレーション時の LOG を格納する。
xsim_dir    : コンパイル時に生成される作業ディレクトリ。
wave        : シミュレーション結果の波形ファイルを格納する。

コンパイル, シミュレーション実行

カレントディレクトリに Makefile、vlog.prj を作成し、
make TESTNAME=test_1
の様に テストパターンを指定してコンパイル、シミュレーションを実行できる様にする。
コンパイル、シミュレーション時に実行 LOG を log ディレクトリ下に生成/移動する。
シミュレーション結果の波形は、wave ディレクトリに 移動した <TESTNAME>.vcd を gtkwave 等で確認する。

vlog.prj は、verilog のファイル構成を記したファイル。
コンパイル、シミュレーションは vivado のプロジェクトは作成せず、コマンド実行のみで行う。

詳細:

ディレクトリ構成は、概要の通り。
サンプルの環境は こちら を参照。(rtl, testbench の内容についての説明は省略)
サンプルは パルス生成回路。
テストパターンは test_1. sv と test_2.sv
make TESTNAME=test_1
make TESTNAME=test_2
でそれぞれ異なるパルス出力 (output_pls) が発生。

尚、vivado のインストールは、
Windows : WSL に Vivado をインストールする
を参照。

テストベンチ構成

テストパターン(項目) に依存しない共通部分を testbench.sv に記述。
テストパターン(項目)毎の記述は、パターンごとにファイルを作成し、testpattern ディレクトリに格納する。
make 実行時に、実行するテストパターン(項目)のファイルを testbench ディレクトリにtp.sv のファイル名でコピーし、testbench.sv から include で 呼び出す。

vlog.prj 例

vlog.prj は、以下を記述する。
verilog <work_library> <file_names>...
sv <work_library> <file_names> ...
verilog xil_defaultlib  \
"./rtl/plsgen.v" \
"./rtl/D_CNT.v" \

sv xil_defaultlib  \
"./testbench/testbench.sv" \
"./testbench/param.sv" \

verilog xil_defaultlib "/tools/Xilinx/Vivado/2020.1/data/verilog/src/glbl.v"
* /tools/Xilinx/ は、Vivado をインストールしたディレクトリ
vlog.prj にvhdl のソースを記述する。
verilog のファイルは verilog に、SystemVerilog のファイルは sv に記述する。
また、glbl.v を記述する必要がある。


Makefile 例

# ==============================================

TESTNAME = default

# -- SHELL setting -------------------------
SHELL=/bin/bash -o pipefail

# -- dir setting ---------------------------
TBDIR  = ./testbench
TPDIR  = ./testpattern
WAVE   = ./wave
LOG    = ./log

# -- compile option ------------------------
VLOGOPT  = -log $(LOG)/xvlog.log
VLOGOPT += -prj vlog.prj

ELABOPT  = -timescale 1ns/100ps
ELABOPT += -log $(LOG)/xelab.log
ELABOPT += -debug typical
ELABOPT += -L xil_defaultlib

# -- simulation option ---------------------
SIMOPT   = -log $(LOG)/simulate.log
SIMOPT  += -R

# -- wave file name ------------------------
VCD_NAME = wave.vcd

# -- Description ---------------------------
all : clean comp  sim

comp :
 # --- testpattern copy to tp.sv ----------------------------
ifeq ($(TESTNAME),default)
 echo >| $(TBDIR)/tp.sv
else
 cp $(TPDIR)/$(TESTNAME).sv $(TBDIR)/tp.sv
endif
 # --- analysis ---------------------------------------------
 xvlog $(VLOGOPT) 2>&1 | tee $(LOG)/comp.log
 # --- elaborate --------------------------------------------
 xelab $(ELABOPT) xil_defaultlib xil_defaultlib.testbench  -s $(TESTNAME) 
 # --- move log file ----------------------------------------
 mv *.pb $(LOG)/. 2> /dev/null ; true
 mv webtalk.* $(LOG)/. 2> /dev/null ; true

sim :
 # --- simulation -------------------------------------------
 xsim $(SIMOPT) $(TESTNAME)
 # --- move log file ----------------------------------------
 mv *.log $(LOG)/. 2> /dev/null ; true
 mv *.jou $(LOG)/. 2> /dev/null ; true
 # --- move wave file ----------------------------------------
 mv *.wdb $(WAVE)/. 2> /dev/null ; true
 mv $(VCD_NAME ) $(WAVE)/$(TESTNAME).vcd

clean :
 rm $(LOG)/* 2> /dev/null ; true

Make file 内容
TESTNAME : テストパターンファイル名の拡張子を除いた部分。初期値として "default" を設定。
SHELL setting :Shell 設定。パイプ中でのエラーコードを返す様にする。
dir setting : 各ディレクトリ名を設定。
compile option : コンパイルオプション (xvlog, xelab のオプション )を指定する。simulation option : シミュレーションオプション (xsim のオプション)を指定する。
wave file name : 波形ファイル名。(テストベンチに記述しているファイル名)Description : make での 実行内容。

実行方法
make TESTNAME=<テストパターンファイル名(拡張子を除く)
で、テストパターンファイルに記述したテスト内容で コンパイル、シミュレーションし、gtkwave を起動する。
実行は、
  1. log ファイル を消去する。
  2. コンパイルを以下の順に行う。
    1. テストパターン ファイルを tp.sv のファイル名で testbench ディレクトリにコピーする。
      TESTNAME を指定しない場合( make のみで実行 ) は、空の tp.sv を作成する。
    2. コンパイル (xvlog) を実行する。
    3. エラボレーション (xelab) を実行する。
    4. ログファイルを LOGディレクトリに移動する。
  3. シミュレーション (xsim) を実行する。
    実行後、ログファイルを ログディレクディレクトリに移動する。
    また、結果 (波形ファイル wave.vcd) を wave ディレクトリ下に <テストパターン名>.vcd として移動する。
の順に行う。
波形の確認は gtkwave で行う。wave ディレクトリで、
gtkwave <テストパターン名>.vcd