3---Python初体験の簡単TestBench自動生成+Verilogモジュール信号抽出

17029 ワード

Pythonの基礎文法を勉強した後、確かにPythonの優美な表現に惹かれたので、Pythonで何かをしたいと思っていましたが、これまでMATLABスクリプトでTestBenchの自動生成を完成させたいと思っていましたが、ここはちょうどPythonで完成しました.TestBenchは主に以下の3つの部分を含む.
  • 基本クロックclkとリセットrstの生成
  • ファイルのデータを読み込む
  • .
  • は、モジュールのインタフェース信号を抽出し、
  • を実例化する.
    最初の2つの部分は通常のファイル書き込み操作で完了し、3番目の部分は少し複雑で、正規表現でモジュールの名前、信号の名前、ビット幅などを抽出する必要があります.総じて言えば、これは簡単なコードです.
    また、第3部をVerilogサブモジュールの最上位ファイルとして自動的に生成し、接続線をコピーして貼り付ける手間を省くことができます.
    分刻みでPythonをマスターするリンクを貼ります.http://www.code123.cc/1049.html
    1.プログラム構造と実行プロセス
    1.1プログラム構造
    このプログラムには3つのファイルがあります.
    プライマリファイル
    文字列ファイル
    モジュール抽出関数ファイル
    verilog_tb_gen.py
    config.py
    extract_interface.py
    _
  • 文字列ファイルには、いくつかの固定印刷情報
  • が格納されている.
  • モジュール抽出関数ファイルでは、モジュールインタフェース情報全体の抽出と印刷が完了する
  • .
  • マスターファイル完了スケジューリング管理
  • 1.2運転プロセス
  • simファイルを開くか新規作成します.
  • configからクロックとリセットを生成する文字列を抽出しsimファイルに書き込む.
  • 同上:memory初期化文字列を抽出する;
  • 同上:memoryデータ読み出しのalwaysブロック文字列を抽出する;
  • 呼び出しモジュール抽出関数は、指定されたファイルのインタフェース情報を抽出しsimファイルに書き込む.
  • ファイルを閉じます._モジュール抽出関数フロー:この関数には3つのセクションがあり、各セクションのフローはほぼ一致しています.
  • 抽出ファイルの文字を行ごとに文字列リストに分離し、変数に付与する.
  • インタフェース情報を含む正規表現をプリコンパイルする.
  • forループを利用して各行の中でこの正規表現を検索し、検索したら次のステップに進む.
  • 検索された文字列をスペースまたはカンマで個別の文字列に分離することで、下付き文字に基づいてインタフェースの情報を抽出することができる.
  • は、抽出された情報をsimファイルに書き込む.


  • 2.プロセスで使用する操作説明
    1.2の流れで:1.開く、閉じる、書き込みなどのファイル操作は他の言語とほぼ一致しており、詳細はリンクを参照してください.http://blog.csdn.net/qq_16923717/article/details/77716137 2. 2、3、4ステップは基本的な印刷とテキストの置換であり、一般的なprintと同じである.3.モジュールインタフェース情報抽出に用いる操作及び参考リンクは以下の通りである.
  • はread()とsplitline()を使用して読み取り、支店化されます.http://blog.csdn.net/nanjunxiao/article/details/9086079
  • 正規表現、注意re.matchとre.searchの違い、およびなぜ正規表現を事前にコンパイルするのか菜鳥教程正規表現廖雪峰Python教程正規表現
  • 正規表現の説明:プログラムで最も長い正規表現を次に示します.
    re_interface = re.compile('(input|output)(\s+|\[\d+:0\]|\s+\[\d+:0\]|\[\d+:0\]\s+|\s+\[\d+:0\]\s+)\w+(,(\s+|)\w+){0,10}')

    この正規表現は、入力信号と出力信号の名前とビット幅情報がマッチしています.Verilogが書く様々な状況を考慮しているので、この正規表現はそんなに長くはありません.インタフェースが規範的であれば、実は短いです.正規表現の3つの記号に注意してください.
  • 反スラッシュ'':式のs+は少なくとも1つのスペースを一致させ、w+は少なくとも1つのアルファベット、数字、または下線を一致させ、d+は少なくとも1つの数字を一致させるなど、エスケープ文字として使用されます.
  • 縦線’|’:表示または操作、例えば(input|output)入力と出力とを一致させることができる.
  • 括弧():論理分離
  • Verilog入出力の可能な書き方は以下の通りです.
    //            
    input   sig_1;
    output  sig_2;
    //            ,        
    input           signal_1;               //    1,      
    input[1:0]signal_2;                     //       
    input   [1:0]signal_3;                  //      
    input[1:0]  signal_4;                   //      
    input   [1:0]   signal_5;               //       
    //                '\w+'            
    //                         ,  ', signal_7',            10 
    input           signal_6, signal_7;     //        ,         
    input           signal_8,signal_9;      //        

    3.付録
    verilog_tb_gen.pyコード
    '''
    Verilog testbench generator
    '''
    import re
    import config
    import extract_interface
    
    # parameter
    NAME = 'fir_sim'                            # tb name 
    PERIOD = 10                                 # clock period: ns
    RST_DELAY = 200                             # reset delay : ns
    DATA_WIDTH = 32                             # rom data width
    DATA_LEN = 301                              # rom data length
    PATH = r'D:\my_prj\my_filter_hdl_1\my_filter_hdl_1.srcs\msg.dat'        
                                                # memory path
    
    # open and truncate file
    fp = open('%s.v' % NAME, 'w')
    fp.truncate()
    
    # print clk and rst
    fp.write(config.mod_clk_rst % (NAME, PERIOD, RST_DELAY))
    fp.write(config.divide)
    # print rom
    fp.write(config.memory % (DATA_WIDTH - 1, DATA_LEN, PATH.replace('\\','/')))
    fp.write(config.divide)
    # print source data
    fp.write(config.src_data % (DATA_WIDTH - 1, DATA_LEN))
    fp.write(config.divide)
    fp.write(config.divide)
    '''
    Extract module interface
    '''
    extract_interface.extract_print('fir_hdl.v', 0, fp)     # Extract file1
    extract_interface.extract_print('fir.v', 1, fp)         # Extract file2
    
    # The end, close the file
    fp.write('

    endmodule'
    ) fp.close()

    config.pyコード
    '''
    Verilog testbench generator
    String
    '''
    
    # module clk rst
    mod_clk_rst = 'module %s;
    \ parameter PERIOD = %d;
    \ reg clk = 1;
    \ reg rst = 1;

    \ initial begin
    \ forever
    \ #(PERIOD/2) clk = ~clk;
    \ end

    \ initial begin
    \ #%d
    \ rst = 0;
    \ end

    \ '
    # divide divide = '//------------------------------------------------------------
    '
    # memory memory = 'reg [%d:0] datain[0:%d];
    \ initial begin
    \ $readmemb("%s", datain);
    \ end

    \ '
    # source data src_data = "reg\t[15:0]\t\ti;
    \ reg\t[%d:0]\t\tsource_data;
    \ reg\t\t\t\tsource_data_vld;

    \ always @ (posedge clk) begin
    \ if (rst) begin
    \ i <= 'd0;
    \ source_data <= 'd0;
    \ source_data_vld <= 'd0;
    \ end
    \ else if (i < %d) begin
    \ i <= i + 1;
    \ source_data <= datain[i];
    \ source_data_vld <= 1;
    \ end
    \ else begin
    \ i <= i;
    \ source_data <= 'd0;
    \ source_data_vld <= 'd0;
    \ end
    \ end

    \ "

    extract_interface.pyコード
    '''
    Verilog testbench generator
    Extract module interface
    '''
    
    import re
    
    def extract_print( path, u, fp ):                               # u         
        with open(path, 'r') as dotv:
            split_as_lines = dotv.read().splitlines()
        # Extract output wire
        re_wire = re.compile('output(\s+|\[\d+:0\]|\s+\[\d+:0\]|\[\d+:0\]\s+|\s+\[\d+:0\]\s+)\w+(,(\s+|)\w+){0,10}')
        for i in range(len(split_as_lines)):
            x = re_wire.search(split_as_lines[i])
            if x:
                wire_list = re.split(r'[\s\,]+', x.group(0))
                if re.match('\[', wire_list[1]):
                    width_info = wire_list[1]
                    indx = 2
                else: 
                    width_info = '\t'
                    indx = 1
                for j in range(len(wire_list) - indx):
                     fp.write('wire\t%s\t\t%-20s;
    '
    % (width_info, wire_list[j + indx])) fp.write('
    '
    ) # Extract module name re_module_name = re.compile('module\s+\w+') # for i in range(len(split_as_lines)): y = re_module_name.search(split_as_lines[i]) if y: module_name = re.split('\s+', y.group(0))[1] fp.write('%-19su%-6d(
    '
    % (module_name, u)) # module name # Extract interface re_interface = re.compile('(input|output)(\s+|\[\d+:0\]|\s+\[\d+:0\]|\[\d+:0\]\s+|\s+\[\d+:0\]\s+)\w+(,(\s+|)\w+){0,10}') k = 0 for i in range(len(split_as_lines)): z = re_interface.search(split_as_lines[i]) if z: interface_string = re.sub(r'\[\d+:0\]', ' ', z.group(0)) interface_list = re.split(r'[\s\,]+', interface_string) for j in range(len(interface_list) - 1): if (k == 0): fp.write('\t.%-21s( %-20s)
    '
    % (interface_list[j+1], interface_list[j+1])) else: fp.write('\t,.%-20s( %-20s)
    '
    % (interface_list[j+1], interface_list[j+1])) k += 1 fp.write('\t);

    '
    ) return

    生成されたtbファイルは、tbがまだ完全なtbではないことに注意してください.
    module fir_sim;
    parameter PERIOD = 10;
    reg clk = 1;
    reg rst = 1;
    
    initial begin
        forever
        #(PERIOD/2) clk = ~clk;
    end
    
    initial begin
        #200
        rst = 0;
    end
    
    //------------------------------------------------------------
    reg [31:0] datain[0:301];
    initial begin
        $readmemb("D:/my_prj/my_filter_hdl_1/my_filter_hdl_1.srcs/msg.dat", datain);
    end
    
    //------------------------------------------------------------
    reg [15:0]      i;
    reg [31:0]      source_data;
    reg             source_data_vld;
    
    always @ (posedge clk) begin
        if (rst) begin
            i <= 'd0;
            source_data <= 'd0;
            source_data_vld <= 'd0;
        end
        else if (i < 301) begin
            i <= i + 1;
            source_data <= datain[i];
            source_data_vld <= 1;
        end
        else begin
            i <= i;
            source_data <= 'd0;
            source_data_vld <= 'd0;
        end
    end
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    wire    [31:0]      fir_out             ;
    
    fir_hdl            u0     (
        .clk                  ( clk                 )
        ,.fir_in              ( fir_in              )
        ,.fir_out             ( fir_out             )
        );
    
    wire    [31:0]      fir_out_TDATA       ;
    wire                fir_in_TREADY       ;
    wire                fir_out_TVALID      ;
    
    fir                u1     (
        .fir_in_TDATA         ( fir_in_TDATA        )
        ,.fir_out_TDATA       ( fir_out_TDATA       )
        ,.ap_clk              ( ap_clk              )
        ,.ap_rst_n            ( ap_rst_n            )
        ,.fir_in_TVALID       ( fir_in_TVALID       )
        ,.fir_in_TREADY       ( fir_in_TREADY       )
        ,.fir_out_TVALID      ( fir_out_TVALID      )
        ,.fir_out_TREADY      ( fir_out_TREADY      )
        );
    
    
    
    endmodule

    抽出されたソースファイルインタフェースfir.v
    module fir (
            fir_in_TDATA,
            fir_out_TDATA,
            ap_clk,
            ap_rst_n,
            fir_in_TVALID,
            fir_in_TREADY,
            fir_out_TVALID,
            fir_out_TREADY
    );
    
    input  [31:0] fir_in_TDATA;
    output  [31:0] fir_out_TDATA;
    input   ap_clk;
    input   ap_rst_n;
    input   fir_in_TVALID;
    output   fir_in_TREADY;
    output   fir_out_TVALID;
    input   fir_out_TREADY;

    fir_hdl.v
    module fir_hdl(
        input clk,
        input [31:0] fir_in,
        output [31:0] fir_out
        );