4.1.2 乗算器

 今度は、乗算器を設計してみましょう。

4.1.2.1 RTLシミュレーション


単に、入力A,BをFFで受けて、掛け算するだけのソースです。

論理合成ソース

//`define No_Qout
module mul (clock,reset,A,B,c256);
        parameter width=6;
        input clock;
        input reset;
        input [width-1:0] A,B;
        output [width*2-1:0] c256;
`ifndef No_Qout
        reg [width*2-1:0] c256;
`endif
        reg [width-1:0] a,b;
        
        always @(posedge clock) begin
                if (reset) begin
                        a<=0;
                        b<=0;
                end else begin
                        a<=A;
                        b<=B;
                end     
        end


`ifdef No_Qout
        assign c256=a*b;
`else
        always @ (posedge clock) begin
                        c256<=a*b;
        end
`endif
endmodule



テストベンチソース

ランダムな6ビット幅A,Bを発生させて入力としています。
後で、論理合成したH/WとRTLの結果を比較するためにコンペアする記述も加えています。

`timescale 1ns/1ps
//`define ENABLE_VCD
//`define No_Qout
`define CYCLE (8.648/2)
module mul_vcd_test;
        reg clock=0;
        reg reset=1;
        parameter width=6;
        reg [width-1:0] A,B,a,b;
        wire [width*2-1:0] C;
        reg [width*2-1:0] c,c_rtl;
        integer i,j;
        initial begin
                reset=1;
                A=0;
                B=0;
                #105 ;
                @(posedge clock);
                #1;//ensure hold time
                reset=0;
                for (j=0; j<256;j=j+1) begin
                        for (i=0; i<256;i=i+1) begin
                                @(posedge clock);
                                #1;//ensure hold time
                                A=$random;
                                B=$random;
                        end
                end
                
        

        end
        initial begin

                        #50000 ;
                        $dumpflush;
                        $finish;
        end
        always @(C) c=C;
  

        always @(posedge clock)begin
                if (reset) begin 
                        a<=0;
                        b<=0;
                end else begin
                        a <=A;
                        b <=B;
                end
        end



`ifndef  No_Qout
        always @(posedge clock)begin
                if (c_rtl !==C && !reset) $display("Compare Error c_rtl=%h C=%h time=%d",c_rtl,C,$time); 
                 c_rtl <=a*b;
        end
`else
        always @(posedge clock)begin
               c_rtl =a*b;
                if (c_rtl !==C && !reset) $display("Compare Error c_rtl=%h C=%h time=%d",c_rtl,C,$time); 
        end

`endif

        always #(`CYCLE) clock=~clock;
        
         mul  #(width) u1(.clock(clock),.reset(reset),.A(A),.B(B),.c256(C));

initial begin
        #0;//Do $sdf_annotate first.
`ifdef ENABLE_VCD
        $dumpfile("counter.vcd");
        $dumpvars(1,mul_vcd_test);
`endif
end
endmodule


RTLシミュレーション結果です。結果を得るまでに二つのFFを通過するので2CLOCK遅れで結果が出力されています。



Quartusによる論理合成

mul.vを論理合成して、下図の遅延情報を得ました。

この回路のボトルネックは、内部FF間の遅延で、Clock Setupの115.63Mzが最大駆動可能周波数とQuartusは解析し報告しています。また、出力遅延7.536nsは、CLock Setup(8.648ns)よりも小さいので、テストベンチ上もClockSetupで駆動できる(コンペアエラーは発生しない)筈です。Clock Cycleを下記のように変更してコンペアエラーがで発生しないことを確認してみましょう。
 `define CYCLE (8.648/2)

ところで、出力最大遅延7.536nsが発生している箇所は、比較的簡単に見つけることができました。(下図参照)
Clock Edgeから最後の変化がQuartasの報告通り、C[5]であること確認できました。

コンペアエラーが発生しないことが確認できました。
ところで、ゲートシミュレーション上、個々の時刻ではどれだけの余裕で動いているものでしょうか?
この様子を見るために、SDOファイルのSETUPをエディタで変更してみると様子がわかります。
エディタで
(37:37:37)=>(100:100:100)

一括置換して、再度走らせてみます。
SPEC.を100psに変更したので、SETUPエラーが発生しています。Veritakでは、SETUPエラーが発生してもxにせず、シミュレーション結果になんの影響も与えない仕様になっています。

最初の行では、時刻 664293psに、Setup Spec.100psMin.のところ、44psしかないと報告しています。それでも、37psよりは大きいので、DefaultのSpec.ではエラーにならなかった訳です。

F:\altera\mul\mul_test.v(5)::mul_vcd_test
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------

SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 664293ps <- 44ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 664293ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 1658813ps <- 82ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 4521301ps <- 44ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 4521301ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 5809853ps <- 44ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 5809853ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 6640061ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 6968685ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 10929469ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 13688181ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 15435077ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 16611205ps <- 82ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 16611205ps <- 82ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 17432765ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 19369917ps <- 82ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 22344829ps <- 88ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 26158597ps <- 88ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 27092581ps <- 82ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 27092581ps <- 82ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 29142157ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 30197213ps <- 44ps: mul_vcd_test.u1.c256[11]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[11]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 30197213ps <- 44ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 30197213ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 30465301ps <- 88ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 33924501ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 35524381ps <- 57ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 36233517ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 36371885ps <- 44ps: mul_vcd_test.u1.c256[11]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[11]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 36371885ps <- 44ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 36371885ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 37323165ps <- 57ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 39640829ps <- 88ps: mul_vcd_test.u1.c256[10]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[10]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 39640829ps <- 88ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 41724997ps <- 95ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 42010381ps <- 95ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 42287117ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 44155085ps <- 44ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
SDF: timing check[0] SETUP[Spec.100ps] FAILS at simtime 46368973ps <- 95ps: mul_vcd_test.u1.c256[9]~reg0_I.lereg.datain ==> posedge mul_vcd_test.u1.c256[9]~reg0_I.lereg.clk
Info: $finishコマンドを実行します。time=50000

---------- シミュレーションを終了します。time=50000----------


以下様々なTiming Errorが発生していますが、信号自体は、c256[10],C256[9]が多いです。。恐らくこのパスがクリティカルパスなのでしょう。確かにQuartusのClockSetupのレポートをみると、8.648nsのクリティカルパスに含まれています。

しかしながら、Veritakのシミュレーションでは、最小値で44psになっており、本当の最小値の37psは発生していません。パターン数が少ないという指摘は当たっていますが、仮に全パターン遷移を行ったとしてもこのような結果は普通に起こりえます。深い論理においてQuartasの静的なTiming解析と動的なパス遅延(慣性遅延も含む)とで、最大値が一致するということはむしろまれです。ただし、動的なパス遅延が静的遅延を超えることはありません。従い、Quartasの報告する駆動周波数で、ゲートシミュレーションが動かないということは(設計上のエラーがない限り)ありません。Setup、Holdエラーの発生の原因の多くは、テストベンチとのIFにあります。
このエラーが発生したときは、まず、テストベンチのIFを疑いましょう。

**シミュレーション開始時の最初のクロックエッジでの報告は、シミュレータの過渡状態によるものですので、無視して構いません。