chiseltest的介绍和实例

Chiseltest的介绍和实例

目录
1 chiseltes介绍 1
1.1支持的模拟器 1
1.1.1 treadle 2
1.1.2 Verilator 3
1.2 withAnnotations API 5
2 chiseltest基本用法 6
2.1 基础的chiselTester实现 6
2.1.1 使用chisel3.iotesters 7
2.1.2 使用Chiseltest 8
2.2 DecoupledDriver库的示例使用 9
2.2.1 QueueTest实例 10
2.3 ChiselTest中的fork和join 13
3 chiseltest 实例 15
3.1波形和printf调试方法 15
3.1.1波形 15
3.1.2 printf调试 15
3.2 chipyard项目下的实例 18
4 参考资料 20
5 chiselverify 20
5.1 chiselverify背景介绍 20

1 chiseltest介绍

chisel中提供了两个测试的方法,分别是chiseltest包中的ChiselTest和iotesters包中的PeekPokeTester。不过iotesters在Chisel 3.5版本开始已经被弃用了。
在这里插入图片描述

ChiselTest是一个针对基于chisel生成的RTL设计的基础验证库,是轻量级的、UT级别、可读性强、可组合重用的测试。
如果你有使用这chiseltest,需要在 你的build.sbt中添加如下依赖库:
libraryDependencies += “edu.berkeley.cs” %% “chiseltest” % “0.5.0”
在这里插入图片描述

1.1支持的模拟器

 完整绑定了两个流行的开源模拟器:
 treadle:默认的模拟器,特点:启动时间快,对于大型电路执行时间慢,仅支持VCD波形文件。
 verilator:需要加with VerilatorBackendAnnotation,启动时间慢,执行快,支持VCD和FST波形文件。
 还提供了一些功能限制的模拟器:
 iverilog: open-source, enable with IcarusBackendAnnotation, supports VCD, FST and LXT。
 vcs: commercial, enable with VcsBackendAnnotation, supports VCD and FSDB

1.1.1 treadle

Treadle是一个FIRRTL表示器,联合Chisel测试器,可以去模拟一个电路,它可以用来debug和测试Chisel电路。通过assertion,我们可以提供测试结果。Treadle也可以生成波形文件(Hello.vcd),可以通过波形观察器(例如,免费的观察器GTKWave或是Modelsim)进行观察。
使用treadle仿真会生成两个文件,一个.fir文件,一个.vcd波形文件
在这里插入图片描述
在这里插入图片描述
执行测试文件时,在终端执行的命令如下:
在这里插入图片描述

1.1.2 Verilator

使用Verilator模拟器,会生成更多的文件,如下图:

1.2 withAnnotations API

此接口类似于便于选项,可以选择不同的仿真工具、生成不同的波形格式文件等功能。
示例:withAnnotations(Seq(VerilatorBackendAnnotation,WriteVcdAnnotation))

Annotations分类 功能描述
VerilatorBackendAnnotation 使用verilator仿真
VcsBackendAnnotation 使用VCS仿真
WriteVcdAnnotation 输出vcd格式的波形文件
WriteFsdbAnnotation 输出FSDB格式的波形文件
PrintPeekPoke 将模拟器交互信息打印到控制台
但是使用VCS时,报错如下:

2 chiseltest基本用法

Chisel团队给测试框架做了很多工作,ChiselTest提供了以下改进:

  1. 既可以进行单元测试也可以进行系统集成测试;
  2. 为可组合的抽象和分层设计;
  3. 高度可用,通过让单元测试更简单、更无痛(避免样板(boilerplate)和其他没意义的事情)和更有用来鼓励单元测试;
    还有以下计划:
     具备面向多种后端和模拟器的能力(如果测试向量不是静态的,或者使用有限的测试构建API子集,则可能需要在综合时链接到Scala);
     将会包含在基础的Chisel3中,以避免封装和依赖带来的麻烦;

2.1 基础的chiselTester实现

ChiselTest和iotesters一样都是从基本操作开始讲起,下面是一个简要的总结,关于旧的iotesters和新的ChiselTest中的基本功能特性的对应关系:
方法 iotesters ChiselTest
poke poke(c.io.in1, 6) c.io.in1.poke(6.U)
peek peek(c.io.out1) c.io.out1.peek()
expect expect(c.io.out1, 6) c.io.out1.expect(6.U)
step step(1) c.io.clock.step(1)
initiate Driver.execute(…) { c => test(…) { c =>

  1. “poke(激励值)”方法给相应的端口添加想要的激励值,激励值是Int类型的;
  2. “peek(当前的值)”方法返回相应的端口的当前值;
  3. “expect(期望值)”方法会对第一个参数(端口)使用peek方法,然后与Int类型的期望值进行对比,如果两者不相等则出错;
  4. “step(n)”方法则让仿真前进n个时钟周期。
    因为测试模块只用于仿真,无需转成Verilog,所以类似for、do…while、to、until、map等Scala高级语法都可以使用,帮助测试代码更加简洁有效。
    poke和expect等方法现在是每个单独的io元素的方法,这样可以给测试人员提供重要的提示,来更好地检查类型。
    还有个区别是poke和expect的值时Chisel字面值。更多高级有趣的例子会展示其更强大的检查功能。未来的改进中通过指定Bundle字面值的能力可以进一步增强这一点(见2.5小节)。

2.1.1 使用chisel3.iotesters

或者:

2.1.2 使用Chiseltest

或者:

2.2 DecoupledDriver库的示例使用

Arbiter和Queue都使用了ready-valid接口,该类型的端口在单一数据信号的基础上又添加了ready和valid信号以使用ready-valid握手协议。
创建ready-valid接口很简单,使用单例对象Decoupled即可创建,有以下两种形式:
 Decoupled(…):可以传入任意的数据类型,然后返回一个ready-valid接口,此时ready是input信号,valid和bits都是output信号。因此它是属于数据生产者producer的端口。
 Flipped(Decoupled(…)):Flipped()会将ready-valid接口的信号方向进行取反,因此此时ready是output信号,valid和bits都是input信号。因此它是属于数据接收者consumer的端口。

ChiselTest提供一些很棒的工具来自动化并可靠地测试这些接口。

2.2.1 QueueTest实例

ChiselTest有一些内置的方法来处理在IO中有解耦合接口的电路。这里展示怎么向queue中插入或从queue中提取数值。
方法 描述
enqueueNow 添加(排队)一个元素到一个Decoupled输入接口
expectDequeueNow 移出(出列)的一个元素来自一个Decoupled输出接口
enqueueSeq 持续从一个Seq中添加元素到Decoupled输入接口,一次一个,直到序列的元素用完了
expectDequeueSeq 从Decoupled输出接口移出元素,一次一个,并且和Seq的下一个元素进行比较。
QueueModule[T <: Data](ioType: T, entries: Int):
一个chisel硬件模块,创建了一个entries个元素的enq的队列;

测试文件:

enqueueSeq必须在expectDequeueSeq 开始之前完成,如果testVector大于队列的深度,那么这个运行就会出问题,因为队列会被填满没法插入新的元素。
测试文件如下:
注意,这里需要一些样板如initSource,setSourceClock等,以此来确保ready和valid字段都在测试开始时正确初始化了。
使用enqueueNow和 expectDequeueNow方法:

使用enqueueSeq 和expectDequeueSeq方法:

如果testVector大于队列的深度,那么这个运行就会出问题,因为队列会被填满没法插入新的元素。

2.3 ChiselTest中的fork和join

这一部分将会介绍怎么同时运行一个单元测试的各个部分,因此首先要介绍两个testers2的新特性:
方法 描述
fork 发射一个并发的代码块,额外的forks(分支)可以通过.fork附加到前一个代码块的结尾来同时执行
join 将多个相关的分支加到一起
下面的例子有两个分支连在一起,然后join到一起。在第一个fork块中enqueueSeq会继续添加元素直到耗尽,第二个fork会在数据可用时,在每个时钟周期expectDequeueSeq。
由fork创建的线程以确定的顺序运行,主要根据代码指定的顺序执行,并且某些依赖于其他线程的容易出bug的操作会在运行时检查中禁止。

2.3.1 fork…join实例

使用类SV语法fork…join父进程等待join的子进程执行结束
注:下面的其他小节的实例,都使用如下DUT。

2.4 timescope特性

使用timescope保留仿真现场:

2.5 bundle字面量

向input端口poke bundle字面量
实例:

3 chiseltest 实例

3.1波形和printf调试方法

3.1.1波形

Chisel测试器可以生成包含所有寄存器和IO信号的波形。
生成波形的操作,目前有两种方式,如下:
1、在测试命令后加 – -DwriteVcd=1 可以生成vcd波形。

2、使用withAnnotations API,修改测试代码就行。

3.1.2 printf调试

Chisel提供了一个“ printf ”函数来打印信息,用于电路调试。它有Scala和C两种风格。如果在when语句块里,只有条件成立时才运行。隐式的全局复位信号有效时也不会触发。
Chisel的printf支持C的部分格式控制符和转义字符。如下图所示:

printf函数会转换成Verilog的系统函数“$fwrite”,包含在宏定义块“ ifndef SYNTHESIS… endif ”里。通过Verilog的宏定义,可以取消这部分不可综合的代码。
例如:printf(“dut01: %d %d %d %d\n”, io.fn, io.a, io.b, io.result)

在scala中也有两个打印函数,分别是printf和println,其注意事项如下:

打印函数 Scala Chisel
printf
(Predef.printf) 1、chisel3包已覆盖了Scala的标准包,要写成“Predef.printf”的完整路径形式。
2、主要用在主函数中,写在主函数中时,只要运行主函数,就会输出信息。
1、 只能写在用户定义的module中,
2、 并且必须要有时钟和复位,否则生成verilog报错,因此如果使用了RawModule,那么需要自定义时钟和复位域;
3、 只在运行测试的时候才有效,并且clk每走一次(也即step(1)),打印一次,必须要有step,否则printf不工作!
printIn 1、 既可以用在Module中,也可以用在主函数中
2、写在主函数中的打印函数,只要运行主函数,就会输出信息。 无

3.2 chipyard项目下的实例

ScalaTest是Scala的测试工具,Chisel的测试工具ChiselTest其实也是ScalaTest的拓展。
Chipyard项目下主要用的是ScalaTest库写的测试文件

例子:BOOM中的RegFileTest.scala

还有一些例子在:tools\chisel-testers\src\test\scala\examples

4 参考资料

1、 https://www.chisel-lang.org/chiseltest/
2、 https://github.com/ucb-bar/chiseltest
3、 https://blog.csdn.net/weixin_43681766/article/details/123931579
4、 https://github.com/ucb-bar/chipyard
5、 https://github.com/schoeberl/chisel-examples

5 chiselverify

5.1 chiselverify背景介绍

视频路径:https://www.bilibili.com/video/BV19V4y1J7Gj?spm_id_from=333.880.my_history.page.click&vd_source=bd907ea743c12b721d0cf6b2cc7a801d

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Python 中,静态方法和实例方法是两种不同的方法类型,它们有以下区别: 1. 调用方式不同:实例方法需要通过实例来调用,而静态方法则可以通过类名直接调用。 2. 参数不同:实例方法的第一个参数是 `self`,用于引用实例本身,而静态方法则没有 `self` 参数。 3. 访问权限不同:实例方法可以修改实例的状态,而静态方法不能修改实例的状态。 下面是一个示例代码,演示了如何定义和使用静态方法和实例方法: ``` python class MyClass: def instance_method(self): print("This is an instance method") self.value = 123 # 实例方法可以修改实例的状态 @staticmethod def static_method(): print("This is a static method") value = 456 # 静态方法不能修改实例的状态,只能访问类的属性和方法 # 创建一个 MyClass 的实例 my_instance = MyClass() # 调用实例方法 my_instance.instance_method() # 输出 "This is an instance method" # 访问实例状态 print(my_instance.value) # 输出 123 # 调用静态方法 MyClass.static_method() # 输出 "This is a static method" ``` 在上述代码中,`MyClass` 类包含一个实例方法 `instance_method` 和一个静态方法 `static_method`。在调用实例方法时,需要先创建一个 `MyClass` 的实例,然后通过实例来调用方法。实例方法可以修改实例的状态,例如在 `instance_method` 中将 `value` 属性赋值为 123。在调用静态方法时,可以直接通过类名来调用,不需要创建类的实例。静态方法不能修改实例的状态,但可以访问类的属性和方法。 总之,实例方法和静态方法在调用方式、参数和访问权限等方面有所不同,具体的选择取决于你的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值