Veriloggenって何だろう(2)LEDチカチカ

Verilog HDLを生成するための記述をpythonで行うことでFPGA回路の生成を楽にする為のライブラリーVeriloggenを使ってみたいと思います。
前回はWindows上に環境を作ったので、さっそくサンプルを動かしてみましょう。

veriloggen サンプルのダウンロード

サンプルは下記のリンクのexamplesにあります。

github.com

veriloggenのバージョンアップに応じてサンプルも変わっているようです。インストールしたveriloggenのバージョンのものを見るようにしましょう。

f:id:feynman911:20181015233611j:plain

veriloggenのバージョンはAnaconda Promptを開いてverilog環境に切り替え、conda listで見ることができます。

>activate verilog
>conda list
・・・
veriloggen                1.2.0                     <pip>
・・・

examplesをダウンロードしたい時にはveriloggen全体をtagをバージョンに合わせておいて、「Download ZIP」でまとめてダウンロードするのが良いでしょう。(最新版1.2.0になってます)

f:id:feynman911:20181015234214j:plain

Spyderの起動

Pythonコマンドラインで使うのは面倒なので、Spyderを使いましょう。
「スタート」-「Anaconda3」-「Spyder(verilog)」からSpyderを立ち上げます。
前回の様に仮想環境を設定してあると、標準環境の「Spyder」の他にveriloggenをインストールした環境用に「Spyder(verilog)」が登録されているはずです。

まずはexamplesのled.pyをベースに機能確認をしましょう。

※「Spyder(verilog)」でワーニングが出る時には「Anaconda Navigator」から verilog 仮想環境でSpyderを起動してみてください。

LEDチカチカ

led.pyを読み込むか、新規作成します。分かりやすくするために、少し下記の様に手を加えました。

import veriloggen as vg

#%% LEDチカチカ本体のモジュールblinkledを生成(HDL変換のターゲット)
def mkLed():
    m = vg.Module('blinkled')
    width = m.Parameter('WIDTH', 8)
    clk = m.Input('CLK')
    rst = m.Input('RST')
    led = m.OutputReg('LED', width)
    count = m.Reg('count', 32)

    m.Always(vg.Posedge(clk))(
        vg.If(rst)(
            count(0)
        ).Else(
            vg.If(count == 1023)(
                count(0)
            ).Else(
                count(count + 1)
            )
        ))
    
    m.Always(vg.Posedge(clk))(
        vg.If(rst)(
            led(0)
        ).Else(
            vg.If(count == 1024 - 1)(
                led(led + 1)
            )
        ))
    
    return m

#%% blinkledにクロックとリセット信号をつないでテストするモジュールtestを生成
def mkTest():
    m = vg.Module('test')
    
    # target instance
    led = mkLed()
    
    # copy paras and ports
    params = m.copy_params(led)
    ports = m.copy_sim_ports(led)
    
    clk = ports['CLK']
    rst = ports['RST']
    
    uut = m.Instance(led, 'uut',
                     params=m.connect_params(led),
                     ports=m.connect_ports(led))
    
    vg.simulation.setup_waveform(m, uut, m.get_vars())
    vg.simulation.setup_clock(m, clk, hperiod=5)
    init = vg.simulation.setup_reset(m, rst, m.make_reset(), period=100)
    
    init.add(
        vg.Delay(1000 * 100),
        vg.Systask('finish'),
    )

    return m

#%% メインルーチン testモジュールをVerilog HDLに変換してシミュレーション     
if __name__ == '__main__':
    test = mkTest()
    verilog = test.to_verilog('tmp.v')
    print(verilog)
    
    sim = vg.simulation.Simulator(test)
    rslt = sim.run()
    print(rslt)

    sim.view_waveform()


緑三角をクリックして led.py を実行すると、ちゃんと動けばフォルダーに Verilog HDL に変換されたファイル tmp.v、iverilog の中間ファイル a.out、vvp でシミュレーションした結果の uut.vcd ができているはずです。

f:id:feynman911:20181016225921j:plain

同時に、シミュレーション結果 uut.vcd が読み込まれた状態で gtkwave が立ち上がるはずです。

f:id:feynman911:20181016231707j:plain


Veriloggen によって作られた Verilog HDL は tmp.v にありますが、次のようなものです。

module test #
(
  parameter WIDTH = 8
)
(

);

  reg CLK;
  reg RST;
  wire [WIDTH-1:0] LED;

  blinkled
  #(
    .WIDTH(WIDTH)
  )
  uut
  (
    .CLK(CLK),
    .RST(RST),
    .LED(LED)
  );


  initial begin
    $dumpfile("uut.vcd");
    $dumpvars(0, uut, CLK, RST, LED);
  end


  initial begin
    CLK = 0;
    forever begin
      #5 CLK = !CLK;
    end
  end


  initial begin
    RST = 0;
    #100;
    RST = 1;
    #100;
    RST = 0;
    #100000;
    $finish;
  end


endmodule



module blinkled #
(
  parameter WIDTH = 8
)
(
  input CLK,
  input RST,
  output reg [WIDTH-1:0] LED
);

  reg [32-1:0] count;

  always @(posedge CLK) begin
    if(RST) begin
      count <= 0;
    end else begin
      if(count == 1023) begin
        count <= 0;
      end else begin
        count <= count + 1;
      end
    end
  end


  always @(posedge CLK) begin
    if(RST) begin
      LED <= 0;
    end else begin
      if(count == 1023) begin
        LED <= LED + 1;
      end 
    end
  end


endmodule

module blinkled が肝心の部分です。
Veriloggen の Always が Verilog HDL の always になったのが分かります。Veriloggen を使うことで、読み易くはなりましたがほとんど1対1なので行数はほとんど同じで、まだこの段階では今一つな感じです。
とりあえず動いたので今回はここまで。
次回は、モジュールの組み立て方と Always について書いてみます。