Veriloggenって何だろう(7)Parameter Delay Mux Sra

Verilog HDL を生成するための記述を python で行うことで FPGA 回路の生成を楽にする為のライブラリー Veriloggen を使ってみたいと思います。
今回はこう書くとこうなるという小技をいくつか、忘れないようにその部分だけ書いておきます。

便利関数の定義

veriloggen_util.pyという名前で下記の関数を定義しておきます。

import subprocess
import veriloggen as vg

# %%
def addtimescale(fname):
    '''
    指定されたファイルの先頭にtimescaleを挿入
    '''
    with open(fname) as f:
        l = f.readlines()
    l.insert(0,"`timescale 1ns/1ns \n")
    with open(fname, mode='w') as f:
        f.writelines(l)


# %%
def dset(t):
    '''
    代入分遅延用delayをEmbeddedCodeで埋め込み
    '''
    return vg.EmbeddedCode('#{}'.format(t))


# %%
def num2h(x, bit):
    '''
    数字を16進verilogフォーマット文字に変換してEmbeddedCodeで埋め込み
    '''
    n = int((bit+3)/4)
    st = "{0}'h{1:0>"+str(n)+"x}"
    return vg.EmbeddedCode(st.format(bit,x))


# %%
def num2b(x, bit):
    '''
    数字を16進verilogフォーマット文字に変換してEmbeddedCodeで埋め込み
    '''
    n = bit
    st = "{0}'b{1:0>"+str(n)+"b}"
    return vg.EmbeddedCode(st.format(bit,x))


# %%
def view_waveform_gtkwave(filename='uut.vcd', background=False):
    '''
    シミュレーション結果の表示
    '''
    cmd = []
    cmd.append('gtkwave')
    cmd.append('--giga')
    cmd.append(filename)
    if background:
        cmd.append('&')
    subprocess.run(cmd)


# %%
def run_iverilog(inputfile, top=None, outputfile='a.out'):
    '''
    iverilog コンパイル
    '''
    cmd = []
    cmd.append('iverilog')
    cmd.append(inputfile)
    if top is not NONE:
        cmd.append('-s')
        cmd.append(top)
    cmd.append('-o')
    cmd.append(outputfile)
    subprocess.run(cmd)


# %%
def run_vvp(inputfile='a.out'):
    '''
    vvp シミュレーション実行
    '''
    cmd=[]
    cmd.append('vvp')
    cmd.append(inputfile)
    subprocess.run(cmd)


# %%
def delete_file(fname):
    '''
    ファイル削除
    '''
    cmd = []
    cmd.append('del')
    cmd.append('fname')
    subprocess.run(cmd,shell=True)

パラメータリストの作り方

python側で作った値のリストをパラメータとして埋め込むことができます。

    import veriloggen_util as vu
    para = [i*7 for i in range(12)]
    paralist = [m.Parameter('p{0:0>2d}'.format(i),
                vu.num2b(para[i], 8)) for i in range(len(para))]

Verilog展開結果

  parameter p00 = 8'b00000000,
  parameter p01 = 8'b00000111,
  parameter p02 = 8'b00001110,
  parameter p03 = 8'b00010101,
  parameter p04 = 8'b00011100,
  parameter p05 = 8'b00100011,
  parameter p06 = 8'b00101010,
  parameter p07 = 8'b00110001,
  parameter p08 = 8'b00111000,
  parameter p09 = 8'b00111111,
  parameter p10 = 8'b01000110,
  parameter p11 = 8'b01001101

使い方は

    seq.add(count(count+paralist[1]))

の様にpythonのリストの様に使えます。
展開されると こんな感じ

      count <= count + p01;

慣性遅延(inertial delay)

代入文の遅延の記述方法が分からなかったので、dset(t)という関数を定義してEmbeddedCode( )で#付きの数字を埋め込むことにします。これにより慣性遅延は次のように書けます。

    seq.add(data2(data1, ldelay=vu.dset(5))

展開すると

    #5 data2 <= data1;

の様に式の左側にdelayが挿入されます。

伝播遅延(transport delay)

伝搬遅延は次のようにして書けます。

    seq.add(data2(data1, rdelay=vu.dset(5)))

展開すると

    data2 <= #5 data1;

の様に式の右側にdelayが挿入されます。

連接演算子 { } の書き方

連接演算子はVeriloggenのCatで作ることができます。

    m.Assign(data2(vg.Cat(data1,vu.num2b(3,4))))

展開すると

    assign data2 = { data1, 4'b0011 };

となります。

マルチプレクサ Mux

マルチプレクサはveriloggenのMuxを使って作成することができます。
下記の様にして絶対値変換が書けます。
pythonの便利なところとしてdata[-1]と言うように書いて最上位bitが指定できます。

    data = m.Reg('data', 8 ,signed=True)
    absdata = m.Wire('absdata', 8, signed=True)
    ...........................
    m.Assign(absdata(vg.Mux(data[-1], ~data+1, data)))

展開すると次のようになります。

  reg signed [8-1:0] data;
  wire signed [8-1:0] absdata;
    ...........................
  assign absdata = (data[7])? ~data + 1 : data;

論理シフトと算術シフト

veriloggenにはシフトのために
論理左シフト: Sll
論理右シフト: Srl
算術右シフト: Sra
があります。
それぞれ次のように書けます。

    seq.add(data2(vg.Sll(data1,1)))
    seq.add(data2(vg.Srl(data1,1)))
    seq.add(data2(vg.Sra(data1,1)))

展開すると次のようになります。

    data2 <= data1 << 1;
    data2 <= data1 >> 1;
    data2 <= data1 >>> 1;

算術シフトが機能するためには変数はsignedで定義されていなくてはいけません。