问题概况
1. error 输出
运行GCD电路的测试,遇到java.lang.NoClassDefFoundError
问题:
[info] TestRealGCD *** ABORTED ***
[info] java.lang.NoClassDefFoundError: treadle/stage/TreadleTesterPhase$
[info] at chiseltest.backends.treadle.TreadleExecutive$.start(TreadleExecutive.scala:47)
[info] at chiseltest.defaults.package$.createDefaultTester(defaults.scala:24)
[info] at chiseltest.ChiselScalatestTester$TestBuilder.apply(ChiselScalatestTester.scala:30)
[info] at TestRealGCD.$anonfun$new$1(test.scala:43)
[info] at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[info] at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
[info] at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info] at org.scalatest.Transformer.apply(Transformer.scala:22)
[info] at org.scalatest.Transformer.apply(Transformer.scala:20)
[info] ...
[info] Cause: java.lang.ClassNotFoundException: treadle.stage.TreadleTesterPhase$
[info] at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
[info] at sbt.internal.ManagedClassLoader.findClass(ManagedClassLoader.java:102)
[info] at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
[info] at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
[info] at chiseltest.backends.treadle.TreadleExecutive$.start(TreadleExecutive.scala:47)
[info] at chiseltest.defaults.package$.createDefaultTester(defaults.scala:24)
[info] at chiseltest.ChiselScalatestTester$TestBuilder.apply(ChiselScalatestTester.scala:30)
[info] at TestRealGCD.$anonfun$new$1(test.scala:43)
[info] at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[info] at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info] ...
[error] Test suite TestRealGCD failed with java.lang.NoClassDefFoundError: treadle/stage/TreadleTesterPhase$.
[error] This may be due to the ClassLoaderLayeringStrategy (ScalaLibrary) used by your task.
[error] To improve performance and reduce memory, sbt attempts to cache the class loaders used to load the project dependencies.
[error] The project class files are loaded in a separate class loader that is created for each test run.
[error] The test class loader accesses the project dependency classes using the cached project dependency classloader.
[error] With this approach, class loading may fail under the following conditions:
[error]
[error] * Dependencies use reflection to access classes in your project's classpath.
[error] Java serialization/deserialization may cause this.
[error] * An open package is accessed across layers. If the project's classes access or extend
[error] jvm package private classes defined in a project dependency, it may cause an IllegalAccessError
[error] because the jvm enforces package private at the classloader level.
[error]
[error] These issues, along with others that were not enumerated above, may be resolved by changing the class loader layering strategy.
[error] The Flat and ScalaLibrary strategies bundle the full project classpath in the same class loader.
[error] To use one of these strategies, set the ClassLoaderLayeringStrategy ke
[error] in your configuration, for example:
[error]
[error] set testrealgcd / Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.ScalaLibrary
[error] set testrealgcd / Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat
[error]
[error] See ClassLoaderLayeringStrategy.scala for the full list of options.
2. 测试代码
import org.scalatest._
import chiseltest._
import chisel3._
import chisel3.experimental.BundleLiterals._
import java.util.regex.Matcher
class TestRealGCD extends FlatSpec with ChiselScalatestTester with Matchers {
behavior of "RealGCD"
it should "calculate proper greatest common denominator" in {
test(new DecoupledGcd(16)) { dut =>
dut.input.initSource().setSourceClock(dut.clock)
dut.output.initSink().setSinkClock(dut.clock)
val testValues = for { x <- 1 to 4; y <- 1 to 4} yield (x, y)
val inputSeq = testValues.map { case (x, y) =>
(new GcdInputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U)
}
val resultSeq = testValues.map { case (x, y) =>
new GcdOutputBundle(16).Lit(_.value1 -> x.U, _.value2 -> y.U, _.gcd -> BigInt(x).gcd(BigInt(y)).U)
}
fork {
dut.input.enqueueSeq(inputSeq)
}.fork {
for (expected <- resultSeq) {
dut.output.expectDequeue(expected)
dut.clock.step(5) // wait some cycles before receiving the next output to create backpressure
}
}.join()
}
}
}
3. chisel硬件描述代码
class GcdInputBundle(val w: Int) extends Bundle {
val value1 = UInt(w.W)
val value2 = UInt(w.W)
}
class GcdOutputBundle(val w: Int) extends Bundle {
val value1 = UInt(w.W)
val value2 = UInt(w.W)
val gcd = UInt(w.W)
}
class DecoupledGcd(width: Int) extends MultiIOModule {
val input = IO(Flipped(Decoupled(new GcdInputBundle(width))))
val output = IO(Decoupled(new GcdOutputBundle(width)))
val xInitial = Reg(UInt())
val yInitial = Reg(UInt())
val x = Reg(UInt())
val y = Reg(UInt())
val busy = RegInit(false.B)
val resultValid = RegInit(false.B)
input.ready := ! busy
output.valid := resultValid
// 可一直使用其赋值而不需要等到计算完毕,因为计算完毕声明output.valid后才会发生传输,且传输之前x会保持。
output.bits.value1 := xInitial
output.bits.value2 := yInitial
output.bits.gcd := x
when(busy) {
// during computation keep subtracting the smaller from the larger
when(x > y) {
x := x - y
}.otherwise {
y := y - x
}
when(y === 0.U) {
// when y becomes zero computation is over,
// signal valid data to output
// data transfer if the output is ready SO non-asserted busy signal
resultValid := true.B
busy := ! output.ready
}
}.otherwise {
when(input.valid) {
// valid data available and no computation in progress, grab new values and start
val bundle = input.deq()
x := bundle.value1
y := bundle.value2
xInitial := bundle.value1
yInitial := bundle.value2
busy := true.B
resultValid := false.B
}
}
}
4. build.sbt
scalaVersion := "2.12.13"
scalacOptions ++= Seq(
"-deprecation",
"-feature",
"-unchecked",
"-Xfatal-warnings",
"-Xsource:2.11",
"-language:reflectiveCalls",
// Enables autoclonetype2
"-P:chiselplugin:useBundlePlugin"
)
resolvers ++= Seq(
Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases")
)
// Chisel 3.4
addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.4.3" cross CrossVersion.full)
libraryDependencies += "edu.berkeley.cs" %% "chisel-iotesters" % "1.5.3"
libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.2.1"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test"
解决方法
-
将
build.sbt
文件中的库依赖libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.2.1"
改成libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.3.3" % "test"
在ChiselTest官网Chisel/FIRRTL: ChiselTest (chisel-lang.org)给出的示例是
libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.2.1"
但可能因为久未更新。最终是参考chisel-template给出的项目模板做出的修改才解决:
chisel-template: A template project for beginning new Chisel work 同时应该参考其中使用org.scalatest.FreeSpec
而不是FlatSpec
可以减少更多的 boiler plate -
猜测原因:
chiseltest 0.2.
与scalaTest
版本间的二进制不兼容问题 -
参考:
chisel3/MultiIOModule not found whe running tests with Chisel 3.5-SNAPSHOT
Latest merge with experimental fails · Issue #996 · chipsalliance/chisel3