Chisel 6.2.0中Hex文件初始化内存测试失败求助
Chisel 6.2.0中
loadMemoryFromFileInline加载Hex文件初始化内存测试失败问题 在Chisel 6.2.0中使用loadMemoryFromFileInline加载Hex文件初始化内存时,测试代码无法读取到预期数据,已确认文件路径无误,但功能不生效。相同代码在Chisel 5.1.0+chiseltest环境下可正常运行。
项目结构
example └── src │ └── hex │ │ └── example.hex.txt │ └── main/scala/circuit │ │ └── IMemory.scala │ └── test/scala/circuit │ └── IMemorySpec.scala └── build.sbt
相关代码
build.sbt(Chisel 6.2.0环境)
ThisBuild / scalaVersion := "2.13.12" ThisBuild / version := "0.1.0" ThisBuild / organization := "%ORGANIZATION%" val chiselVersion = "6.2.0" lazy val root = (project in file(".")) .settings( name := "%NAME%", libraryDependencies ++= Seq( "org.chipsalliance" %% "chisel" % chiselVersion, "org.scalatest" %% "scalatest" % "3.2.16" % "test" ), scalacOptions ++= Seq( "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", "-Ymacro-annotations" ), addCompilerPlugin( "org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full ) )
example.hex.txt
003100b3 40628033 06432283 06512423 064000ef
IMemory.scala
package circuit import chisel3._ import chisel3.util.experimental.loadMemoryFromFileInline import circt.stage.ChiselStage class IMemoryIO extends Bundle { val rdAddr = Input(UInt(5.W)) val rdData = Output(UInt(32.W)) val wrAddr = Input(UInt(5.W)) val wrData = Input(UInt(32.W)) val wrEna = Input(UInt(1.W)) } class IMemory(memoryFile: String = "") extends Module { val io = IO(new IMemoryIO) val mem = SyncReadMem(1024, UInt(32.W)) io.rdData := mem.read(io.rdAddr) io.rdData := mem(io.rdAddr) when(io.wrEna === 1.U) { mem.write(io.wrAddr, io.wrData) } if (memoryFile.trim().nonEmpty) { loadMemoryFromFileInline(mem, memoryFile) } }
IMemorySpec.scala(Chisel 6.2.0环境)
package circuit import chisel3._ import chisel3.experimental.BundleLiterals._ import chisel3.simulator.EphemeralSimulator._ import org.scalatest.freespec.AnyFreeSpec import org.scalatest.matchers.must.Matchers import java.io.File class IMemorySpec extends AnyFreeSpec with Matchers { "write memory" in { simulate(new IMemory("src/hex/example.hex.txt")) { dut => dut.io.wrAddr.poke(4.U) dut.io.wrEna.poke(1.U) dut.io.wrData.poke(0x003100b3.U) dut.clock.step() dut.io.rdAddr.poke(4.U) dut.clock.step() dut.io.rdData.expect(0x003100b3.U) } } "loadMemory from file" in { simulate(new IMemory("src/hex/example.hex.txt")) { dut => dut.io.rdAddr.poke(0.U) dut.clock.step() dut.io.rdData.expect(0x003100b3.U) } } }
错误输出
运行sbt "testOnly circuit.IMemorySpec"后,测试失败:
[info] - file should exist [info] - write memory [info] - loadMemory from file *** FAILED *** [info] chisel3.simulator.PeekPokeAPI$FailedExpectationException: Failed Expectation: Observed value '0' != 3211443. Expectation failed: observed value 0 != 3211443
Chisel 5.1.0环境下可行方案
build.sbt(Chisel 5.1.0环境)
ThisBuild / scalaVersion := "2.13.12" ThisBuild / version := "0.1.0" ThisBuild / organization := "%ORGANIZATION%" val chiselVersion = "5.1.0" lazy val root = (project in file(".")) .settings( name := "%NAME%", libraryDependencies ++= Seq( "org.chipsalliance" %% "chisel" % chiselVersion, "edu.berkeley.cs" %% "chiseltest" % "5.0.2" % "test" ), scalacOptions ++= Seq( "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", "-Ymacro-annotations" ), addCompilerPlugin( "org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full ) )
测试代码(Chisel 5.1.0环境)
package circuit import chisel3._ import chiseltest._ import org.scalatest.freespec.AnyFreeSpec import chisel3.experimental.BundleLiterals._ class IMemorySpec extends AnyFreeSpec with ChiselScalatestTester { "memory initial should work by example.hex.txt" in { test(new IMemory("src/hex/example.hex.txt")) { dut => dut.io.rdAddr.poke(0.U) dut.clock.step() dut.io.rdData.expect(0x003100b3.U) dut.io.rdAddr.poke(1.U) dut.clock.step() dut.io.rdData.expect(0x40628033.U) dut.io.rdAddr.poke(2.U) dut.clock.step() dut.io.rdData.expect(0x06432283.U) dut.io.rdAddr.poke(3.U) dut.clock.step() dut.io.rdData.expect(0x06512423.U) } } }
解决方案
Chisel 6.x版本中,默认的EphemeralSimulator对loadMemoryFromFileInline的内存初始化支持有限,切换回chiseltest测试框架即可解决问题,步骤如下:
1. 更新build.sbt
添加与Chisel版本匹配的chiseltest依赖:
ThisBuild / scalaVersion := "2.13.12" ThisBuild / version := "0.1.0" ThisBuild / organization := "%ORGANIZATION%" val chiselVersion = "6.2.0" lazy val root = (project in file(".")) .settings( name := "%NAME%", libraryDependencies ++= Seq( "org.chipsalliance" %% "chisel" % chiselVersion, "org.scalatest" %% "scalatest" % "3.2.16" % "test", "edu.berkeley.cs" %% "chiseltest" % chiselVersion % "test" ), scalacOptions ++= Seq( "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", "-Ymacro-annotations" ), addCompilerPlugin( "org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full ) )
2. 修改测试代码
改用chiseltest的API编写测试:
package circuit import chisel3._ import chiseltest._ import org.scalatest.freespec.AnyFreeSpec import chisel3.experimental.BundleLiterals._ class IMemorySpec extends AnyFreeSpec with ChiselScalatestTester { "write memory" in { test(new IMemory("src/hex/example.hex.txt")) { dut => dut.io.wrAddr.poke(4.U) dut.io.wrEna.poke(1.U) dut.io.wrData.poke(0x003100b3.U) dut.clock.step() dut.io.rdAddr.poke(4.U) dut.clock.step() dut.io.rdData.expect(0x003100b3.U) } } "loadMemory from file" in { test(new IMemory("src/hex/example.hex.txt")) { dut => dut.io.rdAddr.poke(0.U) dut.clock.step() dut.io.rdData.expect(0x003100b3.U) } } }
3. 额外优化
IMemory.scala中存在冗余代码:io.rdData := mem.read(io.rdAddr)和io.rdData := mem(io.rdAddr)重复,mem(io.rdAddr)等价于调用read方法,保留其中一行即可:
// 保留其中一行,比如: io.rdData := mem(io.rdAddr)
4. 验证测试
重新运行测试命令:
sbt "testOnly circuit.IMemorySpec"
内容的提问来源于stack exchange,提问作者Fang Yongrui
相关产品推荐
相关产品推荐

