Skip to content

Commit

Permalink
Fix 0 width signals chiselsim (#4100)
Browse files Browse the repository at this point in the history
  • Loading branch information
rameloni authored May 28, 2024
1 parent 151d63b commit 2f9faa2
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 5 deletions.
15 changes: 10 additions & 5 deletions src/main/scala/chisel3/simulator/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,16 @@ package object simulator {
}
}
case element: Element =>
DataMirror.directionOf(element) match {
case ActualDirection.Input =>
Seq((element, ModuleInfo.Port(name, isGettable = true, isSettable = true)))
case ActualDirection.Output => Seq((element, ModuleInfo.Port(name, isGettable = true)))
case _ => Seq()
// Return the port only if the width is positive (firtool will optimized it out from the *.sv primary source)
if (element.widthKnown && element.getWidth > 0) {
DataMirror.directionOf(element) match {
case ActualDirection.Input =>
Seq((element, ModuleInfo.Port(name, isGettable = true, isSettable = true)))
case ActualDirection.Output => Seq((element, ModuleInfo.Port(name, isGettable = true)))
case _ => Seq()
}
} else {
Seq()
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/test/scala/chiselTests/simulator/OptionalIOModule.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package chiselTests.simulator

import chisel3._

class OptionalIOModule(n: Int) extends Module {
val a, b, c = IO(Input(Bool()))
val d, e, f = IO(Input(Bool()))
val foo, bar = IO(Input(UInt(n.W)))
val emptyBundle = IO(Input(new Bundle {}))
val bundle = IO(Input(new Bundle { val x = foo.cloneType }))
val out = IO(Output(UInt(n.W)))

val myReg = RegInit(0.U(n.W))

out := myReg

when(a && b && c) {
myReg := foo
}
when(d && e && f) {
myReg := bar
}
}
72 changes: 72 additions & 0 deletions src/test/scala/chiselTests/simulator/SimulatorSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import chisel3.simulator._
import chisel3.util.{HasExtModuleInline, HasExtModulePath, HasExtModuleResource}
import org.scalatest.funspec.AnyFunSpec
import org.scalatest.matchers.must.Matchers
import org.scalatest.matchers.should.Matchers.convertToAnyShouldWrapper
import svsim._

class VerilatorSimulator(val workspacePath: String) extends SingleBackendSimulator[verilator.Backend] {
Expand Down Expand Up @@ -158,5 +159,76 @@ class SimulatorSpec extends AnyFunSpec with Matchers {

}

it("simulate a circuit with zero-width ports") {
val width = 0
// Run a simulation with zero width foo
new VerilatorSimulator("test_run_dir/simulator/foo_zero_width") {
override val firtoolArgs = Seq("--strip-debug-info", "-g")
}
.simulate(new OptionalIOModule(n = width)) { module =>
import PeekPokeAPI._
val dut = module.wrapped
dut.clock.step(2)
dut.clock.step(10)
}
.result

// Check the testbench sv does not contain dut.foo and dut.out
val tbSource = io.Source.fromFile("test_run_dir/simulator/foo_zero_width/generated-sources/testbench.sv")
val tbSV = tbSource.mkString
tbSource.close()
// Check IO ports
(tbSV should not).include("dut.foo")
(tbSV should not).include("dut.bar")
(tbSV should not).include("dut.out")
(tbSV should not).include("dut.emptyBundle")
(tbSV should not).include("dut.bundle_x")

val source = io.Source.fromFile("test_run_dir/simulator/foo_zero_width/primary-sources/OptionalIOModule.sv")
val actualSV = source.mkString
source.close()
(actualSV should not).include("foo")
(actualSV should not).include("bar")
(actualSV should not).include("myReg")
(actualSV should not).include("output [7:0] out")
(actualSV should not).include("emptyBundle")
(actualSV should not).include("bundle_x")
}

it("simulate a circuit with non zero-width ports") {
val width = 8
// Run a simulation with zero width foo
new VerilatorSimulator("test_run_dir/simulator/foo_non_zero_width") {
override val firtoolArgs = Seq("--strip-debug-info", "-g")
}
.simulate(new OptionalIOModule(n = width)) { module =>
import PeekPokeAPI._
val dut = module.wrapped
dut.clock.step(2)
dut.clock.step(10)
}
.result

// Check the testbench sv does not contain dut.foo and dut.out
val tbSource = io.Source.fromFile("test_run_dir/simulator/foo_non_zero_width/generated-sources/testbench.sv")
val tbSV = tbSource.mkString
tbSource.close()
// Check IO ports
tbSV should include("[$bits(dut.foo)-1:0] foo")
tbSV should include("[$bits(dut.bar)-1:0] bar")
tbSV should include("[$bits(dut.out)-1:0] out")
(tbSV should not).include("emptyBundle")
tbSV should include("[$bits(dut.bundle_x)-1:0] bundle_x")

val source = io.Source.fromFile("test_run_dir/simulator/foo_non_zero_width/primary-sources/OptionalIOModule.sv")
val actualSV = source.mkString
source.close()
actualSV should include("foo")
actualSV should include("bar")
actualSV should include("myReg")
actualSV should include("output [7:0] out")
(actualSV should not).include("emptyBundle")
actualSV should include("bundle_x")
}
}
}

0 comments on commit 2f9faa2

Please sign in to comment.