//设计的过程实际是从一种形式到另一种形式的转换,比如从设计规格到RTL代码,从RTL
//到门级网表,从门级网表到
版图等。说的其实是设计的流程的转变,很有道理
//验证的目的就是保证每一步的设计转换过程中都准确无误。
//功能验证指的是从验证RTL代码是否符合原始的设计需求和规格。
//仿真:使用EDA工具通过对设计实际工作情况的模拟验证设计的正确性。
//testbench的使用首先知道它是什么个玩意?testbench是测试平台的意思,就是在仿真的时候testbench产生测试激励给待验证设计(DUT)
// 并检查DUT的输出是否与预期的一致,达到验证的目的
//编写仿真激励:
//1.使用initial和always语句 2.时钟复位的写法
//普通时钟信号
parameter period = 10;
reg clk;
initial
begin
clk = 0;
forever
#(period/2)clk = ~clk;
end
//或者
parameter period = 10;
reg clk;
initial
clk = 0;
always
#(period/2)clk = ~clk;
// 固定数目的时钟信号
parameter pulse = 4,period = 10;
reg clk;
initial
begin
clk=0;
repeat(pulse)
#(period/2)clk = ~clk;
end
//相移时钟信号
parameter HI_TIME = 5,
LO_TIME = 10,
PHASE_SHIFT = 2;
reg Absolute_clk;
wire Derived_clk;
always
begin
#HI_TIME Absolute_clk = 0;
#LO_TIME Absolute_clk = 1;
end
assign #PHASE_SHIFT Derived_clk = Absolute_clk; //相移为2
//异步复位信号
parameter period = 10;
reg rst_n;
initial
begin
rst_n = 1;
#period rst_n = 0;
#(5*period) rst_n = 1;
end
//同步复位信号和异步的有很大不同,见代码
initial
rst_n = 1;
@(negedge clk)
rst_n = 0;
# 30;
@(negedge clk)
rst_n = 1;
end
//产生值序列----------------------------------后续介绍
//利用系统函数和系统任务产生测试激励、显示调试信息、协助定位
//对于$readmemb系统任务,每个数字必须是二进制数字,对于$readmemh系统任务
//从文件里读出和写入数据
reg [7:0]datasource[0:47];
$readmemh("Read_In_File.txt",datasource); //从已有的文件读入数据
//1.打开文件
integer file_id;
file_id = fopen("file_path/file_name");
//2.写入文件
//$fmonitor只要有变化就一直记录
$fmonitor(file_id, "%format_char", parameter);
eg:$fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);
//$fwrite需要触发条件才记录
$fwrite(file_id, "%format_char", parameter);
//$fdisplay需要触发条件才记录
$fdisplay(file_id, "%format_char", parameter);
$fstrobe();
//3.读取文件
integer file_id;
file_id = $fread("file_path/file_name", "r");
//4.关闭文件
$fclose(fjile_id);
//5.由文件设定存储器初值
//初始化数据为十六进制
$readmemh("file_name", memory_name");
//初始化数据为二进制
$readmemb("file_name", memory_name");
integer write_out_file; //定义一个整数的文件指针
write_out_file = $fopen("write_out_file.txt"); //打开文件
$fdisplay(write_out_file,"@%h\n%h",Mpi_add,data_in); //往文件中写入内容
$fclose(write_out_file);
//写并行激励 在仿真的时候的同一时刻启动多个任务,可以使用 fork join
//for语句实现遍历测试
//高级语句:force release,用的不多
/*
task 任务名称;
输入、输出声明;
语句;
endtask
//与task不同,function将会返回一个值
function [BITWIDHT-1:0]函数名称;
输出声明;
语句;
endfunction
*/
function [7:0]product;
input[3:0]sig_a;
input[3:0]sig_b;
begin
product = sig_a*sig_b;
end
endfunction
//搭建仿真环境
//确认仿真结果
//双向总线必须在顶层模块定义并且例化为三态信号,在顶层将双线总线分为输入和输出信号,然后根据需求传向不同的子模块
inout [7:0] data_bus;
wire [7:0] data_in;//双线信号的分裂
wire [7:0] data_out;
assign data_in = data_bus;
assign data_bus = ((!CS_)&&(!OE_))?data_out:8'bZZZZZZZZ; //三态总线的使能
// 在testbench测试平台上
reg [7:0] data_out;
reg [7:0] data_in;
tri [7:0] data_bus;
assign data_bus = ( oe )? data_out : 8'bz ;
// 结构化testbench思想:把不同操作的功能模块以task或者function的封装成一体作为总线功能模型(BFM)
// 而将要操作的数据作为参数去直接调用这种模型。
// 好处:BFM可重用;
// 结构清晰,易于设计,减小testbench设计工作量;
// 将testcase的抽象成都提高,无须关心底层细节;
// 适用于复杂的设计模块
// 总线功能模型(BFM)是一种将物理的接口时序操作转化为更高抽象层次接口的总线模型
// 测试套具就是harness 从系统测试角度说就是将被测模块固定(实例化)以便测试。
// 从验证
verilog代码说就是将测试模块封装起来留出易用的的访问接口,以利于各种testcase调用、测试设计模块
// 单顶层的testbench只有一个顶层,harness的实例以及各种测试用例都在顶层中。
// 多顶层的testbench中通常有一个harness顶层,用来实例化设计模块,实例化BFM,以及提供一些基本的激励。而多个测试用例testcase都可以作为
// 顶层,不同的测试用例用来测试不同的特性或者边界条件,注意顶层之间没有端口映射,它们之间的访问是通过层次路径名方式访问。
// 设计一个testbench的基本思想和步骤:从需求(SPEC)规格到特性:从设计的规格提取设计的特性;
// 从特性到用例:根据设计特性,编写出相应的测试用例来检验该特性;
// 从用例到testbench:用例测试用例,就可以搭建测试平台
//从标志寄存器的低有效位开始查找第一个值为1 的位
reg[15:0]flag;
integer i;
initial
begin
flag = 16'b0010_0000_0000_0000;
i = 0;
begin:block1
while(i<16)
begin
if(flag[i])
begin
$dispaly("number %d",i);
disable block1;
end
i = i+1;
end
end
end