SV入门基础

1.数据类型

1.1variable型和net型

variable型:reg,integer,time
net型:wire,wor,wand.
在Verilog中,variable和net都是四值逻辑:0,1,X,Z

1.2 type和data type

type表明该数据是variable还是net型
data type表明数据是4值逻辑和2值逻辑
variable型数据可以是4值逻辑也可以是2值逻辑,net型只能是4值逻辑

四值逻辑:inter、reg、logic,ner-type(wire、tri)
二值逻辑:byte、shortint、int、longint、bit
如果按照有符号好无符号的类型进行划分,那么可以将常见的变量类型划分为:
有符号类型:byte、shortint、longint、integer
无符号类型:bit、logic、reg、net-type

1.3内建数据类型

bit -12值的整数
byte-82值整数,类似C语言中char
shortint-162值整数,类似C语言中short
int-322值整数,类似C语言中的int
longint-642值整数,类似C语言中的long long
bit resetN; //a 1-bit wide 2-state variable
bit [63:0] data;//a 64-bit 2-state variable
bit [0:7] array [0:255];//an array of 8-bit 2-state variables

System Verilog中,使用关键字logic来代替reg,logic单独使用时,表示4值类型数据:

logic resetN;//a 1-bit wide 4-state variable
logic [63:0] data;//a 64-bit wide variable
logic [0:7] array[0:255];//an array of 8-bit variable

logic类型和bit类型在进行运算时,如果位宽不一致会发生什么?

logic[3:0] x_vector =4'b111x;
bit [2:0] bit_vector;
initial begin
  $display("@ 1 x_vector = 'b%b",x_vector);
  bit_vector = x_vector;
  $display("@ 2 bit_vector = 'b%b",bit_vector);
  仿真结果如下:
  @1 x_vector ='b111x
  @2 bit_vector ='b110

2.数据

2.1合并数据

有时需要把数据当作一个整体来访问,同时又可以把它分解成更小的单元,此时就要引入合并数据,如一个32bit的寄存器,有时看成4个8bit的数据,有时看成一个无符号数据。

bit [3:0][7:0] bytes;  //4个字节组装成32bit
bit [3:0][7:0] bytes_arr[0:3];//4个32bit混合数组
bytes=32'haabb_ccdd;
$display("%h",bytes);//所有32bit,即32'haabb_ccdd;
$display("%h",bytes[3]);//最高byte,即8'haa
$display("%h",bytes[3][7]);//最高bit位,即8'haa=8'b1010_1010

2.2非合并数组

不需要把数据当作一个整体来访问,bit[7:0] b_unpack[3];//3个字节

2.3动态数组

在程序执行之前不知道数组宽度,可以用[]留空来定义动态数组。此时数组最开始是空的,但在调用之前,必须用new[]来指定宽度。

int dyn[],d2[];//声明动态数组
Initial begin
    dyn =new[5]; //分配5个元素
    foreach(dyn[j])dyn[j]=j;//对元素进行初始化
    d2=dyn;               //复制一个动态数组
    d2[0]=5;              //更改元素的值
    dyn=new[20](dyn);//分配20个整数值并进行复制,把新的数组的开始5个数用旧的元素复制
    dyn=new[100];//分配100个新的元素旧值不复存在
    dyn.delete()
 end

2.4队列

SV引入一个新的数据类型,它结合了链表和数组的优点,可以在队列中的任何地方添加或者删除元素;队列的声明使用[ ] ,元素的编号从 0 到 ],元素的编号从0到 ],元素的编号从0

int j=1;
   q2[$]={3,4};
   q[$]={0,2,5};//声明队列,并初始化一些元素
   Initial begin
     q.insert(1,j);//在第二个元素之前插入j
     q.delete(1); //删除第一个元素
     q.push_front(6);//在队列前插入6
     j=q.pop_back;//把最后一个元素pop出来
     q.push_back(8);//在队列尾部插入8
     j=q.pop_front;//pop出第一个元素
     q.delete() //删除整个队列
     end

2.5关联数组

1.声明
通过方括号中防止类型实现 int data_as[bit[31:0]]:int 为存储数据类型,bit[31:0]为寻址的类型
2.初始化
data_as ='{1:20,221,322}3.关联数组的大小
可以使用size()num()来实现,没有写入数据时,大小为0
4.data_as.delete(100)//什么都不做
  data_as.delete(1)//删除1:20
 5.exists函数用来判断对应的索引值是否存在,存在则返回1,不存在则返回0

3.数据结构

3.1结构体

SV中可以使用struct语句创建结构,跟C语言类似

struct {bit [7:0] r,g,b;}pixel;//创建一个pixel
//为了共享该类型,通过typedef来创建新类型
typedef struct {bit [7:0] r,g,b;} pixel_s;
//为了便于硬件使用,还有压缩格式:
typedef struct packed{bit [7:0] r,g,b;} pixel_s;

3.2枚举类型

枚举类型enum经常和typedef搭配使用,由此便于用户自定义枚举类型的共享使用。枚举类型可以保证一些非期望值不会出现,降低了设计风险。
typedef enum{ INIT,DECODE,IDLE} fsmstate_e;
fsmstate_e pstate,nstate//声明自定义类型变量

3.3字符串

string s;
initial begin
  s="IEEE ";
  $display(s.getc(0));//显示“I”的ASCII码,73
  $display(%s”,s.getc(0));//显示“I”
  $display(s.tolower());//显示“ieee”
  s.putc(s.len()-1,"_") //将空格变为“—”
  s={s,"P1800"};//"IEEE-P1800"
  $display(s.substr(2,5));//显示EE-P
  my_log($sformatf("%s,%5d",s,42));//创建一个字符串,并打印
end
task my_log(string message);
  $display("@%0t:%s",$time,message);
endtask

4.过程语句和子语句

4.1always和initial

module/endmodule,interface/endinterface可以被视为硬件世界
program/endprogram,class/endclass可以被视为软件世界

always是为了描述硬件的行为,在使用时需要注意:那种使用方式是时序电路描述,那种使用方式是组合电路描述;
always中的@(event)敏感列表是为了模拟硬件信号的触发行为,需要正确对标硬件行为和always过程块描述。需要理解硬件行为的核心要素有哪些;
always过程块是用来描述硬件时序电路和组合电路的正确打开方式,因此只可以在module或者interface中使用

4.2函数

可以在参数列表中指定输入参数(input)、输出参数(output)、输入输出参数(inout)或者引用参数(ref)。
可以返回数值或者不返回数值(void)
fucntion int double(input int a);
  return 2*a;
endfuction
initial begin
  $display("double of %d is %0d",10,double(10));
 end

4.3 任务task

任务相比于函数要更加灵活,且有以下共同点:

task无法通过return返回结果,因此只能通过output、inout或者ref的参数来返回。
task内可以置入耗时语句,而function则不能。常见的耗时语句包括@event、wait event、#delay等
task mytask1(out logic[31:0] x,input logic y)
...
endtask
task many(input int a=1,b=2,c=3,d=4);
   $display("%0d %0d %0d %0d",a,b,c,d);
 endtask
 initial begin
  many(6,7,8,9);
  many();
  many(.c(5));
  many(,6,.d(8));
 end

5.接口interface

5.1声明

逻辑设计日益复杂,模块之间的通信必须分割成独立的实体。SV使用接口来连接不同的模块。接口可以看作一捆智能连线。它包括了连接、同步;它连接了DUT和验证平台。

//接口声明
interface arb_if(input bit clk);
        logic[1:0] grant,request;
        logic grant_valid;
        logic rst;
//使用clocking block来进行信号的同步
//在clocking block,所有信号的采样和驱动,都是跟时钟同步的。
interface arb_if(input bit_clk);
   logic[1:0] grant,request;
   logic reset;
   clocking cb@(posedge clk);//声明一个时钟模块cb
     output request;
     input grant;
    endclocking
    modport TEST(clocking cb,output reset);//调用cb
    modport DUT(input request,reset,out grant);
 endinterface

在clocking block中,采样和驱动信号遵循如下原则:
同步后的采样(input)信号,都是前一个状态的值。
同步后的驱动(output)信号,都是当前状态的值。#0

//接口中的双向信号
interface master_if(input bit clk);
	wire[7:0] data;
	clocking cb@(posedge clk);
		inout data;
    endclocking
    modport TEST(clocking cb);
  endinterface
  program test(master_if mif);
  	initial begin
  	mif.cb.data <=‘z; //高阻态
  	@mif.cb;
  	$display(mif.cb.data);//从总线读取
  	@mif.cb;
  	mif.cb.data <= 7'h5a;//驱动总线
  	@mif.cb;
  	mif.cb.data <='z;//释放总线
  	end
  	endprogram
  	//如何驱动异步双向信号
  	//1.连续赋值语句;
  	//2.虚接口
1.always块在program中不支持

5.2使用接口简化连接

//采用接口连接:
module top;
  bit clk;
  always #5 clk=~clk;
  arb if arbif(clk);//例化接口
  arb a1(arbif);   //连接DUT
  test t1(arbif);  //连接tb
 endmodule:top
 //采用端口连接
 module top;
   logic[1:0] grant,request;
   bit clk,rst;
   always #5 clk=~clk;
   arb_port a1(grant,grant_valid,request,rst,clk);
   test t1(grant,grant_valid,request,rst,clk);
 endmodule

clocking block的input偏差就是默认的1step,output偏差就是0.

6.面向对象编程

6.1 OOP术语

Class类:包含变量和子程序的基本构建块;在Verilog中module也可以包含变量和方法,只不过它是硬件盒子,而class是软件盒子;
Object对象:类的一个实例;Verilog中module也可以例化,这是硬件例化,在SV中使用class来例化,这是软件例化;
Handle句柄:指向对象的指针;在Verilog中,可以通过层次化的索引来找到结构中的设计实例,而在SV的对象索引时,需要通过句柄索引对象的变量和方法;
Property属性:存储数据的变量;在Verilog中,它可以是wire或者reg类型;
Method方法:类中可以使用task或者function来定义方法以便处理自身或者外部处理的数据。在Verilog可以在module中定义task/funciton,也可以使用initial/always处理数据。
三大特性:
(1)封装:封装就是把抽象的数据和对数据进行的操作封装在一起
(2)继承:一个类型获取另外一个类型的属性的方式。分为实现继承和接口继承
(3)多态:同一个行为具有不同的表现形式或形态能力,同一个消息可以根据发送对象的不同而采用多种不同的行为方式。
激励生成器(stimulus generator):生成激励内容
驱动器(driver):将激励以时序形式发送至DUT
检测器(monitor):检测信号并记录数据
比较器(checker):比较数据
验证环境的不同组件其功能和所需要处理的数据内容是不同得的
不同环境的同一类型的组件其所具备的功能和数据内容是相似的
基于以上两点,验证世界的各个组件角色明确、功能分立,使用面向对象编程与验证世界的构建原则十分符合。

6.2 类Class

类是将相同的个体抽象出来的描述方式,对象时实体

//Class
//Property
Class Transaction;
  logic [31:]addr;
  logic kind;
  logic [63:0] data;
  //Constructor
  function new(logic [31:0] addr);
    this.addr =addr;
    this.kind ='x;
    this.data='x;
  endfunction
  //Method
  fucntion void display();
    $display("addr=%h,kind=%h,data=%h",addr,kind,data)
  endfunction
  //Handle
  Transaction tr_gen;
  Transaction tr_drv;
  //Object
  initial begin
    tr_gen =new(32'h7788);
    tr_drv= new(32'h8877);
    
    //ObjectName.property
    tr_gen.kind =1'h1;
    tr_drv.data ='h0;

    //ObjectName.Method
    tr_gen.display();
    tr_drv.display();
   end

System Verilog类的成员中有public,local,protected,默认的类型是public,当类的类型是local时,不能从外面直接访问,可以通过function间接访问。
(1)如果没有指明访问类型,那么成员的默认类型是public,子类和外部成可以访问成员
(2)如果指明了访问类型是proected,那么只有该类或者子类可以访问成员,而外部无法访问。
(3)如果指明了访问类型是local,那么只要该类可以访问成员,子类和外部均无法访问。

6.2 对象的复制

(1)常用的浅复制的方法有:
tr2 =new tr1;
浅复制复制对象的所有属性;
浅复制不会调用new函数;
(2)深复制
tr1 = new();
tr2=tr.copy;
深复制就是创建一个新的和原始句柄指向的内容相同的字段,是两个一样大的数据段,所以两者的句柄指向的空间是不同的,但内容是相通的,之后新对象中句柄指向的内容发生改变不会引起原始指向发生变化

6.3 类的继承

(1)类的继承包括了继承父类的成员变量和成员方法。也就是说一个子类在继承父类成员变量的同时也继承了父类操作这些成员变量的成员方法。
(2)子类在定义new函数时,需要先调用父类的new函数super.new()。如果父类的new函数没有参数,子类也可以省略该调用,而系统会在编译时自动添加super.new()。
(3)从对象创建时初始化的顺序来看,用户应该注意有如下的规则:
子类的实例对象在初始化首先会调用父类的构造函数
当父类构造函数完成时,会将子类实例对象中各个成员变量按照它们定义时的默认初始化,如果没有默认值则不被初始化。
在成员白能量默认值初始化后,才会最后进入用户定义的new函数中执行剩余的初始化代码
当一个类派生出子类的时候,基类中的一些方法可能需要被重写;用对象中的类型来决定调用哪一个实现方法,这是一个动态的过程。
动态的选择方法的实现方式叫多态。
没有继承就没有多态。

class cat;
  protected color_t color;
  local bit is_good;
  function set_good(bit s);
    this.is_good =s;
  endfunction
 endclass
class black_cat extends cat;
 function new();
   this.color =BLACK;
 endfunction
 endclass
 class white_cat extends cat;
 function new();
   this.color=WHITE;
  endfunction
 endclass
black_cat bk;
white_cat wt;
inital begin
  bk=new();
  wt=new();
  bk.set_good(1);
  wt.set_good(1);
end

6.4 虚方法

(1)类中的方法在定义的时候通过添加virtual关键字来声明一个虚方法,虚方法是一个基本的多态结构
(2)虚方法为具体的实现提供一个原型,也就是在派生类中,重写该方法的时候必须采用一致的参数和返回值。
(3)虚方法可以重写其所有基类中的方法,然而普通的方法被重写后只能在本身及其派生类中有效
(4)每个类的继承关系只有一个虚方法实现,而且是在最后一个派生类别中。

//虚方法的例子
class packet;
   int a=1;
   int b=2;
   fucntion void display_a;
     $display("packet::a is %d",a);
   endfucntion
   virtual function void display_b;
     $display("packet ::b is %d",b);
  endfucntion
  endclass
  class my_packet extends packet;
     int a=3;
     int b=4;
     function void display_a;
       $display("my_packet::a is %d",a);
     endfunction
  virtual function void display_b;
    $display("my_packet::b is %d",b);
   endfunction
 endclass
 //虚方法
 module top;
   packet p1;
   my_packet p2;
   initial begin
     p1=new();
     p2=new();
     p1=p2;
      p1.display_a;
      p1.display_b;
   end
endmodule

为什么引入虚接口?
interface封装了module的端口(ports)、方向(modports)、同步关系(clocking block)、以及function和task。
interfac简化了模块之间的连接,但是无法很好地适用于OOP的测试平台,无法program,class中进行实例化
无法解决这个问题,System Verilog引入virtual interface的概念
使用virtual interface是为了消除绝对路径,尽可能减少验证代码的大面积修改。
virtual interface本质是指针,是指向interface的指针,即virual interface是可以在class中实例化的数据类型,使用virtual interface可与检测设计DUT进行间接地通信,而无需使用层次结构引用。

6.4 虚接口(virtual interface)

//实例化的接口必须正确连接到DUT
interface counter_if(input logic clk);
   logic load_valid;
    logic[3:0] load_value;
 endinterface
module tb_top;
logic rstn,clk;
logic [3:0] out;
counter_if dutif(clk);
counter u_counter(.resetn(rstn),
                 .clk(clk),
                 .load_valid(dutif.load_valid),
                 .load_value(dutif.load_value),
                 .q(out);
)
endmodule
//必须在类中声明virtual interface句柄,并且有相应驱动。
class driver:
  virtual counter_if vif;
  transaction tr;
  function new(input virtual counter_if vif);
    this.vif=vif;
   endfunction
   task run(int n=10);
     for(int i=0;i<n;i++)begin
        tr=new();
        assert(tr.randominze())
        $display("tr.load_valid=%d,tr.load_value=%d",tr.load.valid,tr.load_value);
        @(posedge vif.clk)begin
          vif.load_vlid<=tr.load_valid;
          vif.load_value<=tr.load_value;
          end
          end
          endtask
          class transaction;
           rand logic load_valid;
           rand logic[3:0]load_value;
         endclass   
    //3、必须将virtual interface指向实例化的interface
    counter_if dutif(clk);
    driver my_driver;//create my_driver
    initial begin
       my_driver = new(dutif);
     end     

6.4 this指针

1.通过this可以绑定方法和 对象
2.通过this可以区分方法体的形参和对象的成员
3.thsi指针可以作为实参传递,但是不能作为形参使用
4.this指针在调用方法时开始存在,当方法调用结束时其声明周期也就结束了,这与一般函数的声明周期相同
5.this指针不能用于static方法中

7.随机化

7.1 带有随机变量的简单类

什么需要随机化:
器件配置:通过寄存器和信号系统
环境配置:随机化验证环境,例如合理的时钟和外部反馈信号
原始输入数据:例如数据包的长度、带宽,数据间的顺序
延时:握手信号之间的时序关系,例如valid和ready,req和ack之间的时序关系
协议异常:如果反馈给出异常,那么设计是否可以保持后续数据处理的稳定性

//带有随机变量的简单类
class Packet;
  //The random variable
   rand bit[31:0] src,dst,data[8];
   randc bit[7:0] kind;
   //Limit the values for src
   constraint c
   {
       src>10;
       src<15;
  }
  endclass
  program testgen;
   Packet p;
 initial begin
    p=new();
    assert(p.randomize)
    else $fatal(0,"Packet::randomize failed");
    end
    endprogram 

7.2权重分配 Weighted Distributions

   rand int src,dst;
   constraint c_dist
   {
      src dist{0:=40,[1:30]:=60};
      //1-3都占60,0占40
      dst dist{0:/40,[1:3]:/30};
      //这个是真正的百分比
   }
  

7.3条件表达式

class Stim; 
   bit flag;
   rand bit[31:0]dst;
   constraint c_stim
   {
       if(flag)
       {
          ds inside{[40:80]};
       }
       else
       dst inside {[2:10],[50:67]};
   }
 endclass
 //另外一种表达方式
 class Stim;
    bit flag;
    rand bit[31:0]dst;
    constraint c_stim
    {
       flag->dst inside{[40:80]};
       !flag->dst inside{[2:10],[50:67]};
    }
  endclass

7.4 控制约束模块

//控制多个约束模块 
class Packet;
   rand int length;
   constraint c_short{length inside {[1:32]};}
   constraint c_long {length inside {[1000:1023]};}
endclass
Packet p;
initial begin
  p=new();
  p.c_short.constraint_mode(0);//disabling short constraint
  asset(p.randomize());
  
  p.constraint_mode(0);//disabling all constraint
  p.c_short.constraint_mode(1);
  assert(p.randomize());
  transmit(p);
  end

7.5控制随机变量

class Packet;
  rand bit[7:0]length,payload[];
  constraint c_valid{length>0;payload.size()==length}
  endclass
  Packet p;
  inital begin
    p=new();
    p.lenth.rand_mode(0);//Make length nonrandom
    p.length=42;//set it to a constrain value
    assert(p.randomize()); //then randomize the payload
    p.length.rand_mode(1);//make length random
   end

pre_randomize与post_randomize函数都是function,不消耗仿真时间。
pre_randomize在执行randomize()之前调用,主要用来设定与randomize相关的各个变量的值。post_randomize:在randomize()之后调用。主要用来调用相关的函数对randomize出来的变量进行后续处理

//控制随机变量
class Transaction;
	rand bit[31:0] addr,data;
	constraint c1 {addr inside{[0:100],[1000:2000]};}
endclass

Transaction t;
initial begin
	assert(t.randomize() with{addr >= 50;addr<=1500;data<10});
	$display("t::addr =%d,data=%d",t.addr,t.data);
    assert(t.randomize() with{addr ==2000;data>10});
    $display("t::addr =%d,data=%d",t.addr,t.data);
end

7.6数组约束

class good_sum;
  rand int len[];
  constraint c_len
  {
     foreach(len[i])len[i]inside{[1:255]};
     len.sum<1024;
     len.size()inside{[1:8]};
  }
  function void display();
   $write("sum=%4d",len.sum());
   foreach(len[i]$write("%4d,len[i]"));
   endfucntion

7.7随机化约束的概率

//随机化约束的概率
//1.
class unconstrained;
	rand bit x;
	r and bit[1:0] y;
endclass
//2.y的值依赖于x的值,x,y同时解析
class impact1;
	rand bit x;
	rand bit[1:0];
    
    constraint c_xy{
	(x==0)->y==0
}
endclass
//3.y的值依赖于x的值,先解析randc对应的x
class impact1;
	randc bit x;
	rand bit[1:0];
    
    constraint c_xy{
	(x==0)->y==0
}
endclass
//4.y的值依赖于x的值 
class impact1;
	randc bit x;
	randc bit[1:0];
    
    constraint c_xy{
	(x==0)->y==0
}
endclass

solve …before

//先解析x
class solvebefore
	rand bit x;
	rand bit[1:0] y;
	constraint c_xy{
	(x==0) -> y==0;
	solve x before y;


}

endclass

7.8动态数组

//用来统计动态数组或者队列的元素个数
class dyn_size;
	rand logic[31:0] d[];
	constraint d_size {d.size() inside {[1:10]};}
endclass
//用来计算动态数组或者队列的所有元素的和	
class dyn_sum;
	rand logic[7:0] d[];
	constraint d_sum {d.sum() == 9'd100;}
endclass

7.9 断言作用

(1)使用断言可以缩短研制周期
(2)使用断言可以设计中存在的各种问题更容易比动态检测观察
(3)使用断言内嵌的覆盖率统计功能可以更加容易获得对于功能的覆盖性
(4)断言的可读性较一般描述语言更容易理解
(5)通过全局控制实现设计中断言的开关
(6)断言可以加速形式验证,提供形式验证的效率
断言的种类:
立即断言:Immediate Assertions
并发断言 Concurrent Assertions

//1.立即断言
assert(expression) $display("expression evaluates to true");
else $fatal("expression evaluates to false");
//2.并发断言
//并发断言检查跨越多个时钟周期的事件序列
//我们可以认为并发断言是一个连续运行的模块,为整个仿真过程检查信号,所以需要在并发断言内指定一个采样时钟。区别并发断言和立即断言的关键字是property
//通用格式
//断言名:assert property(判断条件)
always @(posedge clk)begin
	check_a_and_b:assert(a&b) $display("a&&b is true");
	else $error("a&&b is false");
	end
check_a_and_b:assert property(@(posedge clk)(a&b)) $display("a&&b is true");	
else $error("a&&b is false");
//sequence,带参数的sequencer
sequence seq1(signal1,signal2);
	@(posedge clk) signal1&&signal2;
endsequence
//在断言的property中调用sequence
check_a_and_b:assert property(seq1(a,b);

8.覆盖率

8.1代码覆盖率

代码覆盖率100%是验证工作完成的必要条件
1.line coverage //所有行是否运行到
2.paths coverage //所有路径是否cover到
3.toggle coverage //所有变量都过0,1翻转
4.FSM coverage //状态机所有状态都已运行到

8.2 覆盖率的类型

1.功能覆盖率
2.断言覆盖率

8.3 SV的覆盖组概述

//在类里面定义covegroup
class Transaction;
  logic [31:0]data;
  logic [2:0]port;
 endclass
 class Transactor;
   Transaction tr;
   mailbox mbx_in;
   virtual busifc ifc;
 covergroup CovPort;
   coverpoint tr.port;
 endgroup;
 function new(mailbox mbx_in,virtual busifc ifc);
   CovPbrt=new();
   this.mbx_inmbx_in;
   this.ifc=ifc;
 endfucntion
 task main;
   begin 
   mbx_in.get(tr);
   ifc.port<=tr.port;
   ifc.data<=tr.data;
   covPort.sample();
  end
  endtask
  endclass
  //精细化的交叉覆盖率
  class Transaction
    rand bit a,b;
  endclass
  covergroup CrossBinsofintersect;
    a:coverpoint tr.a
     {type_option.weight=0;}
    b:coverpoint tr.b
    {type_option.weight=0;}
    ab:cross a,b
    {bins a0b0 =binsof(a)interest{0}binsof(b)interest{0};
          a1b0 =binsof(a)interest{1}binsof(b)interest{0}
          bins b1=binsof(b)interest{1}}
    endgroup

8.SV时序

8.1竞争

在组合逻辑电路中,某个输入变量通过两条或者两条以上的突进传到输出到,由于延迟时间不同,到达输出门的时间有先有后,这种现象称为竞争,

8.2冒险

如果一个组合逻辑电路中有“毛刺”出现,就说明该电路存在冒险。

由于延迟时间的存在,当一个输入信号经过多条路径传送后又重新会和到某个门上,由于不同路径上门的数目不同,或者门电路延迟时间的差异,导致到达汇合点的时间有先有后,从而产生瞬间错误输出。
冒险现象

8.3解决方法

1.利用D触发器来打拍,保证输入和输出信号来同步。
2.为了避免RTL仿真行为中发生信号竞争问题,我们建议通过非阻塞赋值或者特定的信号延迟来解决问题。

8.4层次化队列

(1)progam
SV中,为了区分验证和RTL事件,testbench代码都包含在program模块中,program通module的形式很类似,只是不包含任何层次结构,program中不能包含module。

9.SV接口的驱动和采样

9.1接口同步

verilog利用@和wait来同步测试平台中的信号。

9.2接口信号采样

当在DUT arb中驱动arbif.grant:test对clocking cb中的输入信号grant进行采样。采样输出为arbif.cb.grant

9.3接口信号驱动

10. sv的类和对象

10.1 类的定义

(1)类是成员变量和成员方法的载体,一个类的功能应该尽可能的简单,不应当承担过多的职责。这在设计模式中共称之为单一职责原则(SPR)
(2)类作为载体,也具备了天生的闭合属性,即将其属性和方法封装在内部,不会直接将成员变量暴露给外部,通过protected和local关键词来设置成变量和方法的外部访问权限。

class clock
local bit is_summer =0;
local int nclock=6;
fucntion int get_clock();
if(!is_summer)return
   this.nclock;
else
	return this.nclock+1;
endfunction
function bit set_summer(bit s);
   this.is_summer =s;
 endfucntion
 clock ck;
 initial begin
 ck=new();
   ck=new();
   $display("now time is %0d",ck.get_clock());
    ck.set_summer(1);
    $display("now time is %0d",ck.nclock);
 end
 这个例程会报错:IIlegal access to local member nclock
 如果成员变量是local或者protected,注意外部不能直接访问类内的成员。

(3).如果没有指明访问类型,那么成员的默认的类型是public,子类和外部均可以访问成员
.如果指明了访问类型是protected,那么只有该类或者子类可以访问成员,而外部无法访问。
.如果指明了访问类型是local,那么只有该类可以访问成员,子类和外部均无法访问。

10.2 对象

(1)sv的例化,创建对象时,注意什么是声明,什么是创建。

Transaction tr;//声明句柄,此时被初始化为null
tr=new();//创建对象;
new函数将初始化的默认值改成想要的值。
new没有返回值。

(3)对象的复制
浅复制: 常用的浅复制方法:
tr2=new tr1;
浅复制复制对象所有的属性,但不包括属性成员中句柄指向的对象!
浅复制不会调用new函数;
deep copy
深复制就是创建一个新的和原始句柄指向的内容相同的字段,是两个一样大的数据段,所以两者的句柄的指向的空间是不同的,但是内容是相通的,之后的新对象中句柄指向的内容发生改变,不会引起原始对象的句柄内容发生改变。
tr2 = tr1.copy();
(4)类的继承

class cat;
  protected color,t_color;
  local bit is_good;
  function set_good(bit s);
    this.is_good=s;
    endfunction
    endclass
class black_cat extends cat;
  function new();
    this.color =BLACK;
   endfunction
   endclass
class white_cat extends cat;
   function new();
     this.color=WHITE;
     endfunction
     endclass
     black_cat bk;
class white_cat extends cat;
    function new()
      this.color =WHITE;
      endfunction
      endclass
   black_cat bk;
   white_cat wt;
   initial begin
     bk=new();
     wt=new();
     bk.set_good(1);
     wt.set_good(1);
    end
     

1)类的继承包括了继承父类的成员变量和成员的方法。
2)子类在定义new函数时,需要先调用父类的new函数即super.new()。如果父类的new函数没有参数,子类也可以省略该调用,而系统会在编译时自动添加super.new().

10. sv的包

10.1 包的定义

package regs_pkg和arb_pkg的定义。

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SV Virtual是一种虚拟现实技术,它是一种用于创建虚拟现实环境的软件平台。该技术利用计算机生成的图像和声音来模拟真实世界或想象中的环境。SV Virtual可以用于多种领域,如游戏、娱乐、培训和仿真等。通过使用头戴式显示器和手柄等设备,用户可以沉浸在虚拟环境中,与虚拟对象进行交互和体验。 使用SV Virtual的过程一般包括以下几个步骤: 1. 硬件准备:首先,您需要一台具备一定配置要求的电脑或游戏主机,以及适配器和传感器等设备,如头戴式显示器、手柄或体感设备等。 2. 安装软件:根据您所使用的SV Virtual平台,您需要下载并安装相应的软件。这些软件可以从官方网站或其他可信来源获取。 3. 设置环境:在使用SV Virtual之前,您需要设置一个合适的环境。这包括清理活动空间、设置参考点或传感器位置、调整设备参数等。 4. 创建虚拟环境:使用SV Virtual软件,您可以创建自己想要的虚拟环境。这可以包括模拟现实世界的场景、游戏世界、培训模拟等。 5. 交互和体验:在虚拟环境中,您可以使用头戴式显示器上的显示和音频功能来看到和听到虚拟场景中的内容。您可以使用手柄或体感设备来与虚拟对象进行交互,如移动、抓取、控制等。 总的来说,SV Virtual是一种用于创建虚拟现实环境的软件平台,可以通过头戴式显示器和手柄等设备让用户沉浸在虚拟世界中。使用SV Virtual需要进行硬件准备、软件安装、环境设置和创建虚拟环境等步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值