位宽推断问题

时间:2018-07-26 11:09:29

标签: riscv chisel

凿子代码(下面提供)通过了测试并被编译,但是在尝试生成verilog文件时发生错误。

凿子代码:

import chisel3._
import chisel3.core.VecInit
import chisel3.util._

//A n-bit adder with carry in and carry out
class AdderNbit(val n: Int) extends Module {    
 val io = IO( new Bundle {
  val A = Input(UInt(n.W))
  val B = Input(UInt(n.W))
  val Cin = Input(UInt(1.W))
  val Sum = Output(UInt(n.W))
  val Cout = Output(UInt(1.W))
 })
 val FAs = Vec(Seq.fill(n) {Module(new FullAdder()).io })
 val carry = Wire(Vec(n+1, UInt(1.W)))
 val sum = Wire(Vec(n, Bool()))
 carry(0) := io.Cin
 for(i <- 0 until n) {
   FAs(i).a := io.A(i)
   FAs(i).b := io.B(i)
   FAs(i).cin := carry(i)
   sum(i) := FAs(i).sum.toBool()
   carry(i+1) := FAs(i).cout
 }
 io.Sum := sum.asUInt()
 io.Cout := carry(n)
}

//Binary to thermometer code converter
class BinThermConv(n: Int) extends Module {
 val io = IO(new Bundle {
  val bin = Input(UInt(n.W))
  val therm = Output(UInt())
 })

 val w = (math.pow(2,n).toInt)-1
 val x = 0.U(w.W)
 val z = Wire(UInt(w.W))
 z := (x | ((1.U << io.bin)-1.U))
 io.therm  := z
}

//4-bit adder with carry in and carry out and coverts sum into thermometer code 
class Adder4bit extends Module {
  val io = IO(new Bundle {
    val A = Input(UInt(4.W))    
    val B = Input(UInt(4.W))  
    val Cin = Input(UInt(1.W))    
    val SumTherm = Output(UInt())
    val Cout = Output(UInt(1.W))
  })

  val Ad = Module(new AdderNbit(4))
  Ad.io.A := io.A
  Ad.io.B := io.B
  Ad.io.Cin := io.Cin

  val Btc = Module(new BinThermConv(Ad.n))
  Btc.io.bin := Ad.io.Sum
  io.SumTherm := Btc.io.therm
  io.Cout := Ad.io.Cout
}

测试工具:

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

class Adder4bitTests(c: Adder4bit) extends PeekPokeTester(c) {
  for (t <- 0 until 1024) {    
    val rnd0 = rnd.nextInt(16)    
    val rnd1 = rnd.nextInt(16)    
    val rnd2 = rnd.nextInt(2)    
    poke(c.io.A,   rnd0)    
    poke(c.io.B,   rnd1)    
    poke(c.io.Cin, rnd2)    
    step(1)    
    val rsum = (rnd0 & 0xF) + (rnd1 & 0xF) + (rnd2 & 0x1)    
    val rsumTherm = 1 << (rsum & 0xF)    
    expect(c.io.SumTherm, ((rsumTherm-1) & 0x7FFF))    
    expect(c.io.Cout, rsum >> 4)    
  }    
}  

class Adder4bitTester extends ChiselFlatSpec {    
  behavior of "Adder4bit"    
  backends foreach {backend =>    
    it should s"correctly add randomly generated numbers $backend" in {    
      Driver(() => new Adder4bit,backend)((c) => new Adder4bitTests(c)) should be (true)    
    }    
  }    
}

遇到错误:

> test:run-main examples.Launcher Adder4bit --backend-name=verilator
[info] Running examples.Launcher Adder4bit --backend-name=verilator
Starting tutorial Adder4bit
[info] [0.001] Elaborating design...
[info] [0.086] Done elaborating.
Total FIRRTL Compile Time: 345.5 ms
java.util.NoSuchElementException: None.get
    at scala.None$.get(Option.scala:347)
    at chisel3.internal.firrtl.UnknownWidth.get(IR.scala:183)
    at chisel3.core.Data.getWidth(Data.scala:371)
    at chisel3.iotesters.VerilatorCppHarnessGenerator$$anonfun$codeGen$2.apply(VerilatorBackend.scala:92)
    at chisel3.iotesters.VerilatorCppHarnessGenerator$$anonfun$codeGen$2.apply(VerilatorBackend.scala:90)
    at scala.collection.immutable.List.foreach(List.scala:392)
    at chisel3.iotesters.VerilatorCppHarnessGenerator$.codeGen(VerilatorBackend.scala:90)
    at chisel3.iotesters.setupVerilatorBackend$.apply(VerilatorBackend.scala:247)
    at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1.apply$mcZ$sp(Driver.scala:53)
    at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1.apply(Driver.scala:38)
    at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1.apply(Driver.scala:38)
    at logger.Logger$$anonfun$makeScope$1.apply(Logger.scala:129)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at logger.Logger$.makeScope(Logger.scala:127)
    at chisel3.iotesters.Driver$$anonfun$execute$1.apply$mcZ$sp(Driver.scala:38)
    at chisel3.iotesters.Driver$$anonfun$execute$1.apply(Driver.scala:38)
    at chisel3.iotesters.Driver$$anonfun$execute$1.apply(Driver.scala:38)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at chisel3.iotesters.Driver$.execute(Driver.scala:37)
    at examples.Launcher$$anonfun$22.apply(Launcher.scala:125)
    at examples.Launcher$$anonfun$22.apply(Launcher.scala:124)
    at utils.TutorialRunner$$anonfun$apply$2.apply(TutorialRunner.scala:43)
    at utils.TutorialRunner$$anonfun$apply$2.apply(TutorialRunner.scala:36)
    at scala.collection.immutable.List.foreach(List.scala:392)
    at utils.TutorialRunner$.apply(TutorialRunner.scala:36)
    at examples.Launcher$.main(Launcher.scala:131)
    at examples.Launcher.main(Launcher.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sbt.Run.invokeMain(Run.scala:67)
    at sbt.Run.run0(Run.scala:61)
    at sbt.Run.sbt$Run$$execute$1(Run.scala:51)
    at sbt.Run$$anonfun$run$1.apply$mcV$sp(Run.scala:55)
    at sbt.Run$$anonfun$run$1.apply(Run.scala:55)
    at sbt.Run$$anonfun$run$1.apply(Run.scala:55)
    at sbt.Logger$$anon$4.apply(Logger.scala:84)
    at sbt.TrapExit$App.run(TrapExit.scala:248)
    at java.lang.Thread.run(Thread.java:748)
================================================================================
Errors: 1: in the following tutorials
Tutorial Adder4bit: exception None.get
================================================================================

Exception: sbt.TrapExitSecurityException thrown from the UncaughtExceptionHandler in thread "run-main-1"
java.lang.RuntimeException: Nonzero exit code: 1
    at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last test:runMain for the full output.
[error] (test:runMain) Nonzero exit code: 1
[error] Total time: 1 s, completed Jul 15, 2018 10:39:45 AM

在这里,我们试图计算两个4位数字的总和,并将其转换为温度计代码。

我们已经能够隔离问题,看来该错误是由于位宽推断引起的。似乎SumTherm没有以适当的方式获得位宽,因为Btc.io.therm也没有明确定义。但是,如果通过以下方式定义端口:val SumTherm = Output(UInt(15.W))一切正常。

但是应该不会发生此问题,因为val w = ((math.pow(2,n).toInt)-1)可以为温度计代码计算适当的宽度,并且变量zx的大小应适当。因此Btc.io.therm应该获得UInt宽度为w的值,io.SumTherm也应该如此。

对这种奇怪行为有任何想法吗?

1 个答案:

答案 0 :(得分:1)

感谢您对此问题的详细说明!

这似乎是凿子测试仪中的错误。 Verilog实际上是在生成的,但看来Verilator凿子测试器后端试图获取凿子对象的宽度,这些对象的宽度未如您所述。相反,它应该从生成的FIRRTL中获取宽度,或者至少能够处理未定义宽度的端口。

您介意将所有这些信息作为问题提交到chisel-testers Github repo上,以便该项目的维护者可以看看吗?