Verilog極簡略チュートリアル


文書ディレクトリ
  • チュートリアル説明
  • 運転環境
  • RTL:モジュール宣言と例化(Module)
  • RTL:定数
  • RTL:変数(wire,reg)
  • RTL:演算子
  • RTL:関数(function)
  • RTL:メモリ(SRAM)
  • RTL:メモリ(ROM)
  • TB:シミュレーション精度
  • TB:タスク(task)
  • TB:クロックとリセット生成(clock_reset_gen)
  • TB:波形ファイル生成(wave_dump)
  • TB:メモリ初期化(mem_init)
  • RUN : Makefile
  • RUN : Questasim(sim.do)

  • Verilogは持ってきたもので、学ぶためのものではありません.
    チュートリアルの説明
    これはVerilogの極めて簡単なチュートリアルで、日常の設計のほとんどの基本的な文法をカバーしています.
    文法は重要ではありません.肝心なのは実践です.
    完全なコードとシミュレーション環境はgithubで共有されています.
    実行環境
    
    # Centos Linux release 7.2.1511 
    cat /etc/redhat-release
    
    # QuestaSim-64 vlog 10.4c 
    vlog -version
    
    # Verdi 2001
    verdi 
    
    

    RTL:モジュール宣言とインスタンス化(Module)
  • ANSI-Cスタイルポートリスト
  • を使用
  • パラメトリック
  • inputはwire
  • です
  • outputはwireまたはreg
  • であってもよい
  • 最後のport ,
  • なし
  • 名前の関連付けを使用して
  • を例示する.
    
    module mini_top #(
        parameter NUM=8
    )(
        input             clk,       
        input             rst_n,     
        input  [15 :0]    i_cw,      
        output reg        o_flag,    
        output [NUM-1:0]  o_data_rd
    );
    
    // module instantiation 
    wire [15:0] cw;
    wire        flag;
    wire [15:0] data_rd;
    
    mini_top #(
        .NUM ( 16 )
    ) u_DUT (
        .clk       ( clk      ) ,
        .rst_n     ( rst_n    ) ,
        .i_cw      ( cw       ) ,
        .o_flag    ( flag     ) ,
        .o_data_rd ( data_rd  ) 
    );
    
    

    RTL:定数
  • defineを使用してグローバル定数
  • を定義する.
  • localparamを使用して局所定数
  • を定義する.
  • includeを使用して
  • を統一的に管理する.
  • hard-coded number
  • をできるだけ避ける
    
    `define NUM_1 8'b0001_1111
    `define NUM_2 8'h1F
    `define NUM_3 8'd31
    `define NUM_4 {4'h1, 4'b1111}
    `define NUM_5 {4'h1, {4{1'b1}}}
    
    localparam NUM_6 = 31;
    localparam NUM_7 = NUM_6;
    localparam NUM_8 = `NUM_1;
    localparam NUM_9 = `NUM_1 + NUM_6 - 31;
    
    

    RTL:変数(wire,reg)
  • 変数に適切な名前を付ける
  • wireは、組合せ論理
  • にのみ使用される
  • wire付与方式:assign、モジュール例化
  • regブロック付与記述組合せ論理
  • reg非ブロック付与記述タイミングロジック
  • 
    wire r_enable;
    wire r_start;
    wire r_stop; 
    wire r_invert;
    wire r_skip;
    
    assign {
        r_enable,
        r_start,
        r_stop,
        r_invert,
        r_skip
    } = i_cw[4:0];
    
    // reg
    // combinational logic
    
    reg flag;
    always @* begin
        flag = r_enable | r_skip | r_stop | r_invert;
    end
    
    // reg 
    // sequential logic
    reg       cnt_4b_is_0xa;
    reg [3:0] cnt_4b;
    
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            cnt_4b        <= 4'd0;
            cnt_4b_is_0xa <= 1'b0;
            o_flag        <= 1'b0;
        end
        else begin
            cnt_4b        <= cnt_4b + 4'd1;
            cnt_4b_is_0xa <= cnt_4b==4'ha ? 1'b1 : 1'b0;
            o_flag        <= cnt_4b ==4'h8 ? 1'b1 : 1'b0;
        end
    end
    
    

    RTL:演算子
  • 優先度
  • をカッコで保証
  • 優先順位表上位から下位へ
  • high: () [] {}
  • h0: ! ~
  • h1: */%
  • h2: + -
  • h3: << >>
  • h4: <<= >>=
  • h5: == != === !==
  • h6: &
  • h7: ^ ^~
  • h8: |
  • h9: &&
  • h10: ||
  • low: ? :


  • RTL:関数(function)
  • 統合可能
  • モジュールで定義する
  • は、少なくとも1つの入力
  • を含む.
  • 出力
  • は不可
  • 関数定義ではalwaysブロック文
  • は表示されません.
  • 関数定義では、関数
  • を呼び出すことができる.
    
    // function : max
    // 
    function [7:0] max;
        input [7:0] A;
        input [7:0] B;
        
        begin
            max = A < B ? B : A;
        end
    endfunction
    
    wire [7:0] temp_max;
    
    assign temp_max = max(i_din[7:0], NUM_6);
    
    

    RTL:メモリ(SRAM)
  • シミュレーション可能、統合可能、fpga
  • に使用可能
  • プロセスライブラリを使用するmemory compiler
  • module mini_sp_ram #(
        parameter ADDR_BITS=8
    )(    
        input             clk,
        input      [ 7:0] addr,
        input      [ 7:0] din,
        input             ce,
        input             we,
        output reg [ 7:0] dout
    );
    
    localparam MEM_DEPTH= 1<

    RTL:メモリ(ROM)
  • シミュレーション可能、統合可能、fpga
  • に使用可能
  • プロセスライブラリを使用するmemory compiler
  • 
    
    module mini_rom (    
        input             clk,
        input      [ 7:0] addr,
        output reg [ 7:0] dout
    );
    
    always @(posedge clk) begin
        case(addr)
            8'h00: dout <= 8'h0A;
            8'h01: dout <= 8'h1A;
            8'h02: dout <= 8'h2A;
            8'h03: dout <= 8'h3A;
            8'h04: dout <= 8'h4A;
            8'h05: dout <= 8'h5A;
            8'h06: dout <= 8'h6A;
            8'h07: dout <= 8'h7A;
            8'h08: dout <= 8'h8A;
            8'h09: dout <= 8'h9A;
            8'h0A: dout <= 8'hAA;
            8'h0B: dout <= 8'hBA;
            8'h0C: dout <= 8'hCA;
            8'h0D: dout <= 8'hDA;
            8'h0E: dout <= 8'hEA;
            8'h0F: dout <= 8'hFA;
    
            8'h10: dout <= 8'h50;
            8'h11: dout <= 8'h51;
            8'h12: dout <= 8'h52;
            8'h13: dout <= 8'h53;
            8'h14: dout <= 8'h54;
            8'h15: dout <= 8'h55;
            8'h16: dout <= 8'h56;
            8'h17: dout <= 8'h57;
            8'h18: dout <= 8'h58;
            8'h19: dout <= 8'h59;
            8'h1A: dout <= 8'h5A;
            8'h1B: dout <= 8'h5B;
            8'h1C: dout <= 8'h5C;
            8'h1D: dout <= 8'h5D;
            8'h1E: dout <= 8'h5E;
            8'h1F: dout <= 8'h5F;
    
            default: dout <= 8'hff;
        endcase
    end
    
    endmodule
    
    

    TB:シミュレーション精度(timescale)
  • またはエミュレータコマンドオプションで
  • を指定します.
    
    `timescale 1ns/10ps 
    
    

    TB:タスク(task)
  • 統合できない
  • 
    task hello;
        begin
            $display("hello world.");
        end
    
    endtask
    
    
    initial begin
        hello;
    end
    
    
    

    TB:クロックとリセット発生(clock_reset_gen)
    
    reg clk;
    reg rst_n;
    
    initial begin
        clk = 0;
    end
    
    // Be careful if CLOCK_CYCLE%2 !=0
    always #(`CLOCK_CYCLE/2) clk=~clk;
    
    
    

    TB:波形ファイル生成(wave_dump)
    
    // use +define+DUMP_FSDB in vsim command
    // to enable fsdb file dump
    //
    // -pli $(VERDI_HOME)/share/PLI/MODELSIM/$PLATFORM/novas_fli.so 
    //
    `ifdef DUMP_FSDB 
    initial begin
        $fsdbDumpfile("tb.fsdb");
        $fsdbDumpvars(0,tb);
        #`MAX_RUN_TIME
        $finish(2);
    end
    `endif
    
    

    TB:メモリ初期化(mem_init)
    
    // memory initilization
    integer fp_dmem;
    
    initial begin
        fp_dmem = $fopen(`MEM_INIT_FILE, "r");
        if(fp_dmem)
            #5 $readmemh(`MEM_INIT_FILE, `MEM_INST);
        else begin
            $display("%s open failed.",`MEM_INIT_FILE);
            $finish;
        end
    end
    
    

    RUN : Makefile
    
    PROJ_PATH = ../..
    
    RTL_PATH  = $(PROJ_PATH)/rtl
    TB_PATH   = $(PROJ_PATH)/sim/tb
    
    FILE_LIST = rtl.f
    DOFILE    = sim.do
    
    TB_TOP    = tb
    
    sim: 
    	@rm -rf work
    	vsim -c -do $(DOFILE) 
    
    verdi: 
    	@verdi -nologo -f $(FILE_LIST) -top $(TB_TOP) &
    
    clean:
    	@rm -rf *.ini *.fsdb *.log verdiLog transcript work 
    
    veryclean: clean
    
    listfile:
    	@ls $(RTL_PATH)/*.v  > $(FILE_LIST)
    	@ls $(TB_PATH)/*.v  >> $(FILE_LIST)
    
    

    RUN : Questasim(sim.do)
    vlib work
    vmap work work
    
    vlog -timescale=1ns/1ps +incdir=./ -work work \
        +define+DUMP_FSDB \
        -f rtl.f
    
    vsim +notimingchecks -t 1ps -novopt -L work -l tb.log \
        -pli $env(VERDI_HOME)/share/PLI/MODELSIM/LINUX64/novas_fli.so \
        work.tb
    
    run -all
    
    

    詳細Verilogの記事は、微信の購読番号に注目してください.