学习github上的chisel教材之Module 2.1: Your First Chisel Module¶

第一部分、
1、Chisel stands for Constructing Hardware In a Scala Embedded Language(chisel 是 嵌在Scala上的硬件构造语言)意味着它是Scala中的DSL,使您可以在同一代码中利用Scala和Chisel编程,同时 了解哪个代码是“ Scala”和哪个代码是“ Chisel”很重要。

2、该模块将为您提供整个Chisel模块和test case 。


//为Chisel下载所需要的依赖项
val path = System.getProperty("user.dir") + "/source/load-ivy.sc"
interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))

//导入Chisel时需要以下语句
import chisel3._
import chisel3.util._
import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}

第二部分:
以下正式进入写module of Chisel部分:
像Verilog一样,在Chisel中声明模块定义;
以下示例为Chisel模块:具有一个4位输入和一个4位输出。 该模块组合直接连接输入和输出。

// Chisel Code: Declare a new module definition
class Passthrough extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(4.W))
    val out = Output(UInt(4.W))
  })
  io.out := io.in
}
//第一句:我们声明一个名为Passthrough的新模块。 模块 is a built-in Chisel class that all hardware modules must extend.

//第二句:把所有的输入和输出都声明为io val . 它必须被叫做io,并且是IO对象或者实例, which requires something of the form IO(_instantiated_bundle_).

//第三句:声明了一个新的"硬件结构"类型(Bundle),其中包含 some named signals in and out with directions Input and Output, respectively.

//第四句:我们声明信号的"硬件类型"。 在这种情况下,它是宽度为4的无符号整数。

//第五句:将输入端口连接到输出端口,以便io.in驱动io.out。 请注意,:=运算符是Chisel运算符,它指示右侧信号驱动左侧信号。 它是定向操作员。

总结:关于硬件构造语言(HCL)的整洁之处在于,我们可以将基础编程语言用作脚本语言。 例如,在声明我们的Chisel模块之后,我们然后使用Scala调用Chisel编译器将Chisel Passthrough转换为Verilog Passthrough。 这个过程称为精化(elaboration)

// Scala代码:通过将其翻译为Verilog来详细说明我们的凿子设计
//不要担心理解此代码; 这是非常复杂的Scala
println(getVerilog(new Passthrough))

//请注意,我们模块的名称是cmd<#>WrapperHelperPassthrough,这是因为刚刚在Jupyter环境才这样。 在常规代码中,其名称应仅为Passthrough。

第三部分:写模块生成器
如果将对Scala的了解应用于本示例,则可以看到Chisel模块已作为Scala类实现。 与其他Scala类一样,我们可以使Chisel模块采用一些构造参数(construction parameters)。 在这种情况下,我们创建一个新的PassthroughGenerator类,该类将接受一个整数宽度,该整数指示其输入和输出端口的宽度:

// Chisel Code, but pass in a parameter to set widths of ports
class PassthroughGenerator(width: Int) extends Module { 
  val io = IO(new Bundle {
    val in = Input(UInt(width.W))
    val out = Output(UInt(width.W))
  })
  io.out := io.in
}

// Let's now generate modules with different widths
println(getVerilog(new PassthroughGenerator(10)))
println(getVerilog(new PassthroughGenerator(20)))

解释:Chisel模块是普通的Scala类,所以我们可以使用Scala的类构造函数的功能来参数化设计的细节。
您可能会注意到,此参数化是由Scala而非Chisel启用的; Chisel没有其他用于参数化的API,但是设计人员可以简单地利用Scala功能对他/她的设计进行参数化。
因为PassthroughGenerator不再描述单个模块,而是描述了由width参数化的一系列模块,所以我们将此Passthrough称为生成器。

第四部分:写tester
没有测试,任何硬件模块或发生器都不应完整。 Chisel具有内置的测试功能,您将在本训练营中进行探索。 以下示例是Chisel测试工具,它将值传递到Passthrough输入端口输入的实例,并检查在输出端口out上是否看到相同的值。

//这里有一些高级Scala。 但是,除了poke和Expect命令之外,您无需了解其他任何内容。 您可以将其余代码视为编写这些简单测试的简单样板。
//Scala代码:调用Driver实例化Passthrough + PeekPokeTester并执行测试。
//不要担心理解此代码; Scala非常复杂。
//将其更多地看作是运行Chisel测试的样板。
val testResult = Driver(() => new PassthroughGenerator()) {
  c => new PeekPokeTester(c) {
    poke(c.io.in, 0)     // Set our input to value 0
    expect(c.io.out, 0)  // Assert that the output correctly has 0
    poke(c.io.in, 1)     // Set our input to value 1
    expect(c.io.out, 1)  // Assert that the output correctly has 1
    poke(c.io.in, 2)     // Set our input to value 2
    expect(c.io.out, 2)  // Assert that the output correctly has 2
  }
}
assert(testResult)   // Scala Code: if testResult == false, will throw an error
println("SUCCESS!!") // Scala Code: if we get here, our tests passed!

//这是怎么回事? 该测试接受Passthrough模块,为该模块的输入分配值,然后检查其输出。 要设置输入,我们称为poke,为了检查输出,我们称expexct。 
//如果我们不想将输出与期望值进行比较(no assertion),则可以查看peek输出。
//如果所有的期望语句都为true,则我们的样板代码将返回true(请参见testResult)。

练习:编写自己的testers
编写并执行两个测试,一个测试PassthroughGenerator的宽度为10,第二个测试PassthroughGenerator的宽度为20。
检查每个值至少两个值:零和指定宽度支持的最大值。 请注意,教程显示的???指自己要写的那部分
以下是填完???之后的代码(就是答案)

val test10result = Driver(() => new PassthroughGenerator(10)) {
  c => new PeekPokeTester(c) {
    poke(c.io.in, 0)
    expect(c.io.out, 0)
    poke(c.io.in, 1023) 
    expect(c.io.out, 1023)
  }
}

val test20result = Driver(() => new PassthroughGenerator(20)) {
  c => new PeekPokeTester(c) {
    poke(c.io.in, 0)
    expect(c.io.out, 0)
    poke(c.io.in, 1048575)
    expect(c.io.out, 1048575)
  }
}

第五部分:查看生成的Verilog / FIRRTL
如果您在理解生成的硬件时遇到麻烦,并且对阅读结构性的Verilog和/或FIRRTL(Chisel的IR相当于Verilog的仅合成子集)感到满意。可以尝试查看生成的Verilog以查看Chisel执行的结果。
以下是生成Verilog和FIRRTL的示例:

// Viewing the Verilog for debugging
println(getVerilog(new Passthrough))
// Viewing the firrtl for debugging
println(getFirrtl(new Passthrough))

附录:有关“ printf”调试的说明
使用打印语句进行调试并非始终是最佳的调试方法,但通常是第一步,可以轻松地了解当某些事情无法按预期方式工作时正在发生的情况。 Because Chisel generators are programs generating hardware, there are some extra subtleties about printing generator and circuit state。 重要的是要记住您的打印语句何时执行以及正在打印什么。
The three common scenarios where you might want to print have some important differences:
1、Chisel generator prints during circuit generation
2、Circuit prints during circuit simulation
3、Tester prints during testing

println是一个内置的Scala函数,可打印到控制台。 由于生成的电路是FIRRTL或Verilog-而非Scala,因此不能在电路仿真期间用于打印。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值