2011年11月24日木曜日

ISimでシミュレーションする


by yosikawa » 2011年2月12日(土) 18:29
ロータリスイッチを使うの続き。

ロータリスイッチのモジュールS3E_Rotary には当初バグがあった。
問題の個所は、
コード: 
   always @(posedge clk or negedge reset) begin
      if(!reset) begin
         rotary_q1 <= 0;
         rotary_q2 <= 0;
      end else begin
         case ({ rotary_a, rotary_b })
            2'b00 : { rotary_q1, rotary_q2 } <= { 1'b0, rotary_q2 };
            2'b01 : { rotary_q1, rotary_q2 } <= { rotary_q1, 1'b1 };
            2'b10 : { rotary_q1, rotary_q2 } <= { rotary_q1, 1'b0 };
            2'b11 : { rotary_q1, rotary_q2 } <= { 1'b1, rotary_q2 };
            default: { rotary_q1, rotary_q2 } <= { rotary_q1, rotary_q2 };
         endcase
      end
   end
   

ここで、定数の1'b0, 1'b1 を単に 0, 1 などと簡単に書いてたのが間違い。初歩的なミス。

何にせよ、シミュレーションでバグ取りすることが重要。例え正しく動いてそうに見えても、やはり確かめておくことが大切だろう。
開発環境のISEには、ISimというシミュレータが含まれている。
まずはこれで確かめてみる。

先ず、プロジェクトの設定をシミュレーション用のモードに切り替える。
Sourcesペインで、Sources for:のプルダウンをBehavioral Simulation に変える。
そうすると、シミュレーション用のソースコード一覧が表示される。
実は、各ファイルごとに、どのモードで表示されるかが決められている。
確認するには、どれかのファイルを右クリックして、Propertiesを選択する。
View Association がAllのときは、すべてのモードで対象となるが、
ここがSimulationとなっていると、シミュレーション用のモードのときにだけ表示される。

注意が必要なのは、なぜかときどき、意図せずにファイルの設定がSimulationになってしまうことがあること。
このProperties画面で変更できる。

では、topのテストベンチ t_top を作成する。
Project->New source
ファイルの種類はVerilog Test Fixture、ファイル名はt_topとする。
以下を入力する。
コード: 
`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   22:06:08 02/11/2011
// Design Name:   top
// Module Name:   C:/WORK/FPGA/Spartan-3E/T2-LED2/t-top.v
// Project Name:  T2-LED2
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: top
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////
`default_nettype none
module t_top;

   // Inputs
   reg clk;
   reg [3:0] switch;
   reg [3:0] btn;
   reg rotary_a;
   reg rotary_b;
   reg rotary_press;

   // Outputs
   wire [7:0] led;

   // Instantiate the Unit Under Test (UUT)
   top uut (
      .clk(clk), 
      .led(led), 
      .switch(switch), 
      .btn(btn), 
      .rotary_a(rotary_a), 
      .rotary_b(rotary_b), 
      .rotary_press(rotary_press)
   );

   always #5 clk <= ‾clk;
   
   initial begin
      // Initialize Inputs
      clk = 0;
      switch = 0;
      btn = 0;
      rotary_a = 0;
      rotary_b = 0;
      rotary_press = 0;
   
      // Wait 100 ns for global reset to finish
      #100;
      uut.reset_count = 0;
      #50;
        
      // Add stimulus here
      #3;
      rotary_a = 1;
      #20;
      rotary_a = 0;
      #15;
      rotary_a = 1;
      #40;
      rotary_b = 1;
      #20;
      rotary_b = 0;
      #30;
      rotary_b = 1;
      #40;
      rotary_a = 0;
      #20;
      rotary_a = 1;
      #15;
      rotary_a = 0;
      #40;
      rotary_b = 0;
      #20;
      rotary_b = 1;
      #30;
      rotary_b = 0;

      #100;
      rotary_b = 1;
      #20;
      rotary_b = 0;
      #30;
      rotary_b = 1;
      #40;
      rotary_a = 1;
      #20;
      rotary_a = 0;
      #15;
      rotary_a = 1;
      #40;
      rotary_b = 0;
      #20;
      rotary_b = 1;
      #30;
      rotary_b = 0;
      #40;
      rotary_a = 0;
      #20;
      rotary_a = 1;
      #15;
      rotary_a = 0;

      #1000;

   end
      
endmodule

大部分は自動的に作成される。
コード: 
always #5 clk <= ‾clk;

により、10nsのクロックを作っている。100MHzだから、ボードの本当のクロックである50MHzと違うけど、
シミュレーションなのであまり関係ないだろう。

テスト開始後、
コード: 
      #100;
      uut.reset_count = 0;
      #50;

によって全体をリセットしている。
実際のハードは電源投入後に自動的にすべてのフリップフロップがゼロクリアされるが、
シミュレータはこのような仮定をしてくれないので、ここで明示的に全体をリセットする。

あとは、
コード: 
      #3;
      rotary_a = 1;
      #20;
      rotary_a = 0;

みたいな羅列で、テストパターンを作っている。#3などは3ns待つという意味。
ロータリスイッチのA接点とB接点が、互いに少しタイミングをずらしながらON/OFFすることで、
ロータリスイッチの回転をテストする。
チャタリングをシミュレーションするため、
B接点を変更しないで、A接点だけ2回ON/OFFするパターンで試している。

さて、シミュレータを起動する。
Sourcesペインでt_topを選択。(重要!ここで選択したものがシミュレーションの対象になる)
ProcessesペインでSimulate Behavioral Model をダブルクリックする。

シミュレータの使い方
  • F8とF7で横方向のスケールを変更する。
  • 見たい信号を追加するには、Sourcesペインの下のタブでSim Instタブを選択。
    Processesペインの下のタブでSim Objectsを選択。
    Sourcesペインで見たい信号を含むソースファイルを選択する。
    Processesペインに表示された信号の一覧から、見たい信号をシミュレーション画面にドラッグする。

各信号が期待通りの値かを確認する。
初期化してない信号は、不定を表す赤色の表示になり、これでは確認ができない。
従ってテストソースで例えば uut.reset_count = 0; のように強制的に初期化する。

テストソースの中で、周期的に変化する信号を作りたいときは、例えば以下のようにする。
clkを4分周してenableという信号を作る例。
コード: 
   reg enable;
   reg [1:0] i;
   always @(posedge clk) begin
      i <= i + 1'b1;
      enable <= (&i) ? 1 : 0;
   end


これで、無料のツールで開発からシミュレーション、ボードへの書き込みまで一通りできた。

0 件のコメント:

コメントを投稿