目录
3、软约束用chnl_generator想控制chnl_trans生成值
一、lab1

实验流程
1、chnl_initiator是module,module chnl_initiator(input clk,...);
2、在tb中例化连接mcdt dut(.clk_i(clk),...)、chnl_initiator chnl1_init(.clk(clk),...);
3、通过chnl0_arr = new[100],foreach生成数据,write发送数据;
4、判断dut中的ready决定是否发送下一个数据,给tb中的valid高电平,表示准备好了
二、lab2


实验流程
类放在package中
module tb4_ref中 1、连接dut
2、initial clk、rst
3、import chnl_pkg::*; 注意pkg中的intf都是virtual intf;( interface是硬件 语言,无法放在测试平台实例化,virtual interface本质是指向interface的 指针。)
4、例化接口、例化test
5、initial中实例化test,并用test中的方法传入接口,然后run;
1、数组、队列、索引
2、类的三要素
封装:属性、方法封装在内部,而不是暴露在外部,public(内部与外部可访问)、protected(父类、子类)、local(仅父类)。
以下为关联知识点:
- 属性:可用static设置为静态,这种可以在未例化对象前用 class名::var 找到,且无论例化多少次,都是唯一的。
- new()函数:用来开辟空间放入成员变量的初始化值,当无初始化变量时,可以省略function new()函数。
- 类与结构体区别:stuct时就开辟了内存,不用new()函数创建对象。类可以有方法。
- 类与模块区别:module是硬件,默认为静态方法,静态变量,仿真一开始就确定是否例化。类任何时间例化,有封装、继承、多态特性。
继承:通过extends子类继承父类的属性、方法。
以下为关联知识点:
- function new()中先super.new()才可以继承父类new()的属性,
- 父类有llp方法,子类也设置类llp方法,两者仅是同名的方法,无关联。
- 父类有llp方法,子类也设置类llp方法,并在第一行写super.llp()、则继承父类方法,名字可以不同,但是如果父类需要传入参数,则子类方法传入参数需要一致,不然父类所需参数会找不到。
多态:通过虚方法进行动态绑定,达到句柄根据指向对象调用对应方法的效果。
以下为关联知识点:
- 两种情况:父类方法(task或function都可以)virtual A,子类方法virtual A;或 父类方法virtual A,子类方法 A;
- 当父类句柄指向子类对象时,如果父与子有同名函数且加了virtual(或只是父类加viretual),则父类句柄会调用子类中的方法。(更深入来讲是依然调用父类方法,但是父类方法加了virtual,方法被重写了)
- 但是注意:1、方法加virtual,方法名字一样;2、且有一致的参数和返回值。与继承不同的是没有加super.moth() ;益处是父类句柄可调用子类方法的一种设置。
- 动态绑定,根据指向对象调用方法,结合之前实验,父类句柄test[xxx]=t1(子类);后,test[xxx].run()是父类的run(),但父类中的virtual task do_reg()等都被子类更新了,且不是方法继承的方式,没有super.do_reg()
3、接口设置、clocking块
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
clocking drv_ck @(posedge clk);
default input #1ns output #1ns;
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
接口传入:module tb4中例化接口chnl_intf chnl0_if(.*);并通过asic_test.set_interface(chnl0_if, chnl1_if, chnl2_if);传入
接口接收:在package的类中例化local virtual chnl_intf intf;
function void set_interface(virtual chnl_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intantiated");
else
this.intf = intf;
endfunction
接口与dut连接方式:
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
。。。。。。。。。。。。。。。。。。。。
4、package具有隔离作用
类型1:先写好.sv文件,再在module tb中import reg_pkg::*;reg_mon mon1=new()是声明句柄同时建立对象。
package reg_pkg;
`include "regs_stm.sv";
endpackage
module mcdf_tb;
import reg_pkg::*;
reg_mon mon1=new();
endmodule
类型二:直接在package中写入class,然后在module tb4_ref中import chnl_pkg::*;便可以使用package中的class了。
三、lab3
1、随机约束使用
class chnl_trans;
rand bit[31:0] data[];
rand int ch_id;
constraint cstr{
soft data.size inside {[4:8]};
foreach(data[i]) data[i] == 'hC000_0000 + (this.ch_id<<24) + (this.pkt_id<<8) + i;
soft ch_id == 0;
};
endclass
//调用
chnl_trans t;
t=new();
assert(t.randomize with {ch_id == 5;})
2、邮箱使用
- init、gen两个类声明:mailbox #(chnl_trans) req_mb; 注意:名字不一定一样,连接到同一对象即可通信。
- init、gen两个类建立对象:function new()中req_mb=new()
- 进行连接:init.req_mb = gen.req_mb;
class chnl_generator;
mailbox #(chnl_trans) req_mb;
....
function new();
this.req_mb = new();
endfunction
....
task send_trans();
...
this.req_mb.put(req);
...
endtask
endclass
class chnl_initiator;
mailbox #(chnl_trans) req_mb;
...
task drive();
forever begin
...
this.req_mb.get(req);
...
end
endtask
...
endclass: chnl_initiator
///////////在上层进行连接。
class chnl_root_test;
...
this.agents[i].init.req_mb = this.gen[i].req_mb;//指向建立的对象
...
endclass
3、软约束用chnl_generator想控制chnl_trans生成值
chnl_generator中对chnl_trans进行randomize,并通过邮箱给到chnl_initiator,在chnl_write()中写到dut。
进一步思考,通过软约束用chnl_generator想控制chnl_trans生成值,在chnl_basic_test中先对genp[i].randomize且用with进行约束,这样gen就不是默认的软约束值了。
4、关联数组启动仿真
父类句柄数组,然后关联数组如tests["chnl_basic_test"] = basic_test,父类句柄指向子类对象中的父类部分,调用父类的virtual run(),方法是在子类中进行的更新,用到了方法的多态。
5、mcdt_monitor
mcdt_monitor从mcdt(DUT)中获得id和data,通过mailbox给cheaker,然后out_mb.get(on)后,case(om.id)决定和哪个chnl_monitor.get(im)后data比较;
6、gen正常/非正常发送数据
gen正常完成全部发送时,每个gen完成都会run_stop_flag.put(),三个通道全部完成run_stop_callback()启动结束仿真$finish();
gen未正常完成全部发送时,用以下表示全部接受完停止下来
fork
wait(agents[0].vif.ch_margin == 'h20);
wait(agents[1].vif.ch_margin == 'h20);
wait(agents[2].vif.ch_margin == 'h20);
join
$finish();
7、约束constraint
constraint cstr {
da.size() inside{3,4};
da dist{10:=50,[10:20]:=20};
}
8、其他
- 字符串s={s,$sformatf("------",this.af)},
- 仿真结束$finish
- b变化且iff为真@事件,才可以触发 ,always@(b iff en) auto<=a;
四、lab4

以部分知识点的形式列出:
1、实验知识
- fmt_trans中lenght的作用是接收DUT中的length,intf.length和intf.mon_ck.fmt_lenth是一致的;
- 参考模型建立,通过monitor捕捉reg_trans进行设置更新参考模型值,参考模型输出打包后的chnl_trans和fmt_trans进行比较;
- 控制寄存器CMD,CMD_ADDR,CMD_DATA_IN(31:0),CMD_DATA_OUT(31:0)约束是data和addr,cmd的关系,其中write为读是先发送CMD和ADDR,一个周期后在将数据给出reg_write()后 rsp=req.clone();reg与chnl_trans的关系是控制使能通道和优先级,与formatter的关系是控制数据包输出长度;
- this本类中找不到去父类找,do_formatter(),do_data(),do_reg(),是完成数据传输前的设置工作,给上确定的发送数据个数,模式等等。
2、常见验证方法
- 动态仿真
- 静态仿真(STA):语法、语义、跨时钟域CDC(setup、hold)、形式验证
- 效能验证:能耗、门控时钟、区域时钟、多核
3、事件、 旗语
- 事件: event e1,e2; 触发为->e1,等待触发为@e1或wait(e1.triggered)
- 旗语: semaphore sem; 分配1个钥匙sem=new(1),sem.get(1);....... sem.put(1);形成每次都只能一个进行访问
4、结构体、枚举
结构体 struct{bit[7:0],r,g,b} pixel 只是把数据组织到一起,不如用类;
使用方法:typedef stuct{int a;byte b ...} my_struct_s; 先定义;
my_strut_s st='{32'haaaa_aaaa,8'hbb,...}后赋值;
枚举使用
typedef enum {SHORT_FIFO, MED_FIFO, ....} fmt_fifo_t; //定义
fmt_fifo_t fifo; //声明
case(req.fifo) //一种使用方式
SHORT_FIFO: this.fifo_bound = 64;
MED_FIFO: this.fifo_bound = 256;
LONG_FIFO: this.fifo_bound = 512;
ULTRA_FIFO: this.fifo_bound = 2048;
endcase
5、其他
- 过程语句 initial always
- 语句块 begin fork
- 线程 fork...join_any,for...join_none会执行完内部程序,想要在其未执行完前结束线程,指明fork:aa ...... join disable aa;
五、lab5
1、covergroup根据测试功能点设计
设计
covergroup coverport;
coverpoint tr{xxxx};
endgroup
例化 coverport = new();
触发 1、coverport.sample 2、covergroup coverport@(trans_ready)
例子如下:
class mcdf_coverage;
......
covergroup cg_mcdf_reg_write_read;
addr: coverpoint reg_vif.mon_ck.cmd_addr {
type_option.weight = 0;
bins slv0_rw_addr = {`SLV0_RW_ADDR};
bins slv1_rw_addr = {`SLV1_RW_ADDR};
}
cmd: coverpoint reg_vif.mon_ck.cmd {
type_option.weight = 0;
bins write = {`WRITE};
bins read = {`READ};
bins idle = {`IDLE};
}
cmdXaddr: cross cmd, addr {
bins slv0_rw_addr = binsof(addr.slv0_rw_addr);
bins slv1_rw_addr = binsof(addr.slv1_rw_addr);
bins write = binsof(cmd.write);
bins read = binsof(cmd.read );
bins write_slv0_rw_addr = binsof(cmd.write) && binsof(addr.slv0_rw_addr);
bins write_slv1_rw_addr = binsof(cmd.write) && binsof(addr.slv1_rw_addr);
...........
}
endgroup
task run();
this.do_reg_sample();
endtask
task do_reg_sample();
forever begin
@(posedge reg_vif.clk iff reg_vif.rstn);
this.cg_mcdf_reg_write_read.sample();
end
endtask
endclass
2、其他
- $cast(A,B)认为B不变,将B的类型转换成A型后赋值给A
- $cast(Ta,Tb)Ta句柄是Tb对象的子类句柄,成功转化的前提是Tb指向的对象是子类对象(既通过Tb=Ta操作后),是cast的目的是Ta指向Tb指向的对象,此时可以通过操作Ta句柄改变Tb指向对象中的内容。
- mcdf_intf从dut.ctrl_regs_intf拿到slvo_en_o,并放到mcdf_pkg中去,当其为0时(通道关闭),不允许ch_valid===1同时ch_ready也为1;
- $get_coverage()为平均覆盖率,type_option.weight=0为不统计该coverpaint的权重;
1663

被折叠的 条评论
为什么被折叠?



