Verilog-HDL 文法(6):シミュレーション記述(2)
2015/09/27
[CategoryTop] [Prev] [Next]
[目次]・シミュレーション記述例(その2)
     + モチーフ回路はSRAM
     + テストベンチ

●シミュレーション記述例(その2)

 ◆モチーフ回路はSRAM
 
  ・今回はモチーフ回路をSRAMとしてテストベンチ記述/シミュレーション実行を行
   いたいと思います。SRAMは通常CB(Custom Block)として設計されることがほとん
   どですが、Simulation時には、動作モデルを作成して対応します。
  
  ・下記はReadアドレスとWriteアドレスが別に用意されている、いわゆる2ポート
   SRAMの動作概念図です。(*1)
 
   [Fig.1 SRAMモデルイメージ]
  ┌───────────────────────────────────────┐
   SRAMモチーフ回路モデル
  └───────────────────────────────────────┘
  
  ・また、クロックとデータの関係は以下のようになっていると仮定します。普通は
   ディレイありますが、今回は無しということで。

   [Fig.2 Write/Readシーケンス]
  ┌───────────────────────────────────┐
   シーケンス
  └───────────────────────────────────┘
  
  ・このSRAMをシミュレーション可能な記述にすると下記のようになります。

   [List.1 SRAMシミュレーションモデル]
  ┌───────────────────────────────────┐
   `timescale 1ns/1ns
   
   `define M_ADRW 4 // Address Bit Width
   `define M_DATW 16 // Data Bit Width
   `define M_DLY  1 // Delay Unit
  └───────────────────────────────────┘
  ┌───────────────────────────────────┐
   `timescale 1ns/1ns
   
   module mem_a16_d16 (
    wclk, rclk,
    din,  dout,
    waddr, raddr,
    we,  re
   );
    parameter ADRW = `M_ADRW;
    parameter DATW = `M_DATW;
    parameter DLY = `M_DLY;
    
    input        wclk; // Write Clock
    input        rclk; // Read Clock
    input [(DATW-1):0] din;  // Input Data
    output [(DATW-1):0] dout; // Output Data
    input [(ADRW-1):0] waddr; // Write Address
    input [(ADRW-1):0] raddr; // Read Address
    input        we;  // Write Enable
    input        re;  // Read Enable
    
    reg  [(DATW-1):0] mem [0:{ADRW{1'b1}}]; // Memory本体(Reg配列)
    
    reg  [(ADRW-1):0] waddrReg;
    reg         weReg;
    
    always @(posedge wclk) begin
      weReg  <= #(DLY) we;
      waddrReg <= #(DLY) waddr;
      if (weReg) mem[waddrReg] <= #(DLY) din;
    end
    
    
    reg  [(ADRW-1):0] raddrReg;
    reg         reReg;
    
    always @(posedge rclk) begin
      reReg  <= #(DLY) re;
      raddrReg <= #(DLY) raddr;
    end
    
    assign dout = (reReg)? mem[raddrReg] : {(DATW-1){1'bx}};
    
   endmodule
  └───────────────────────────────────┘

  ・上記RTLのポイントは、メモリセルのArray部にレジスタ配列を使用している点で
   す。この記述はシミュレーションのみで、合成ツールやATPGツールには適用でき
   ません(*2)。

  ・また、上記のSRAM動作モデルは、re/weが同時にassertされた場合や、waddrと
   raddrが同じ値だった場合にSRAMが何を出力するか(通常はZかX)が記述されてい
   ません。今回は省略していますが、本来であればこれらの動作についてもモデ
   ル内で記述します。
  
  ・また、これは合成対象にRTLにおいても意識する話ですが、FF/LATCH相当のレジ
   スタに値を代入する場合、必ずディレイを入れます。これは合成時にはツールか
   ら無視されますが、検証時にシミュレータによって実行結果に差が出ないように
   するためです。
  

 ◆テストベンチ
 
  ・テストの観点から言えば、ここではマーチパターン等を書くべきですが、とりあ
   えずは通常動作のシミュレーションを実施してみます。
  
  ・テストベンチの大まかな動作としては下記です。
    + 最初に全てのデータを読み出す(Xが読み出されるはず)
    + 次にアドレス展開したデータを書き込みます
      --> アドレス 0010 には 0010_0010_0010_0010 を書き込む
    + 最後に書き込んだデータを読み出します
   具体的な記述例と動作結果を示します。
   
   [List.2 SRAMシミュレーション テストベンチ]
  ┌───────────────────────────────────┐
   `timescale 1ns/1ns
   
   module mem_a16_d16_test;
    
    parameter CYC = 100;
    parameter ADRW = `M_ADRW;
    parameter DATW = `M_DATW;
   
    reg        clk;  // Clock (Synchronous)
    reg [(DATW-1):0] din;  // Write data
    reg [(ADRW-1):0] waddr; // Write address
    reg [(ADRW-1):0] raddr; // Read address
    reg        we;   // Write enable
    reg        re;   // Read enable
    
    wire [(DATW-1):0] dout;  // Read Data (Observe)
    
    always #(CYC/2) clk = ~clk; // clock
    
    integer idx;
    
    // ==== event write sequence ====
    event write_seq;
    always @(write_seq) begin
      #(0)  we = 1'b1;
          din = {4{waddr}};
      #(CYC) we = 1'b0;
          $display("Din [%4b]=%16b", waddr, din);
      #(CYC) waddr = waddr + 1'b1;
    end
    
    // ==== event preread sequence ====
    event preread_seq;
    always @(preread_seq) begin
      #(0)  re = 1'b1;
      #(CYC) re = 1'b0;
          $display("Dout[%4b]=%16b", raddr, dout);
      #(CYC) raddr = raddr + 1'b1;
    end
   
    // ==== event postread sequence ====
    event postread_seq;
    always @(postread_seq) begin
      #(0)  re = 1'b1;
      #(CYC) re = 1'b0;
          if (dout == {4{raddr}})
            $display("Dout[%4b]=%16b : PASS", raddr, dout);
          else
            $display("Dout[%4b]=%16b : FAIL", raddr, dout);
      #(CYC) raddr = raddr + 1'b1;
    end
   
    // ==== simple write/read ====
    initial begin
      // ---- initialize ----
      #(0)   clk = 1'b0;
           waddr = {ADRW{1'b0}};
           raddr = {ADRW{1'b0}};
           we  = 1'b0;
           re  = 1'b0;
      #(CYC*2);
      
      // ---- pre read ----
      $display("==== PreRead Sequence ====");
      for (idx={ADRW{1'b0}}; idx<={ADRW{1'b1}}; idx=idx+1'b1) begin
        -> preread_seq;
        #(CYC*3) ;
      end
      #(CYC*2);
      
      // ---- write ----
      $display("==== Write Sequence ====");
      for (idx={ADRW{1'b0}}; idx<={ADRW{1'b1}}; idx=idx+1'b1) begin
        -> write_seq;
        #(CYC*3) ;
      end
      #(CYC*2);
      
      // ---- post read ----
      $display("==== PostRead Sequence ====");
      for (idx={ADRW{1'b0}}; idx<={ADRW{1'b1}}; idx=idx+1'b1) begin
        -> postread_seq;
        #(CYC*3) ;
      end
      #(CYC) $finish;
    end
    
    
    // ==== memory instance ====
    mem_a16_d16 mem_a16_d16 (
      .wclk (clk),  .rclk (clk),
      .din (din),  .dout (dout),
      .waddr(waddr), .raddr(raddr),
      .we  (we),  .re(re)
    );
    
   endmodule
   
   ───────────────────────────────────
   [実行結果]
   ==== PreRead Sequence ====
   Dout[0000]=xxxxxxxxxxxxxxxx
   Dout[0001]=xxxxxxxxxxxxxxxx
   Dout[0010]=xxxxxxxxxxxxxxxx
   Dout[0011]=xxxxxxxxxxxxxxxx
   Dout[0100]=xxxxxxxxxxxxxxxx
   Dout[0101]=xxxxxxxxxxxxxxxx
   Dout[0110]=xxxxxxxxxxxxxxxx
   Dout[0111]=xxxxxxxxxxxxxxxx
   Dout[1000]=xxxxxxxxxxxxxxxx
   Dout[1001]=xxxxxxxxxxxxxxxx
   Dout[1010]=xxxxxxxxxxxxxxxx
   Dout[1011]=xxxxxxxxxxxxxxxx
   Dout[1100]=xxxxxxxxxxxxxxxx
   Dout[1101]=xxxxxxxxxxxxxxxx
   Dout[1110]=xxxxxxxxxxxxxxxx
   Dout[1111]=xxxxxxxxxxxxxxxx
   ==== Write Sequence ====
   Din [0000]=0000000000000000
   Din [0001]=0001000100010001
   Din [0010]=0010001000100010
   Din [0011]=0011001100110011
   Din [0100]=0100010001000100
   Din [0101]=0101010101010101
   Din [0110]=0110011001100110
   Din [0111]=0111011101110111
   Din [1000]=1000100010001000
   Din [1001]=1001100110011001
   Din [1010]=1010101010101010
   Din [1011]=1011101110111011
   Din [1100]=1100110011001100
   Din [1101]=1101110111011101
   Din [1110]=1110111011101110
   Din [1111]=1111111111111111
   ==== PostRead Sequence ====
   Dout[0000]=0000000000000000 : PASS
   Dout[0001]=0001000100010001 : PASS
   Dout[0010]=0010001000100010 : PASS
   Dout[0011]=0011001100110011 : PASS
   Dout[0100]=0100010001000100 : PASS
   Dout[0101]=0101010101010101 : PASS
   Dout[0110]=0110011001100110 : PASS
   Dout[0111]=0111011101110111 : PASS
   Dout[1000]=1000100010001000 : PASS
   Dout[1001]=1001100110011001 : PASS
   Dout[1010]=1010101010101010 : PASS
   Dout[1011]=1011101110111011 : PASS
   Dout[1100]=1100110011001100 : PASS
   Dout[1101]=1101110111011101 : PASS
   Dout[1110]=1110111011101110 : PASS
   Dout[1111]=1111111111111111 : PASS
  └───────────────────────────────────┘
 
  ・今回のテストベンチでは定型的な動作の記述に event を使用しています。event
   は event型変数として定義されます。
     event イベント変数名;
   イベントの呼び出しは
     -> イベント変数名;
   です。このイベント変数がアサートされたときに、どのような動きをさせるかに
   ついてはalways文で記述します。
     always @(イベント変数名) begin
       動作記述
     end
  
  ・eventの場合は、呼び出した側で実行が即次行へ移ります。なので、eventで規定
   した動作を行わせてから、次の動作を行いたい場合は、待ち時間を記述する必要
   があります。
  
  ・例えば今回の例「preread_seq」では3サイクルを想定しているので、呼び出し側
   も3サイクルを待たせます。
  
     ─┬─ re = 1'b0;      | <呼び出し側>
     Cycle            | -> preread_seq;
     ─┼─ re = 1'b1;      | #(CYC*3); // 3サイクル待たせる
     Cycle            |
     ─┼─ raddr = raddr + 1'b1; |
     Cycle            |
     ─┴─            |

  ・定型的動作の記述については、その他に task文 もありますが、これについては
   次回説明したいと思います。


(*1)ちなみに、このタイプのモデルを考えるときは、Behavior(動作)モデルがRTLで記
  述できるだけではNGです。必ずネットリストのイメージが作れるように書きましょ
  う。テストのときに必要となるからです。

(*2)特定EDAベンダのツールでは適用できますが、特殊性を含んだものは、横展開時に
  必ず困ることになるので、汎用の観点からモデル適用可否の判断をしましょう。


[Revision Table]
 |Revision |Date    |Comments
 |----------|-----------|-----------------------------------------------------
 |1.00   |2005-11-20 |初版
 |1.01   |2005-11-24 |モデル注意事項追記
[end]

Copyright(C) 2015 Altmo