对mcdf这个验证项目,从顶层环境来看一共有:
第一个子模块是channel=node+fifo,按我自己的理解是接收apb总线从端写入过来的数据。
这里的问题是,mcdf的输入端数据的来源是?
要写chnl_pkg,整体的结构是怎么样的?
子模块的顶层环境是agent,agent包含了driver,sequencer,monitor,driver和seqr之间的通信通过两个组件自带的tlm端口实现。通过这个sequencer的item是chnl_trans,在sequence中产生。
其中,chnl_trans需要传递的包,包含的成员变量包括:数据本身,通道的id(有4个node),发包的间隔,数据之间的间隔,包与包之间的间隔,最后是发送完毕的单比特标志位rsp。
正文开始,按照自己的理解敲出来代码,然后再修正。
chnl_pkg
第一版本如下,一个class写完就订正吧。
//要写的是chnl_pkg,所以先写大标题
package chnl_pkg;
//需要用到uvm,两句话少不了
import uvm_pkg::*;
`includ "uvm_macro.svh"
//正片开始,从小写到大,从item开始写
//chnl_trans继承于uvm_sequence_item类
class chnl_trans extends uvm_sequence_item;
//声明随机变量,也就是包的成员变量,按照刚才说的
rand int [31:0] data[];//数据个数不确定,用动态数组,数据是32位的
rand int [ 1:0] chnl_id;//一共4个通道
rand int data_idle;//间隔的位数要用多少?怎么确定?
rand int pkg_idle;//同理
bit rsp;//标志位不用随机变量
//做约束,也就是初始化
constraint trans_cnst {
//data的随机化按chnl_id左移8位+id先
soft data[i]=chnl_id<<8 + chnl_id;
soft chnl_id=2'd0;
soft data_idle inside {0:4};
soft pkg_idle inside {0:10};
}
//然后做注册和域的自动化
`uvm_utils_begin(chnl_trans)
`uvm_field_array_int(data[i], UVM_ALL_ON)
`uvm_field_int(chnl_id, UVM_ALL_ON)
`uvm_field_int(data_idle, UVM_ALL_ON)
`uvm_field_int(pkg_idle, UVM_ALL_ON)
`uvm_utils_end(chnl_trans)
//然后是每个类都需要的new函数,item继承于trans事务类,又继承于object类
function void new (string "name");
super.new("chnl_trans");
endfunction
endclass: chnl_trans
uvm两句话,少了个s
import uvm_pkg::*;
`include "uvm_macros.svh"
声明随机变量时只有data有位宽,其他都不用
成员变量还有包的id
随机变量的约束,动态数组限制size在4-32,用等式==而不是赋值=;数据生成用foreach,规律是'hC0000000+数据左移24位+包id左移8位+i;约束的花括号最后要加分号;
域的自动化,动态数组只写data,rsp也需要写到,
new函数的写法,参数是string name="chnl_trans",super的参数写name即可
第二个版本
package chnl_pkg;
import uvm_pkg::*;
`includ "uvm_macros.svh"
class chnl_trans extends uvm_sequence_item;
rand int [31:0] data[];
rand int chnl_id;
rand int pkg_id;
rand int data_idle;
rand int pkg_idle;
bit rsp;
constraint trans_cnst {
soft data.size() inside {4:32};
foreach(data[i]) data[i]=='hC0000000+(chnl_id<<24)+(pkt_id<<8)+i;
soft chnl_id==0;
soft pkg_id==0;
soft data_idle inside {0:2};
soft pkg_idle inside {1:10};//发包时序,有印象是不能连续发包
};//注意分号
`uvm_object_utils_begin(chnl_trans)
`uvm_field_array_int(data, UVM_ALL_ON)
`uvm_field_int (chnl_id, UVM_ALL_ON)
`uvm_field_int ( pkg_id, UVM_ALL_ON)
`uvm_field_int (data_idle, UVM_ALL_ON)
`uvm_field_int (pkg_idle, UVM_ALL_ON)
`uvm_filed_int (rsp, UVM_ALL_ON)
`uvm_object_utils_end
function void new (string name="chnl_trans");
super.new(name);
endfunction
endclass: chnl_trans
错误如下:
pkt_id的类型是int而不是bit,手误了;
约束中data.size不用加括号;
约束中foreach后data要加soft;
data约束是两个id相加不是加自身data,并且两个id要加上this前缀表示在这个class中的;
约束中两个inside后面要加{},里面才是范围[1:10]
约束的花括号最后要加分号;
注册的宏是`uvm_object_utils_begin(chnl_trans)和`uvm_object_utils_end;
new函数没有void;
总结:这里data其实是payload。一个包可以是数量不同、间隔不同的数据组成的
chnl_driver
接下来是driver ,负责从sequencer中拿到刚才写的item,解析,设置好通道和包的id后返回给sequencer一个rsp并点亮rsp,通信手段是自带的seq_item_port和export端口。
第一个版本
class chnl_driver extends uvm_driver #(chnl_trans);
chnl_trans req,rsp;
`uvm_component_utils(chnl_driver)
function new (string name="chnl_driver",