IC 設計 驗證 -學習筆記

IC 設計 驗證
編寫 TESTBENCH 的目的是爲了對使用硬件描述語言設計的電路進行仿真驗證,測試
設計電路的功能、性能與設計的預期是否相符。通常,編寫測試文件的過程如下:
• 產生模擬激勵(波形);
• 將產生的激勵加入到被測試模塊中並觀察其響應;
• 將輸出響應與期望值相比較。
完整的test bench 文件結構

時鐘激勵
/----------------------------------------------------------------
時鐘激勵產生方法一:50%佔空比時鐘
----------------------------------------------------------------
/
parameter ClockPeriod=10;
initial
begin
clk_i=0;
forever
#(ClockPeriod/2) clk_i=~clk_i;
End

/----------------------------------------------------------------
時鐘激勵產生方法二:50%佔空比時鐘
----------------------------------------------------------------
/
initial
begin
clk_i=0;
always #(ClockPeriod/2) clk_i=~clk_i;
End

/----------------------------------------------------------------
時鐘激勵產生方法四:產生固定數量的時鐘脈衝
----------------------------------------------------------------
/
initial
begin
clk_i=0;
repeat(6)
#(ClockPeriod/2) clk_i=~clk_i;
End

/----------------------------------------------------------------
時鐘激勵產生方法五:產生非佔空比爲 50%的時鐘
----------------------------------------------------------------
/
initial
begin
clk_i=0;
forever
begin
#((ClockPeriod/2)-2) clk_i=0;
#((ClockPeriod/2)+2) clk_i=1;
end
End

復位信號設計:
/----------------------------------------------------------------
復位信號產生方法一:異步復位
----------------------------------------------------------------
/
initial
begin
rst_n_i=1;
#100;
rst_n_i=0;
#100;
rst_n_i=1;
end
/----------------------------------------------------------------
復位信號產生方法二:同步復位
----------------------------------------------------------------
/
initial
begin
rst_n_i=1;
@(negedge clk_i)
rst_n_i=0;
#100; //固定時間復位
repeat(10) @(negedge clk_i); //固定週期數復位
@(negedge clk_i)
rst_n_i=1;
end
/----------------------------------------------------------------
復位信號產生方法三:復位任務封裝
----------------------------------------------------------------
/
task reset;
input [31:0] reset_time; //復位時間可調,輸入復位時間
RST_ING=0; //復位方式可調,低電平或高電平
begin
rst_n=RST_ING; //復位中
#reset_time; //復位時間
rst_n_i=~RST_ING; //撤銷復位,復位結束
end
Endtask

特殊信號設計
/----------------------------------------------------------------
特殊激勵信號產生描述一:輸入信號任務封裝
----------------------------------------------------------------
/
task i_data;
input [7:0] dut_data;
begin
@(posedge data_en); send_data=0;
@(posedge data_en); send_data=dut_data[0];
@(posedge data_en); send_data=dut_data[1];
@(posedge data_en); send_data=dut_data[2];
@(posedge data_en); send_data=dut_data[3];
@(posedge data_en); send_data=dut_data[4];
@(posedge data_en); send_data=dut_data[5];
@(posedge data_en); send_data=dut_data[6];
@(posedge data_en); send_data=dut_data[7];
@(posedge data_en); send_data=1;
#100;
end
endtask
//調用方法:i_data(8’hXX);
/----------------------------------------------------------------
特殊激勵信號產生描述二:多輸入信號任務封裝
----------------------------------------------------------------
/
task more_input;
input [7:0] a;
input [7:0] b;
input [31:0] times;
output [8:0] c;
begin
repeat(times) //等待 times 個時鐘上升沿
@(posedge clk_i)
c=a+b; //時鐘上升沿 a,b 相加
end
endtask
//調用方法:more_input(x,y,t,z); //按聲明順序
/----------------------------------------------------------------
雙向信號描述一:inout 在 testbench 中定義爲 wire 型變量
----------------------------------------------------------------
/
//爲雙向端口設置中間變量 inout_reg 作爲 inout 的輸出寄存,其中 inout 變
//量定義爲 wire 型,使用輸出使能控制傳輸方向
//inout bir_port;
wire bir_port;
reg bir_port_reg;
reg bi_port_oe;
assign bi_port=bi_port_oe ? bir_port_reg : 1’bz;
/----------------------------------------------------------------
雙向信號描述二:強制 force
----------------------------------------------------------------
/
//當雙向端口作爲輸出口時,不需要對其進行初始化,而只需開通三態門
//當雙向端口作爲輸入時,只需要對其初始化並關閉三態門,初始化賦值需
//使用 wire 型數據,通過 force 命令來對雙向端口進行輸入賦值
//assign dinout=(!en) din :16’hz; 完成雙向賦值
initial
begin
force dinout=20;
#200
force dinout=dinout-1;
end
/----------------------------------------------------------------
特殊激勵信號產生描述三:輸入信號產生,一次 SRAM 寫信號產生
----------------------------------------------------------------
/
initial
begin
cs_n=1; //片選無效
wr_n=1; //寫使能無效
rd_n=1; //讀使能無效
addr=8’hxx; //地址無效
data=8’hzz; //數據無效
#100;
cs_n=0; //片選有效
wr_n=0; //寫使能有效
addr=8’hF1; //寫入地址
data=8’h2C; //寫入數據
#100;
cs_n=1;
wr_n=1;
#10;
addr=8’hxx;
data=8’hzz;
end
/----------------------------------------------------------------
Testbench 中@與 wait
----------------------------------------------------------------
/
//@使用沿觸發
//wait 語句都是使用電平觸發
initial
begin
start=1’b1;
wait(en=1’b1);
#10;
start=1’b0;
End

仿真控制語句以及系統任務描述
/----------------------------------------------------------------
仿真控制語句及系統任務描述
----------------------------------------------------------------
/
$stop //停止運行仿真,modelsim 中可繼續仿真
$stop(n) //帶參數系統任務,根據參數 0,1 或 2 不同,輸出仿真信息
$finish //結束運行仿真,不可繼續仿真
$finish(n) //帶參數系統任務,根據參數 0,1 或 2 不同,輸出仿真信息
//0:不輸出任何信息
//1:輸出當前仿真時刻和位置
//2:輸出當前仿真時刻、位置和仿真過程中用到的 memory 以及 CPU 時間的
統計
$random //產生隨機數
KaTeX parse error: Expected '}', got 'EOF' at end of input: …-n 到 n 之間的隨機數 {random} % n //產生範圍 0 到 n 之間的隨機數
/----------------------------------------------------------------
仿真終端顯示描述
----------------------------------------------------------------
/
$monitor //仿真打印輸出,大印出仿真過程中的變量,使其終端顯示
/*
monitor(monitor(time,“clk=%d reset=%d out=%d”,clk,reset,out);
/
$display //終端打印字符串,顯示仿真結果等
/

$display(” Simulation start ! “);
display(Attimedisplay(” At time %t,input is %b%b%b,output is %b",time,a,b,en,z);
/
$time //返回 64 位整型時間
$stime //返回 32 位整型時間
realtime///realtime //實行實型模擬時間 /*---------------------------------------------------------------- 文本輸入方式:readmemb/$readmemh
----------------------------------------------------------------
/
//激勵具有複雜的數據結構
//verilog 提供了讀入文本的系統函數
readmemb/readmemb/readmemh(”<數據文件名>",<存儲器名>);
readmemb/readmemb/readmemh("<數據文件名>",<存儲器名>,<起始地址>);
readmemb/readmemb/readmemh("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
$readmemb:/讀取二進制數據,讀取文件內容只能包含:空白位置,註釋行,二進制數
數據中不能包含位寬說明和格式說明,每個數字必須是二進制數字。
/
$readmemh:/讀取十六進制數據,讀取文件內容只能包含:空白位置,註釋行,十六進
制數
數據中不能包含位寬說明和格式說明,每個數字必須是十六進制數字。
/
/當地址出現在數據文件中,格式爲@hh…h,地址與數字之間不允許空白位
置,
可出現多個地址
/
module
reg [7:0] memory[0:3];//聲明 8 個 8 位存儲單元
integer i;
initial
begin
$readmemh(“mem.dat”,memory);//讀取系統文件到存儲器中的給定地址
//顯示此時存儲器內容
for(i=0;i<4;i=i+1)
$display(“Memory[%d]=%h”,i,memory[i]);
end
endmodule
/*mem.dat 文件內容
@001
AB CD
@003
A1
*/
//仿真輸出爲
Memory[0] = xx;
Memory[1] = AB;
Memory[2] = CD;
Memory[3] = A1;

加法器的仿真測試文件的編寫
• 封裝有用且常用的 testbench,testbench 中可以使用 task 或 function 對代碼
進行封裝,下次利用時靈活調用即可;
• 如果待測試文件中存在雙向信號(inout)需要注意,需要一個 reg 變量來表示輸
入,一個 wire 變量表示輸出;
• 單個 initial 語句不要太複雜,可分開寫成多個 initial 語句,便於閱讀和修改;
• Testbench 說到底是依賴 PC 軟件平臺,必須與自身設計的硬件功能想搭配。
module add(a,b,c,d,e);// 模塊接口
input [5:0] a; // 輸入信號 a
input [5:0] b; // 輸入信號 b
input [5:0] c; // 輸入信號 a
input [5:0] d; // 輸入信號 b
output[7:0] e; // 求和輸出信號
wire [6:0]outa1,outa2; // 定義輸出網線型
assign e = outa2+outa1; // 把兩部分輸出結果合併
/*
通常,我們模塊的調用寫法如下:
被調用的模塊名字- 自定義的名字- 括號內信號
這裏比如括號內的信號,.ina(ina1)
這種寫法最常用,信號的順序可以調換
另外還有一種寫法沒可以直接這樣寫
adder u1 (ina1,inb1,outa1);
這種寫法必須確保信號的順序一致,這種寫法幾乎沒有人採用
*/
adder u1 (.ina(a),.inb(b),.outa(outa1)); // 調用 adder 模塊,自定義名字爲 u1
adder u2 (.ina©,.inb(d),.outa(outa2)); // 調用 adder 模塊,自定義名字爲 u2
endmodule
//adder 子模塊
module adder(ina,inb,outa );// 模塊接口
input [5:0] ina; // ina-輸入信號
input [5:0] inb; // inb-輸入信號
output [6:0] outa; // outa-輸入信號
assign outa = ina + inb; // 求和
endmodule // 模塊結束

仿真文件
`timescale 1ns / 1ps
module add_tb();
reg [5:0] a;
reg [5:0] b;
reg [5:0] c;
reg [5:0] d;
wire[7:0] e;
reg [5:0] i; //中間變量
// 調用被仿真模塊模塊
add uut (.a(a), .b(b),.c©,.d(d),.e(e));
initial begin // initial 是仿真用的初始化關鍵詞
a=0;b=0;c=0;d=0; // 必須初始化輸入信號
for(i=1;i<31;i=i+1) begin
#10 ;
a = i;
b = i;
c = i;
d = i;
end // 給是輸入信號 a 賦值
end
initial begin
monitor(monitor(time,"%d + %d + %d + %d ={%d}",a,b,c,d,e); // 信號打印輸出
#500 $finish;
end
endmodule

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章