赞
踩
使用情况:
1. 使用灵活性–看索引
索引是连续的非负整数,采用定宽或动态数组
索引不规则,且稀疏分布,采用关联数组
2. 排序方式
如果元素一次性全部加入,选择定宽或者动态数组,只需要对数组进行一次分配
如果元素一个一个加入,选择队列
如果数组的值不连续且互异,可以使用关联数组,把元素值本身作为索引
3. 占用系统的存储空间
小于1000个元素的数组,各种类型对存储器用量影响不大
1000 ~ 100万个元素的数组,定宽和动态数组具有最高的存储器使用效率
大于100万个元素的数组,重新检查算法是否有问题
对兆字节量级的存储器建模应该使用关联数组,但是注意指针带来的额外消耗,关联数组中每个元素站的空间可能会比定宽和动态数组大好几倍
多线程之间同步主要由mailbox、event、 semaphore三种进行一个通信交互。
@(event handle):边沿触发,事件会一直等待,直到触发为止,阻塞型;
wait(event_handle,triggered):电平触发,如果事件在当前已经被触发,则不会引起阻塞,非阻塞型,当event被多次触发时,避免使用wait;
FIFO在硬件上是一种地址依次自增的Simple Dual Por RAM,按读数据和写数据工作的时钟域是否相同分为同步FIFO和异步FIFO
同步FIFO:是指读时钟和写时钟为同步时钟,常用于数据缓存和数据位宽转换;
异步FIFO:通常情况下是指读时钟和写时钟频率有差异,即由两个异步时钟驱动的FIFO,由于读写操作是独立的,故常用于多比特数据跨时钟域处理;
封装、继承和多态
封装:通过将一些数据和使用这些数据的方法封装在一个集合里,成为一个类。
继承:允许通过现有类去得到一个新的类,且其可以共享现有类的属性和方法。现有类叫做基类,新类叫做派生类或扩展类。
多态:得到扩展类后,有时我们会使用基类句柄去调用扩展类对象,这时候调用的方法如何准确去判断是想要调用的方法呢?通过对类中方法进行virtual声明,这样当调用基类句柄指向扩展类时,方法会根据对象去识别,调用扩展类的方法,而不是基类中的。而基类和扩展类中方法有着同样的名字,但能够准确调用,叫做多态。
ref参数类型是引用
向子程序传递数组时应尽量使用reí获取最佳性能,如果不希望子程序改变数组的值,可以使用const ref类型;
在任务里可以修改变量而且修改结果对调用它的函数随时可见。
最常用的是assert(acc.randomize() with {arr.seze()==3;});
约束常见的几种方式
权重约束dist::=n表示每一个取值的权重都是n,:/=n表示每一个取值的权重都是n/num;
条件约束if-else或->:->表示前面的条件满足情况下,才会触发后面的条件;
范围约束inside:约束在一个范围;
代码覆盖率:是针对RTL设计代码的运行完备度的体现,包括行覆盖率、条件覆盖率、FSM覆盖率、跳转覆盖率、分支覆盖率,只要仿真就可以收集,可以看DUT的哪部分代码没有动,如果有一部分代码一直没动看一下是不是case没有写到。
功能覆盖率:与spec比较来发现,design是否行为正确,需要按testplan来比较进度,用来衡量哪些设计特征已经被测试程序测试过的一个指标,首要的选择是使用更多的种子来运行现有的测试程序;其次是建立新的约束,只有在确实需要的时候才会求助于定向测试,改进功能覆盖率最简单的方法是仅仅增加仿真时间或者尝试新的随机种子。验证的目的就是确保设计在实际环境中的行为正确。设计规范里详细说明了设备应该如何运行,而验证计划里则列出了相应的功能应该如何激励、验证和测量;
断言覆盖率:用于检査几个信号之间的关系,常用在査找错误,主要是检査时序上的错误,测是断言被触发的频繁程度;
立即断言的话就是和时序无关,比如我们在对激励随机化时,我们会使用立即断言,如果随机化出错我们就会触发断言报错。
并发断言的话主要是用来检测时序关系的,由于在很多模块或者总线中,单纯使用覆盖率或者事务check 并不能完全检测多个时序信号之间的关系,但是并发断言却可以使用简洁的语言去监测。除此之外,还可以进行覆盖率检测。
井发断言的用法的话,主要是有三个层次:
立即断言(immediate assertion)
并行断言( concurrent assertion)
return之后,function里剩下的语句不能执行,return是终止函数的执行,并返回函数的值
Factory机制也叫工厂机制,其存在的意义就是为了能够方便的替换TB中的实例或者已注册的类型。一般而言,在搭建完TB后,我们如果需要对TB进行更改配置或者相关的类信息,我们可以通过使用factory机制进行覆盖,达到替换的效果,从而大大提高TB的可重用性和灵活性。
要使用factory机制先要进行:
UVM的启动
依次执行uvm_test容器中的各个component组件中的phase机制,按照顺序:
传递virtual interface到环境中:uvm_config_db
为什么要用virtual?
首先看下面两段代码
(1) interface intfa; |第一段代码中,只要module里面定义了intfa0,那么编译的时候就知道这是一个硬件结构, logic a; |是一种数据结构,需要分配内存空间来对应。可以抽象理解interface定义出来的是一种 ... |“静态存在”的数据结构。 endinterface | module a(); | intfa intfa0; | endmodule | (2) |第二段代码中,如果我们也使用intfa intfa1,那么就意味着class a中有一个静态存在的接口, class a; |需要分配内存来对应,但是问题来了,class a本身还不存在,因为只有a这个类只有被实例化出 intfa intfa1; |来,才会被分配内存空间,通常是在别的地方被new这种方法(或者create方法)实例化出来。 endclass | function xxx | a a1; | a1 = new(); | endfunction |
第二段代码中,只有在代码执行到new()这一行的时候,a1这个对象才存在,才会被分配内存空间,请注意:此时一定是处于运行态,因为代码已经执行起来了,那么这就有了一个矛盾:在运行态才存在的a1里面有一个在静态就存在的interface,这个明显逻辑就不通。
所以给class里面的interface加上virtual,含义就是:这个interface静态不存在!
只有当class的对象被创建出来以后,这个interface才存在。此时在运行态再把这个动态的产生的interface和module里面定义的静态interface连接起来。这逻辑上就通了,编译器和仿真器也知道该怎么干活了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。