01-chisel-tutorial代码学习之GCD

1. chisel-tutorial初介绍

chisel-tutorial是ucb写的一个代码库,放在github上,用于初学者学习一些chisel的基础语法。
重点推荐这个github库的wiki页面,对chisel基础语法基本都涉及到了。

我这里就是简单的记录一下这个代码的学习笔记。

2. chisel-tutorial代码库的文件结构

下面是文件结构,直接从wiki上粘贴过来的。编译器通过build.sbt这个文件下载相应的依赖。

chisel-tutorial/  
  build.sbt # project description
  run-examples.sh   # shell script to execute one or more examples
  run-problem.sh    # shell script to execute one or more problems
  run-solution.sh   # shell script to execute one or more solutions
  src/
    main/
      scala/
        examples/   # chisel examples
          Accumulator.scala ...
        problems/   # skeletal files for tutorial problems
          Counter.scala ...
        solutions/  # solutions to problems
          Counter.scala ...
    test/
      resources/
        in.im24
        in.wav
      scala/
        examples/   # examples testers
          AdderTests.scala ...
        problems/   # problems testers
          AccumulatorTest.scala ...
        solutions/  # solutions testers
          AccumulatorTests.scala ...
        util/
          TutorialRunner.scala

3. chisel代码初体验: GCD.scala

GCD.scala这个文件是wiki里让看的第一个chisel代码,具备了chisel代码的基本元素,这个模块的作用是计算2个16-bit无符号数的最大公约数。我这里直接把代码贴过来,

package examples

import chisel3._

/**
 * Compute the GCD of 'a' and 'b' using Euclid's algorithm.
 * To start a computation, load the values into 'a' and 'b' and toggle 'load'
 * high.
 * The GCD will be returned in 'out' when 'valid' is high.
 */
class GCD extends Module {
  val io = IO(new Bundle {
    val a     = Input(UInt(16.W))
    val b     = Input(UInt(16.W))
    val load  = Input(Bool())
    val out   = Output(UInt(16.W))
    val valid = Output(Bool())
  })
  val x = Reg(UInt())
  val y = Reg(UInt())

  when (io.load) {
    x := io.a; y := io.b
  } .otherwise {
    when (x > y) {
      x := x - y
    } .elsewhen (x <= y) {
      y := y - x
    }
  }

  io.out := x
  io.valid := y === 0.U
}

代码GCD.scala分为3大部分,

  • package examples涉及scala的包管理,这里暂不作细致介绍
  • import chisel3._引入chisel3的库文件,其中._表示将chisel3的所有库文件都引入进来,不引入就不可以使用chisel定义的关键词,比如IOBundleUIntwhen等等
  • 最后一大部分就是class GCD extends Module {},这部分可以等价理解为verilog的模块定义,包括端口定义和逻辑设计。chisel中定义模块,需要这个class继承Module
    • 首先是端口定义val io = IO(new Bundle{ ... }),这几个字母是固定的,io就是ioIO就是IOnew Bundle{}就是new Bundle{},不能写错,不理解就死记住,将来再理解。
    • 接着定义了2个寄存器Reg分别是xy,用作中间变量
    • 然后是一个when代码块,直接把这个代码块理解成verilog里always @ (posedge clock)块的if ... else if ... else ...就行了,完全是同一个意思
    • when代码块里,xy的赋值用的是:=操作符,这是因为在scala中,val定义的变量是不可变变量,一旦定义好之后,不可以重新赋值,因此chisel定义了:=操作符,用于val变量的重新赋值,最后两个输出的赋值也是同理。注意,chisel中变量首次定义或者说赋值使用=操作符,后面的重赋值使用:=操作符。
    • 最后给两个输出端口赋值,也就是verilog里assign

整个GCD.scala的代码比较简单,需要注意的就是2点,

  • 1是端口列表里没有clock信号和reset信号,这是因为chisel会隐式的添加这两个信号到端口列表中,不需要我们手动添加。最后生成verilog代码后就可以看到这两个信号了。
  • 2是xy这样的中间变量不需要指定位宽,chisel具有强大的位宽推断功能,会自动指定所需要的最小位宽

4. chisel的testbench

在verilog中,我们写完一个模块,一般还会写一个testbench来仿真验证这个模块的功能,chisel也是一样的。对于刚才所写的GCD.scala这个模块,在/src/test/scala/examples/路径下有一个测试文件,GCDTests.scala,相当于verilog里的testbench。这里把代码贴过来,

package examples

import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}

class GCDTests(c: GCD) extends PeekPokeTester(c) {
  val inputs = List( (48, 32), (7, 3), (100, 10) )
  val outputs = List( 16, 1, 10)

  var i = 0
  do {
    poke(c.io.a, inputs(i)._1)
    poke(c.io.b, inputs(i)._2)

    poke(c.io.load, 1)
    step(1)
    poke(c.io.load, 0)

    var ready = false

    do {
      ready = peek(c.io.valid) == 1
      step(1)
    } while (t < 100 && ! ready)

    expect(c.io.out, outputs(i))
    i += 1
  } while (t < 100 && i < 3)

  if (t >= 100) fail
}

class GCDTester extends ChiselFlatSpec {
  behavior of "GCD"

  backends foreach {backend =>
    it should s"test the basic gcd circuit" in {
      Driver(() => new GCD, backend)((c) => new GCDTests(c)) should be (true)
    }
  }
}

首先使用import引入iotesters,这是chisel的仿真库,包括常用的仿真方法peekpokestepexpect方法。

然后定义了一个类GCDTests(c)去继承PeekPokeTester,主构造器接收一个待测模块GCD类型的对象c,并将c传递给PeekPokeTester。在类的内部,主要由一个do..while代码块构成,写了3个测试用例,使用poke给待测模块的输入赋值,使用expect去检验待测模块的输出和期望值是不是相等的,如果相等,就会在仿真时输出success

5. 运行chisel仿真

按照wiki的指示,运行./run-examples.sh GCD,经过编译和仿真后有如下打印,

test GCD Success: 3 tests passed in 29 cycles in 0.044277 seconds 654.96 Hz
[info] [0.015] RAN 24 CYCLES PASSED
Tutorials passing: 1
[success] Total time: 7 s, completed 2021-8-19 20:32:17

表示3个测试用例都通过了。

6. 生成verilog代码和vcd波形文件

使用刚才的脚本命令,再增加一个环境变量即可。

./run-examples.sh GCD --backend-name verilator

运行这个脚本命令,就会在chisel-tutorial/test_run_dir/examples/GCD/目录下,生成许多编译和仿真的文件,中间我们最关心的就是两个,一个是产生的verilog文件,一个是.vcd波形文件。使用gtkwave就可以打开波形文件看,例如这次生成的GCD.vcd使用gtkwave打开就如下图所示,

GCD仿真波形文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值