Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[choice] Adds a means to declare a choice group without use #4554

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion core/src/main/scala/chisel3/choice/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
package chisel3

import chisel3.experimental.{BaseModule, SourceInfo}
import chisel3.internal.Builder
import chisel3.util.simpleClassName

import scala.collection.mutable
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{currentMirror => cm}
Comment on lines +10 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scala.reflect._ doesn't cross-compile with Scala 3, it needs to be put in core/src/main/scala-2/chisel3/


/** This package contains Chisel language definitions for describing configuration options and their accepted values.
*/
package object choice {
Expand All @@ -13,7 +18,7 @@ package object choice {
*
* @example
* {{{
* import chisel3.option.{Group, Case}
* import chisel3.choice.{Group, Case}
* object Platform extends Group {
* object FPGA extends Case
* object ASIC extends Case
Expand All @@ -23,6 +28,22 @@ package object choice {
abstract class Group(implicit _sourceInfo: SourceInfo) {
self: Singleton =>

private[choice] def registerCases(): Unit = {
// Grab a symbol for the derived class (a concrete Group)
val instanceMirror = cm.reflect(this)
val symbol = instanceMirror.symbol

symbol.typeSignature.members.collect {
// Look only for inner objects in the Group. Note, this is not recursive.
case m: ModuleSymbol if m.isStatic =>
val instance = cm.reflectModule(m.asModule).instance
// Confirms the instance is a subtype of Case
if (cm.classSymbol(instance.getClass).toType <:< typeOf[Case]) {
Builder.options += instance.asInstanceOf[Case]
}
}
}

private[chisel3] def sourceInfo: SourceInfo = _sourceInfo

private[chisel3] def name: String = simpleClassName(this.getClass())
Expand All @@ -47,4 +68,14 @@ package object choice {
*/
def ->[T](module: => T): (Case, () => T) = (this, () => module)
}

/** Registers all options in a group with the Builder.
* This lets Chisel know that this layer should be emitted into FIRRTL text.
*
* This API can be used to guarantee that a design will always have certain
* group defined. This is analagous in spirit to [[layer.addLayer]].
*/
def addGroup(group: Group): Unit = {
group.registerCases()
}
}
40 changes: 27 additions & 13 deletions src/test/scala/chiselTests/ModuleChoiceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package chiselTests

import chisel3._
import chisel3.choice.{Case, Group, ModuleChoice}
import chisel3.choice.{addGroup, Case, Group, ModuleChoice}
import chiselTests.{ChiselFlatSpec, MatchesAndOmits, Utils}
import _root_.circt.stage.ChiselStage

Expand All @@ -23,7 +23,7 @@ class ASICTarget extends FixedIOExtModule[TargetIO](new TargetIO(8))

class VerifTarget extends FixedIORawModule[TargetIO](new TargetIO(8))

class ModuleChoiceSpec extends ChiselFlatSpec with Utils with MatchesAndOmits {
class ModuleChoiceSpec extends ChiselFlatSpec with Utils with FileCheck {
it should "emit options and cases" in {
class ModuleWithChoice extends Module {
val out = IO(UInt(8.W))
Expand All @@ -35,17 +35,14 @@ class ModuleChoiceSpec extends ChiselFlatSpec with Utils with MatchesAndOmits {
out := inst.out
}

val chirrtl = ChiselStage.emitCHIRRTL(new ModuleWithChoice, Array("--full-stacktrace"))

info("CHIRRTL emission looks correct")
matchesAndOmits(chirrtl)(
"option Platform :",
"FPGA",
"ASIC",
"instchoice inst of VerifTarget, Platform :",
"FPGA => FPGATarget",
"ASIC => ASICTarget"
)()
generateFirrtlAndFileCheck(new ModuleWithChoice)(
"""|CHECK: option Platform :
|CHECK-NEXT: FPGA
|CHECK-NEXT: ASIC
|CHECK: instchoice inst of VerifTarget, Platform :
|CHECK-NEXT: FPGA => FPGATarget
|CHECK-NEXT: ASIC => ASICTarget""".stripMargin
)
}

it should "require that all cases are part of the same option" in {
Expand Down Expand Up @@ -129,3 +126,20 @@ class ModuleChoiceSpec extends ChiselFlatSpec with Utils with MatchesAndOmits {
}

}
class AddGroupSpec extends ChiselFlatSpec with Utils with FileCheck {
it should "emit options for a registered group even if there are no consumers" in {
class ModuleWithoutChoice extends Module {
addGroup(Platform)
val out = IO(UInt(8.W))
val in = IO(UInt(8.W))
out := in
}

generateFirrtlAndFileCheck(new ModuleWithoutChoice)(
"""|CHECK: option Platform :
|CHECK-NEXT: ASIC @[
|CHECK-NEXT: FPGA @[
|""".stripMargin
)
}
}