Skip to content

Commit

Permalink
Add isOneOf method to ChiselEnum (#1966)
Browse files Browse the repository at this point in the history
* Add @ekiwi's code as a starting point

* Add test for ChiselEnum isOneOf method

* Make isOneOfTester naming consistent with other testers

* Add scaladoc comments for isOneOf

* Add isOneOf tests that use the method that takes variable number of args

* Add guide level documentation example for isOneOf
  • Loading branch information
chiplet authored Jul 8, 2021
1 parent f1e3790 commit bb520b8
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
18 changes: 18 additions & 0 deletions core/src/main/scala/chisel3/StrongEnum.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,24 @@ abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolea
}
}

/** Test if this enumeration is equal to any of the values in a given sequence
*
* @param s a [[scala.collection.Seq$ Seq]] of enumeration values to look for
* @return a hardware [[Bool]] that indicates if this value matches any of the given values
*/
final def isOneOf(s: Seq[EnumType])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
VecInit(s.map(this === _)).asUInt().orR()
}

/** Test if this enumeration is equal to any of the values given as arguments
*
* @param u1 the first value to look for
* @param u2 zero or more additional values to look for
* @return a hardware [[Bool]] that indicates if this value matches any of the given values
*/
final def isOneOf(u1: EnumType, u2: EnumType*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
= isOneOf(u1 +: u2.toSeq)

def next(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
if (litOption.isDefined) {
val index = factory.all.indexOf(this)
Expand Down
19 changes: 19 additions & 0 deletions docs/src/explanations/chisel-enum.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,25 @@ def expectedSel(sel: AluMux1Sel.Type): Boolean = sel match {
}
```

The enum value type also defines some convenience methods for working with `ChiselEnum` values. For example, continuing with the RISC-V opcode
example, one could easily create hardware signal that is only asserted on LOAD/STORE operations (when the enum value is equal to `Opcode.load`
or `Opcode.store`) using the `.isOneOf` method:

```scala mdoc
class LoadStoreExample extends Module {
val io = IO(new Bundle {
val opcode = Input(Opcode())
val load_or_store = Output(Bool())
})
io.load_or_store := io.opcode.isOneOf(Opcode.load, Opcode.store)
}
```

```scala mdoc:invisible
// Always need to run Chisel to see if there are elaboration errors
ChiselStage.emitVerilog(new LoadStoreExample)
```

Some additional useful methods defined on the `ChiselEnum` object are:

* `.all`: returns the enum values within the enumeration
Expand Down
39 changes: 39 additions & 0 deletions src/test/scala/chiselTests/StrongEnum.scala
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,41 @@ class StrongEnumFSMTester extends BasicTester {
}
}

class IsOneOfTester extends BasicTester {
import EnumExample._

// is one of itself
assert(e0.isOneOf(e0))

// is one of Seq of itself
assert(e0.isOneOf(Seq(e0)))
assert(e0.isOneOf(Seq(e0, e0, e0, e0)))
assert(e0.isOneOf(e0, e0, e0, e0))

// is one of Seq of multiple elements
val subset = Seq(e0, e1, e2)
assert(e0.isOneOf(subset))
assert(e1.isOneOf(subset))
assert(e2.isOneOf(subset))

// is not element not in subset
assert(!e100.isOneOf(subset))
assert(!e101.isOneOf(subset))

// test multiple elements with variable number of arguments
assert(e0.isOneOf(e0, e1, e2))
assert(e1.isOneOf(e0, e1, e2))
assert(e2.isOneOf(e0, e1, e2))
assert(!e100.isOneOf(e0, e1, e2))
assert(!e101.isOneOf(e0, e1, e2))

// is not another value
assert(!e0.isOneOf(e1))
assert(!e2.isOneOf(e101))

stop()
}

class StrongEnumSpec extends ChiselFlatSpec with Utils {
import chisel3.internal.ChiselException

Expand Down Expand Up @@ -474,6 +509,10 @@ class StrongEnumSpec extends ChiselFlatSpec with Utils {
val (log, _) = grabLog(ChiselStage.elaborate(new MyModule))
log should not include ("warn")
}

it should "correctly check if the enumeration is one of the values in a given sequence" in {
assertTesterPasses(new IsOneOfTester)
}
}

class StrongEnumAnnotator extends Module {
Expand Down

0 comments on commit bb520b8

Please sign in to comment.