テストの考え方
- テスト[1]は数値結果の確認とパイプライン制御の確認になります。入力値から出力値が一意に決まるため入力順は関係ないように思えますが、パイプライン制御を考えるとステージ間は異なる動作にした方がラッチタイミングの誤りを検出できるので得策です。従って、なるべく異なる入力値が連続するようにします(同じ値を連続して入れない)。
- 入力値は予め決まった内部の動作を網羅するような値にします。その後、ランダム入力も試したいところです。今回は、シミュレータ自体に手を入れる必要のない2パス方式を用います。
- 1パス: C言語等を用いてランダムな入力値と期待値をまとめてファイル化
- 2パス: RTLシミュレーション時にファイルを読み込んで、入力値と期待値を生成
- 期待値は手計算よりは、C言語などを用いた機械的な計算の算出が望まれます。ただしこの作業が曲者で、同じ誤った期待値生成ツールになる可能性があります。なお単精度や倍精度では、PC等のCPUの生の結果を期待値にできます[2]。
- 組み込まれていないNaNやInfinityに対するテストも必要です。システム組み込み時、その結果が採用不採用の判断材料になります。
テストモジュールの概要
- 簡単なテストモジュールを示します。入力値と期待値は予め埋め込んでおく方式です。テスト名はtestでクロックとリセットを発生します。これに呼び出されるtopモジュールは、テストすべきモジュールと期待値比較のtsモジュールを呼び出します。
- 入力値は、パイプラインのネゴシエーションの度にインクリメントされる番号に従って値を変えます。tsモジュールにおいて期待値をFIFOで同期合わせし、実際の結果と比較します。その際、無効な入力値(NaNやInfinity、非正規数)にはタグを立てて、期待値比較で識別します。
- OK/NG/Skipとして結果を順次標準出力します。なおサンプルでは、分量的にパターンを省いて掲載しています。
テストモジュールサンプル(RTL)
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2011, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// ***************************** MODULE HEADER *********************************
`timescale 1ps / 1ps
module test;
// ************************ PARAMETER DECLARATIONS *****************************
parameter D = 1;
parameter DCLK = 5000;
parameter DCLK2 = DCLK/2;
// ************************** LOCAL DECLARATIONS *******************************
reg clk;
reg reset_n;
// ****************************** MODULE BODY **********************************
// -----------------------------------------------------------------------------
initial begin clk=0; forever begin #(DCLK2) clk=~clk; end end
// -----------------------------------------------------------------------------
initial begin reset_n=0; #D reset_n=0; #(DCLK*3.5) reset_n=1; end
// -----------------------------------------------------------------------------
top top_0 (
clk, reset_n
);
// ************************** FUNCTIONS and TASKS ******************************
endmodule
// *****************************************************************************
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2011, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// ***************************** MODULE HEADER *********************************
module top (
clk,
reset_n
);
// ***************************** I/O DECLARATIONS ******************************
input clk;
input reset_n;
// ************************** LOCAL DECLARATIONS *******************************
reg iVld;
wire iStall;
wire [15:0] iA;
wire [15:0] iB;
wire oVld;
reg oStall;
wire [15:0] oY;
reg [7:0] oCnt;
reg [1:0] rst;
reg reset;
// ******************************** MODULE BODY ********************************
// -----------------------------------------------------------------------------
// Pipeline drive
always @(posedge clk)
if (reset)
iVld <= #1 1'b0;
else if (!iStall)
iVld <= #1 $random;
always @(posedge clk)
if (reset)
oStall <= #1 1'b0;
else
oStall <= #1 $random;
always @(posedge clk)
if (reset)
oCnt <= #1 8'd0;
else
oCnt <= #1 oCnt + (oVld & !oStall);
// -----------------------------------------------------------------------------
// Clock & Reset
// Generate a synchronized reset
always @(posedge clk or negedge reset_n)
if (!reset_n)
rst <= #1 2'b11;
else
rst <= #1 {rst[0], 1'b0};
always @(posedge clk or negedge reset_n)
if (!reset_n)
reset <= #1 1'b1;
else
reset <= #1 rst[1];
// -----------------------------------------------------------------------------
// FMul
fmul fmul_0 (
.iVld (iVld),
.iStall (iStall),
.iA (iA),
.iB (iB),
.oVld (oVld),
.oStall (oStall),
.oY (oY),
.reset (reset),
.clk (clk)
);
// -----------------------------------------------------------------------------
// Sequencer
ts ts_0 (
.iVld (iVld),
.iStall (iStall),
.iA (iA),
.iB (iB),
.oVld (oVld),
.oStall (oStall),
.oY (oY),
.reset (reset),
.clk (clk)
);
// **************************** FUNCTIONS and TASKS ****************************
endmodule
// *****************************************************************************
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2011, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// ***************************** MODULE HEADER *********************************
module ts (
iVld,
iStall,
iA,
iB,
oVld,
oStall,
oY,
clk,
reset
);
// ***************************** I/O DECLARATIONS ******************************
input iVld;
input iStall;
output [15:0] iA;
output [15:0] iB;
input oVld;
input oStall;
input [15:0] oY;
input clk;
input reset;
// ************************** LOCAL DECLARATIONS *******************************
reg [15:0] iA;
reg [15:0] iB;
reg [15:0] expY;
reg expC;
wire [15:0] resultY;
wire resultC;
reg [9:0] iSc;
reg [9:0] oSc;
reg simEnd;
wire doEnd;
wire errY;
wire iAlloc = iVld & !iStall;
wire oAlloc = oVld & !oStall;
// ******************************** MODULE BODY ********************************
// Timing synchronizer for expectation
fifo #(18, 8) fifo_0 (
.iVld (iAlloc),
.iStall (),
.iData ({simEnd, expC, expY}),
.oVld (),
.oStall (!oAlloc),
.oData ({doEnd, resultC, resultY}),
.reset (reset),
.clk (clk)
);
// Message out
always @(posedge clk)
if (doEnd)
$finish;
else if (oAlloc)
case (errY)
1'b0: if (resultC)
$display("Skip : oY=%4h\texpY=%4h\t@%d", oY, resultY, oSc);
else
$display(" OK : oY=%4h\texpY=%4h\t@%d", oY, resultY, oSc);
1'b1:
$display(" NG : oY=%4h\texpY=%4h\t@%d", oY, resultY, oSc);
endcase
assign errY = !resultC & (resultY != oY);
// Test in counter
always @(posedge clk)
if (reset)
iSc <= #1 10'd0;
else
iSc <= #1 iSc + iAlloc;
// Test out counter
always @(posedge clk)
if (reset)
oSc <= #1 10'd0;
else
oSc <= #1 oSc + oAlloc;
// Test sequence
always @(
iSc
) begin
simEnd = 1'b0;
case (iSc)
0: begin iA = 16'h0000; // 0
iB = 16'h0000; // 0
expY = 16'h0000; // 0
expC = 1'b0;
end
1: begin iA = 16'h3c10; // 1.015625
iB = 16'h3cf0; // 1.234375
expY = 16'h3d04; // 1.253906
expC = 1'b0;
end
2: begin iA = 16'h1c00; // 2^-8
iB = 16'h2000; // 2^-7
expY = 16'h0000; // 0^-15 ->0
expC = 1'b0;
end
3: begin iA = 16'hffff; // -NaN
iB = 16'hffff; // -NaN
expY = 16'h7fff; // +NaN
expC = 1'b1; // Skip!
end
4: begin iA = 16'h2000; // 2^-7
iB = 16'h2000; // 2^-7
expY = 16'h0400; // 2^-14
expC = 1'b0;
end
5: begin iA = 16'h3db0; // 1.421875
iB = 16'h3da0; // 1.406250
expY = 16'h4000; // 1.999896 ->2.0 (carry)
expC = 1'b0;
end
6: begin iA = 16'h1400; // 2^-10
iB = 16'h1400; // 2^-10
expY = 16'h0000; // 2^-20 ->0
expC = 1'b0;
end
7: begin iA = 16'hfbff; // -Max
iB = 16'h7bff; // +Max
expY = 16'hfc00; // -Infinity
expC = 1'b1;
end
8: begin iA = 16'h3c01; // 1+2^-10
iB = 16'h3c01; // 1+2^-10
expY = 16'h3c02; // 1+2^-9
expC = 1'b0;
end
9: simEnd = 1'b1;
endcase
end
// **************************** FUNCTIONS and TASKS ****************************
endmodule
// *****************************************************************************
回路デザイン > 設計例 [浮動小数点] > テスト 次のページ(応用FPUその1) このページのTOP ▲
[2]
ちなみに単精度なら、簡単にfloatからhexへの変換が可能です。例えば、floatからhexへの変換はこんな感じです。
main()
{
float i;
int *o = &i;
printf("Input: ");
scanf("%f", &i);
printf("%8x\n", *o);
}