systemverilog笔记
变量类型
变量名 | 状态数 | 是否带符号 | 比特数 |
---|---|---|---|
logic | 4 | 无 | 1 |
bit | 2 | 无 | 1 |
byte | 2 | 有 | 8 |
shortint | 2 | 有 | 16 |
int | 2 | 有 | 32 |
longint | 2 | 有 | 64 |
integer | 4 | 有 | 32 |
time | 4 | 无 | 64 |
$isunknown(表达式)
:在表达式任意位出现X或者Z时返回1。
数组
数组初始化
使用单引号加大括号
数组遍历
$size(数组)会返回数组长度,可以使用for(int i=0;i<$size(test);i++)
为了简写,可以直接使用foreach,foreach(test[j])
,其中j不需要定义。
对于二维数组,foreach(test[i,j])
同时遍历两个维度,foreach(test[i])
遍历第一个维度,foreach(test[,j])
遍历第二个维度。
合并数组与非合并数组
合并数组声明时,数组大小必须在变量名前声明,且数组大小定义格式为[MSB:LSB],而非[size]。
两者可以混合使用,例如bit[3:0][7:0] test [3];
合并数组连续存储,操作部分字节时非常方便。如果作为@后面的触发信号,则必须用合并数组。
例如上面的test,alway@(test)就会报错,得写成alway@(test[0] or test[1] or test[2])
动态数组
声明时[]中不加入内容,通过new分配空间。
例如int test[];
与test=new[5];
。
可以使用动态数组来声明常数数组,此时不需要冒数组长度数错的风险。
队列
数组与链表的结合,两者都支持。声明时使用$。
操作时可以通过方法或者下标指引的方式。
方法的方式
下标指引的方式
关联数组
有时只使用部分固定下标进行索引,此时使用关联数组可以缩小空间。声明时方括号中放入数据类型。
数组方法
数组可以进行求和等。例如bit test[10]
,可以通过test.sum
进行求和。相似的还有product(积),xor,and,or等。
可以通过test.max()
、test.min()
、test.unique()
求最大值,最小值,筛除重复值。
同时还可以通过find进行搜索。
同时还可以通过sum with结合实现一下功能,例如count = d.sum with(item==4)
,统计数组中4的个数。
d.reverse()反向,d.sort()正排序,d.rsort()逆排序,d.shuffle()随机打乱。
使用接口
interface test(input bit clk);
logic[1:0] a,b;
logic rst;
endinterface
//使用时如下
module test_m(test u_test)
always@(posedge test.clk or negedge test.rst)
...
modport
可以使用modport对信号分组并定义输入输出方向。
interface test(input bit clk);
logic[1:0] a,b;
logic rst;
modport A(input a,output b,input rst);
modport B(output a,input b,input rst);
endinterface
//使用时如下
module test_A(test.A u_test);
module test_B(test.B u_test);
约束
所有约束没有顺序关系,并行执行,约束是可以继承的
dist操作符
constraint con_name{
src dist {0:=40,[1:3]:=60};
//src=0,weight 40/220
//src=1,weight 60/220
//src=2,weight 60/220
//src=3,weight 60/220
src dist {0:/40,[1:3]:/60};
//src=0,weight 40/100
//src=1,weight 20/100
//src=2,weight 20/100
//src=3,weight 20/100
}
inside操作符
constraint con_name{
src inside {[lo,hi]};//src>=lo && src<=hi
src inside {[lo,$]};//src>=lo
src inside {[$,hi]};//src<=hi
}
->操作符
constraint con_name{
(condition) -> 约束;
//等同于 if(condition) 约束;
}
在顶层打开或关闭约束块
class packet;
constraint name1 ...;
constraint name2 ...;
packet p;
在调用时,可以p.name1.constraint_mode(0)
关闭这个约束。
p.constraint_mode(0)
关闭所有约束。
randomize添加外部约束
assert(p.randomize() with {约束1;})
当外部约束与内部约束冲突时,会报错。
可以给内部约束添加soft关键字,降低内部约束优先级。
class packet;
soft constraint name1 ...;
rand与randc
rand每次随机产生,不能保证两次产生的数不一样。
randc每次产生一个不重复的序列,以8bit为例,周期性随机255个不同的数,即255个值都取到过后,才会重复取值。
randcase与randsequence
参考[https://blog.csdn.net/u010491580/article/details/114605586]
for(int i=0;i<15;i++) begin
randsequence(stream)
stream:cfg_read:=1 | io_read:=2 | mem_read:=5;
cfg_read:{cfg_read_task;} | {cfg_read_task;} cfg_read;
io_read:{io_read_task;} | {io_read_task;} io_read;
mem_read:{mem_read_task;} | {mem_read_task;} mem_read;
end
上例中,产生了随机序列stream,它将执行cfg_read、io_read和mem_read三者中的一个,cfg_read的权重是1,io_read的权重是2,mem_read的权重是5。
cfg_read序列的意思是执行一次cfg_read_task或执行多次cfg_read_task,当随机到{cfg_read_task;}时,执行一次cfg_read_task就结束。
当随机到{cfg_read_task;} cfg_read时,执行完一次cfg_read_task后,再跳到cfg_read序列,重新执行cfg_read序列,重新执行前面的过程。
在序列中没有执行权重时,权重默认是1。
randcase
1:task1;//10%
8:task2;//80%
1:task3;//10%
endcase
线程控制
fork...join fork...join_none fork...join_any
等待fork中的线程
task task1:
fork
...
join_none
wait fork//会等到所有线程执行结束再结束task
endtask
停止fork中的线程
task task1:
fork : timecheck
...
join_any
disable timecheck;//会等到任一线程执行结束就结束task
endtask
disable会禁止掉所有同名线程
线程通信
event
event e1;
->e1;//触发事件
@e1;//等到e1发生变化,边沿敏感,多次触发可以识别
wait(e1.triggered);//电平敏感,多次触发时不会识别
semaphore
semaphore sem1;
sem1 = new(n);//定义钥匙数量,不传参就没有钥匙,一般不会这么用
sem1.get(n);//拿出钥匙,一般n为1,省略参数也为1,如果sem1没钥匙,会锁死在这
sem1.put(n);//放回钥匙,一般n为1,省略参数也为1
mailbox
mailbox mbx;
int i,j;
mbx = new(n);//定义信箱数量,不传参相当于无限容量
sem1.get(i);//放入数据i,如果信箱满了,会锁死在这
sem1.put(j);//拿走数据赋值给j,如果信箱空了,会锁死在这
sem1.peek(j);//拿走数据赋值给j,但不会从信箱中删除这个变量,如果信箱空了,会锁死在这
uvm组件
uvm_driver
class uvm_driver #(type REQ=uvm_sequence_item,type RSP=REQ) extends uvm_component;
uvm_seq_item_pull_port #(REQ,RSP) seq_item_port;
uvm_analysis_port #(RSP) rsp_port;
REQ req;
RSP rsp;
endclass //className
driver.seq_item_port.connect(sequencer.seq_item_export);
driver.rsp_port.connect(sequencer.rsp_export);
uvm_component提供的方法
- 结构,例如get_full_name(),get_parent(),get_num_childrent()
- 阶段(phase)机制,例如build_phase(),connect_phase(),run_phase()
- 配置(configuration)机制,例如print_config(),print_override_info()
- 报告(report)机制,例如report_hook(),set_report_verbosity_level_hier()
- 事务记录(transaction recording),例如record()
- 工厂(factory)机制,例如set_inst_override(),set_type_override()
注
- config_db可以先去被创建之前执行,保证创建的时候可以使用这些值。
- 所有的test必须继承自uvm_test,否则可能找不到
- .clone()返回的是uvm_object,必要时需要cast进行类型转换
本文作者:心比天高xzh
本文链接:https://www.cnblogs.com/xzh-personal-issue/p/18452217
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2023-10-08 pytorch训练模版
2023-10-08 python命令行传参
2023-10-08 pytorch 自定义dataset类
2023-10-08 python查看占用系统内存