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。

数组

常数数组

int test[4]='{1,2,3,4};
int test2[5]='{5{4}};
//int test2[5]='{4{4}}; error
test[0:2]='{5,6,7};
test = '{default:5};//所有值赋成5
//foreach(test[i])
for(int i=0;i<$size(test);i++)
    $display("index:%d,num:%d",i,test[i]);
foreach(test2[i])
    $display("index:%d,num:%d",i,test2[i]);

动态数组

int dyn[];
//int dyn[] = '{1,1,2,2,3,3,4,4};定义时候赋初值
dyn = new[5];
dyn = '{5{4}};
//dyn = '{default:5};报错
dyn = new[20](dyn);
foreach(dyn[i])
    $display("index:%d,num:%d",i,dyn[i]);
dyn.delete();//清空所有元素,不能删某一个元素
foreach(dyn[i])
    $display("index:%d,num:%d",i,dyn[i]);

队列

int que[$]= {1,2,3,4,5};
int j;
//int que[$]= {5{1}};报错
foreach(que[i])
    $display("index:%d,num:%d",i,que[i]);
que.insert(1,5);
que.delete(0);
//que.delete();删除整个队列
que.push_front(5);
que.push_back(6);
j = que.pop_front();
j = que.pop_back();
que = {que[0],j,que[1:$]};//$表示最大值下标,实现的功能与insert(1,j)类似
for(int i=0;i<$size(que);i++)
//for(int i=0;i<que.size();i++)
//foreach(que[i])
    $display("index:%d,num:%d",i,que[i]);

关联数组

int rela[int];
int idx;
rela[1] = 15; 
rela[5] = 20; 
rela[20] = 30; 
rela[30] = 40; 
rela.delete(5);
rela.first(idx);
$display("index:%d,num:%d",idx,rela[idx]);
rela.next(idx);//找到下一个元素会返回1,否则返回0
$display("index:%d,num:%d",idx,rela[idx]);
foreach(rela[i])
    $display("index:%d,num:%d",i,rela[i]);
if(!rela.exists(15))
    $display("15 not exists in arr");
if(rela.exists(20))
    $display("20 exists in arr");

数组通用方法

bit [15:0] que[$]= {1,2,3,5,5,4};
bit [15:0]  tq[$];
int  tq_idx[$];//find_index返回的类型只能用int
$display("sum:%d",que.sum);
$display("sum:%d",que.sum with (item==5?item:0));//把item替换成with括号里的值
$display("product:%d",que.product);
$display("and:%d",que.and);
$display("xor:%d",que.xor);
$display("or:%d",que.or);
tq = que.min();
$display("min:%d",tq[0]);
//$display("min:%d",que.min());错误示例,min的返回值是数组,不能直接打印
tq = que.max();
$display("max:%d",tq[0]);
tq = que.unique();//去掉重复元素
foreach(tq[i])
    $display("unique:index %d,value %d",i,tq[i]);
tq = que.find with (item!=5);
tq = que.find_last with (item!=5);
tq = que.find_first with (item!=5);

tq_idx = que.find_index with (item!=5);
tq_idx = que.find_first_index with (item!=5);
tq_idx = que.find_last_index with (item!=5);
foreach(tq[i])
    $display("index %d,value %d",i,tq[i]);
que.reverse();//原来的数组已经改变了
que.sort();
que.rsort();
que.shuffle();

使用enum定义

typedef enum{IDLE,STATE1,STETE2} state_e;
state_e state;
//声明一个生成随机数的类
initial begin
    state = IDLE;
    $display("%s",state.name);
    state = STATE1;
    $display("%s",state.name);
    $finish;
end

使用接口

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)
...

clocking

interface dut_if (input clk);
    logic [15:0] dout;
    logic [15:0] din;
    logic ld, inc, rst_n;

    clocking cb1 @(posedge clk);
        default input #1step output `Tdrive;
        input dout;
        output din;
        output ld, inc, rst_n;
    endclocking
endinterface

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 ...;

控制随机哪些变量

class test_class;
    bit [7:0] a;
    rand bit [7:0] b,c;

test_class t1;
t1=new();
t1.b.rand_mode(0);
assert(t1.randomize());//随机c,不随机b
assert(t1.randomize(c));//只随机c
assert(t1.randomize(a));//只随机a,非随机变量也可以

rand与randc

rand每次随机产生,不能保证两次产生的数不一样。
randc每次产生一个不重复的序列,以8bit为例,周期性随机255个不同的数,即255个值都取到过后,才会重复取值。

系统random函数

$random()//返回32位有符号随机数
$urandom()//返回32位无符号随机数
$urandom_range(a,b)//返回a-b或者b-a范围内的平均分布
$urandom_range(a)//返回0-a范围内的平均分布

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提供的方法

  1. 结构,例如get_full_name(),get_parent(),get_num_childrent()
  2. 阶段(phase)机制,例如build_phase(),connect_phase(),run_phase()
  3. 配置(configuration)机制,例如print_config(),print_override_info()
  4. 报告(report)机制,例如report_hook(),set_report_verbosity_level_hier()
  5. 事务记录(transaction recording),例如record()
  6. 工厂(factory)机制,例如set_inst_override(),set_type_override()

  1. config_db可以先去被创建之前执行,保证创建的时候可以使用这些值。
  2. 所有的test必须继承自uvm_test,否则可能找不到
  3. .clone()返回的是uvm_object,必要时需要cast进行类型转换

使用示例

constraint常见用法

rand bit [7:0] data;  // 随机变量
rand bit [3:0] addr;  // 随机变量
rand bit [7:0] data_array[10]; // 随机数组
constraint c_data_addr {
    data inside {[0:100]};       // data的取值范围是0到100
    addr dist {0:=40, [1:15]:=60}; // addr的分布:0的概率40%,1-15的概率60%
    if (mode == 0)  // 如果mode为0
      data == 0;    // data必须为0
    else            // 否则
      data inside {[1:255]};
    data < 256;
    foreach (data_array[i]) {    // 遍历数组
      data_array[i] inside {[0:100]}; // 每个元素的取值范围是0到100
      if (i > 0) {
        data_array[i] > data_array[i-1]; // 数组元素必须递增
      }
    }
    unique {data_array};
}
约束类型 关键字/语法 用途
范围约束 inside 定义变量的取值范围
条件约束 if-else 或 -> 根据条件定义约束
分布约束 dist 定义变量的概率分布
关系约束 比较运算符(<,>,==) 定义变量之间的关系
数组约束 foreach 对数组元素的约束
软约束 soft 定义优先满足但不强制的约束
唯一值约束 unique 确保数组中的值唯一
动态约束 constraint_mode() 运行时启用/禁用约束

covergroup常见用法

covergroup cg;
coverpoint s0 iff(!reset);//如果保护表达式在采样点计算为false,则忽略覆盖点。
coverpoint s1{
bins a   = { [120:150],[140:190] }; //任何一个都可以满足这个仓
bins a[] = { [120:150],[140:190] }; //120-190共71个仓
bins b[] = { 200,201,202 }; //三个仓
bins c[] = {[0:255]} with (item % 3 == 0);//带判断条件,只含有0,3,6
bins d[] = {[1:8]} iff(c==1);//只有c==1满足才收集bin
bins others[] = default;//没取到的所有仓
wildcard bins g12_15 = { 4'b11?? };//带?,x,z
ignore_bins ignore_vals = {7,8};//忽视
illegal_bins bad_trans = (4=>5=>6);//非法
	bins test1 		= (1=>2=>3);  		//收集变量a 从1变化到2再变化到3的场景
	bins test2 		= (1=>2), (2=>3); 	//收集变量a 从1变化到2或者2变化到3的场景
	bins test3 		= (1,2=>6,7);  		//表示收集1=>6/2=>6/1=>7/2=>7 四种场景之一
	bins test4[] 	= (1,2=>6,7);  		//表示收集1=>6,2=>6,1=>7,2=>7 四种场景
	bins test5      = (1=>[*3]2=>3); 	//收集1=>2=>2=>2=>3
	bins test6      = (1=>[*3:5]2); 	//收集1=>3~5个2
	bins test7      = (1[->3]);			//收集...=>1...=>1...=>1 (...)表示任意数量的除1之外的任何值
	bins test8      = (1[=3]) ;         //收集...=>1...=>1...=>1 (...)表示任意数量的除1之外的任何值, 这个要求最后一个1结束后不会再出现任意1
}
coverpoint data {
    bins low = {[0:127]};
    bins high = {[128:255]};
  }
coverpoint addr {
  bins low_addr = {[0:7]};
  bins high_addr = {[8:15]};
}
// 检查data和addr同时满足条件
data_x_addr: cross data, addr {
  bins low_data_low_addr = binsof(data.low) and binsof(addr.low_addr);
}
endgroup

property常见用法

property  p_shakehand;                 
   @(posedge  clk)  disable iff(a==1)                  	  //当a为1时,关闭属性检查
   request |=> acknowledge ##1 data_enable ##1 done;      //符号“|=>”左侧的为原因序列,右侧为结果序列,两者差一个clk
endproperty
apshakehand:assert property(p_shakehand);else `uvm_error("assert apshakehand","error occur");       
sequence s1;        //sequence主要描述信号与信号之间的时序关系
  	a ##1 b ##1 c;    //a为高,下一拍b为高,在下一拍c为高
endsequence
a ##1 b[*2] ##1 c    //第一拍a为1,最后一拍c为1,a与c之间b为1要出现2次,连续出现。
a ##1 b[*2:5] ##1 c  //a,c之间出现b2-5次,连续出现
a ##1 b[=2] ##1 c    //第一拍a为1,最后一拍c为1,a与c之间b为1要出现2次,非连续出现。
a ##1 b[=2:5] ##1 c  //a,c之间出现b2-5次,非连续出现
a ##1 b[->2] ##1 c    //第一拍a为1,最后一拍c为1,a与c之间b为1要出现2次,区别在于c的前一拍要为b,非连续出现。
a ##1 b[->2:5] ##1 c  //a,c之间出现b2-5次,非连续出现
$rose(signal)
$fell(signal)
$stable(signal)
$past(signal,clk_num,condition)//condition可以不加
$onehot(signal)	//只有1bit为0
$onehot0(signal) //只有1bit为0或者全0
$countones(signal) //bit为1的个数
posted @ 2024-10-08 18:01  心比天高xzh  阅读(175)  评论(0)    收藏  举报