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

Add enum support #221

Merged
merged 2 commits into from
Dec 10, 2018
Merged
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
26 changes: 14 additions & 12 deletions src/main/scala/chisel3/iotesters/AdvTester.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import java.io.{PrintWriter, StringWriter}
// Provides a template to define advanced tester transactions
trait AdvTests extends PeekPokeTests {
def cycles: Long
def wire_poke(port: Bits, target: BigInt): Unit
def reg_poke(port: Bits, target: BigInt): Unit
def wire_poke[T <: Element: Pokeable](port: T, target: BigInt): Unit
def reg_poke[T <: Element: Pokeable](port: T, target: BigInt): Unit
def takestep(work: => Unit = {}): Unit
def takesteps(n: Int)(work: =>Unit = {}): Unit
def until(pred: =>Boolean, maxCycles: Long = 0L)(work: =>Unit): Boolean
Expand Down Expand Up @@ -42,19 +42,21 @@ abstract class AdvTester[+T <: Module](dut: T,
// This section of code lets testers easily emulate have registers right before dut inputs
// This testing style conforms with the general ASPIRE testbench style
// Also, to ensure difference enforced, poke 'deprecated' and replaced with wire_poke
def wire_poke(port: Bits, target: BigInt) = super.poke(port, target)
def wire_poke[T <: Element: Pokeable](port: T, target: BigInt) = super.poke(port, target)

override def poke(port: Bits, target: BigInt) {
override def poke[T <: Element: Pokeable](port: T, target: BigInt) {
require(false, "poke hidden for AdvTester, use wire_poke or reg_poke")
}

private val registered_bits_updates = new scala.collection.mutable.HashMap[Bits,BigInt]()
private val registered_bits_updates = new scala.collection.mutable.HashMap[Element,BigInt]()
private def do_registered_updates() = {
registered_bits_updates.foreach( kv => wire_poke(kv._1,kv._2) )
registered_bits_updates.foreach{case (key, value) => key match {
case Pokeable(p) => wire_poke(p, value)
}}
registered_bits_updates.clear
}

def reg_poke(port: Bits, target: BigInt) { registered_bits_updates(port) = target }
def reg_poke[T <: Element: Pokeable](port: T, target: BigInt) { registered_bits_updates(port) = target }

// This function replaces step in the advanced tester and makes sure all tester features are clocked in the appropriate order
def takestep(work: => Unit = {}): Unit = {
Expand Down Expand Up @@ -134,7 +136,7 @@ abstract class AdvTester[+T <: Module](dut: T,
}

object IrrevocableSink {
def apply[T<:Bits](socket: ReadyValidIO[T]) =
def apply[T<:Element: Pokeable](socket: ReadyValidIO[T]) =
new IrrevocableSink(socket, (socket_bits: T) => peek(socket_bits))
}

Expand All @@ -145,7 +147,7 @@ abstract class AdvTester[+T <: Module](dut: T,
}

object DecoupledSink {
def apply[T<:Bits](socket: ReadyValidIO[T]) =
def apply[T<:Element: Pokeable](socket: ReadyValidIO[T]) =
new DecoupledSink(socket, (socket_bits: T) => peek(socket_bits))
}

Expand All @@ -164,7 +166,7 @@ abstract class AdvTester[+T <: Module](dut: T,
preprocessors += this
}
object ValidSink {
def apply[T<:Bits](socket: ValidIO[T]) =
def apply[T<:Element: Pokeable](socket: ValidIO[T]) =
new ValidSink(socket, (socket_bits: T) => peek(socket_bits))
}

Expand Down Expand Up @@ -195,7 +197,7 @@ abstract class AdvTester[+T <: Module](dut: T,
postprocessors += this
}
object DecoupledSource {
def apply[T<:Bits](socket: DecoupledIO[T]) =
def apply[T<:Element: Pokeable](socket: DecoupledIO[T]) =
new DecoupledSource(socket, (socket_bits: T, in: BigInt) => reg_poke(socket_bits, in))
}

Expand Down Expand Up @@ -223,7 +225,7 @@ abstract class AdvTester[+T <: Module](dut: T,
postprocessors += this
}
object ValidSource {
def apply[T<:Bits](socket: ValidIO[T]) =
def apply[T<:Element: Pokeable](socket: ValidIO[T]) =
new ValidSource(socket, (socket_bits: T, in: BigInt) => reg_poke(socket_bits, in))
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/chisel3/iotesters/ChiselPokeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ trait ChiselPokeTesterUtils extends Assertions {
// TODO: statically-typed Bundle constructors
// Map-based Bundle expect/pokes currently not supported because those don't compile-time check

def expect(ref: Bits, value: BigInt, msg: String="") {
def expect[T <: Element: Pokeable](ref: T, value: BigInt, msg: String="") {
val actualValue = backend.peek(ref, None)
val postfix = if (msg != "") s": $msg" else ""
assert(actualValue == value, s"(cycle $currCycle: expected ${ref.instanceName} == $value, got $actualValue$postfix)")
}

/** Write a value into the circuit.
*/
def poke(ref: Bits, value: BigInt) {
def poke[T <: Element](ref: T, value: BigInt) {
assert(!ref.isLit, s"(attempted to poke literal ${ref.instanceName})")
backend.poke(ref, value, None)
val verifyVal = backend.peek(ref, None)
Expand Down Expand Up @@ -87,7 +87,7 @@ trait ChiselPokeTesterUtils extends Assertions {
// Dynamic testbenches may be a specialized option later.
/** Internal: read a value into the circuit.
*/
private[iotesters] def peek(ref: Bits): BigInt = {
private[iotesters] def peek[T <: Element: Pokeable](ref: T): BigInt = {
backend.peek(ref, None)
}
}
Expand Down Expand Up @@ -129,7 +129,7 @@ trait PokeTester extends ChiselPokeTesterUtils {
trait ImplicitPokeTester extends ChiselPokeTesterUtils {
/** Pokes a value into the circuit.
*/
def poke(ref: Bits, value: BigInt)(implicit t: InnerTester) {
def poke[T <: Element: Pokeable](ref: T, value: BigInt)(implicit t: InnerTester) {
t.poke(ref, value)
}

Expand All @@ -140,12 +140,12 @@ trait ImplicitPokeTester extends ChiselPokeTesterUtils {

// Wrapper for check when no explicit message is passed in.
// Scala doesn't allow multiple overloaded functions with default arguments.
def check(ref: Bits, value: BigInt)(implicit t: InnerTester) {
def check[T <: Element: Pokeable](ref: T, value: BigInt)(implicit t: InnerTester) {
check(ref, value, "")
}
/** Asserts that the node's simulation value is equal to the given value.
*/
def check(ref: Bits, value: BigInt, msg: String)(implicit t: InnerTester) {
def check[T <: Element: Pokeable](ref: T, value: BigInt, msg: String)(implicit t: InnerTester) {
t.expect(ref, value, msg)
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/chisel3/iotesters/FirrtlTerpBackend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private[iotesters] class FirrtlTerpBackend(
def poke(signal: InstanceId, value: BigInt, off: Option[Int])
(implicit logger: TestErrorLog, verbose: Boolean, base: Int): Unit = {
signal match {
case port: Bits =>
case port: Element =>
val name = portNames(port)
interpretiveTester.poke(name, value)
if (verbose) logger info s" POKE $name <- ${bigIntToStr(value, base)}"
Expand All @@ -45,7 +45,7 @@ private[iotesters] class FirrtlTerpBackend(
def peek(signal: InstanceId, off: Option[Int])
(implicit logger: TestErrorLog, verbose: Boolean, base: Int): BigInt = {
signal match {
case port: Bits =>
case port: Element =>
val name = portNames(port)
val result = interpretiveTester.peek(name)
if (verbose) logger info s" PEEK $name -> ${bigIntToStr(result, base)}"
Expand All @@ -63,7 +63,7 @@ private[iotesters] class FirrtlTerpBackend(
def expect(signal: InstanceId, expected: BigInt, msg: => String)
(implicit logger: TestErrorLog, verbose: Boolean, base: Int) : Boolean = {
signal match {
case port: Bits =>
case port: Element =>
val name = portNames(port)
val got = interpretiveTester.peek(name)
val good = got == expected
Expand Down
94 changes: 57 additions & 37 deletions src/main/scala/chisel3/iotesters/PeekPokeTester.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ trait PeekPokeTests {
implicit def int(x: Boolean): BigInt
implicit def int(x: Int): BigInt
implicit def int(x: Long): BigInt
implicit def int(x: Bits): BigInt
implicit def int[T <: Element: Pokeable](x: T): BigInt
def println(msg: String = ""): Unit
def reset(n: Int): Unit
def step(n: Int): Unit
def poke(path: String, x: BigInt): Unit
def peek(path: String): BigInt
def poke(signal: Bits, x: BigInt): Unit
def pokeAt[T <: Bits](signal: Mem[T], x: BigInt, off: Int): Unit
def peek(signal: Bits): BigInt
def peekAt[T <: Bits](signal: Mem[T], off: Int): BigInt
def poke[T <: Element: Pokeable](signal: T, x: BigInt): Unit
def pokeAt[T <: Element: Pokeable](signal: Mem[T], x: BigInt, off: Int): Unit
def peek[T <: Element: Pokeable](signal: T): BigInt
def peekAt[T <: Element: Pokeable](signal: Mem[T], off: Int): BigInt
def expect(good: Boolean, msg: => String): Boolean
def expect(signal: Bits, expected: BigInt, msg: => String = ""): Boolean
def expect[T <: Element: Pokeable](signal: T, expected: BigInt, msg: => String = ""): Boolean
def finish: Boolean
}

Expand All @@ -46,7 +46,7 @@ object PeekPokeTester {
signal match {
case elt: Aggregate => elt.getElements.toIndexedSeq flatMap {extractElementBits(_)}
case elt: Element => IndexedSeq(elt)
case elt => throw new Exception(s"Cannot extractElementBits for type ${elt.getClass}")
case elt => throw new Exception(s"Cannot extractElementBits for type ${elt.getClass.getName}")
}
}
}
Expand Down Expand Up @@ -95,8 +95,8 @@ abstract class PeekPokeTester[+T <: MultiIOModule](

/** Convert a Boolean to BigInt */
implicit def int(x: Boolean): BigInt = if (x) 1 else 0
/** Convert Bits to BigInt */
implicit def int(x: Bits): BigInt = x.litValue()
/** Convert Pokeables to BigInt */
implicit def int[T <: Element: Pokeable](x: T): BigInt = x.litValue()

/**
* Convert an Int to unsigned (effectively 32-bit) BigInt
Expand Down Expand Up @@ -135,16 +135,16 @@ abstract class PeekPokeTester[+T <: MultiIOModule](

def peek(path: String) = backend.peek(path)

def poke(signal: Bits, value: BigInt): Unit = {
def poke[T <: Element: Pokeable](signal: T, value: BigInt): Unit = {
if (!signal.isLit) backend.poke(signal, value, None)
// TODO: Warn if signal.isLit
}

def poke(signal: Bits, value: Int) {
def poke[T <: Element: Pokeable](signal: T, value: Int) {
poke(signal, BigInt(value))
}

def poke(signal: Bits, value: Long) {
def poke[T <: Element: Pokeable](signal: T, value: Long) {
poke(signal, BigInt(value))
}

Expand All @@ -156,13 +156,13 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
/** Locate a specific bundle element, given a name path.
* TODO: Handle Vecs
*
* @param path - list of element names (presumably bundles) terminating in a non-bundle (i.e., Bits) element.
* @param path - js (presumably bundles) terminating in a non-bundle (e.g., Bits) element.
* @param bundle - bundle containing the element
* @return the element (as Bits)
* @return the element (as Element)
*/
private def getBundleElement(path: List[String], bundle: ListMap[String, Data]): Bits = {
private def getBundleElement(path: List[String], bundle: ListMap[String, Data]): Element = {
(path, bundle(path.head)) match {
case (head :: Nil, element: Bits) => element
case (head :: Nil, element: Element) => element
case (head :: tail, b: Bundle) => getBundleElement(tail, b.elements)
case _ => throw new Exception(s"peek/poke bundle element mismatch $path")
}
Expand All @@ -178,19 +178,27 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
for ( (key, value) <- map) {
val subKeys = key.split('.').toList
val element = getBundleElement(subKeys, circuitElements)
poke(element, value)
element match {
case Pokeable(e) => poke(e, value)
case _ => throw new Exception(s"Cannot poke type ${element.getClass.getName}")
}
}
}

def poke(signal: Aggregate, value: IndexedSeq[BigInt]): Unit = {
(extractElementBits(signal) zip value.reverse).foreach(x => poke(x._1.asInstanceOf[Bits], x._2))
(extractElementBits(signal) zip value.reverse).foreach{ case (elem, value) =>
elem match {
case Pokeable(e) => poke(e, value)
case _ => throw new Exception(s"Cannot poke type ${elem.getClass.getName}")
}
}
}

def pokeAt[TT <: Bits](data: Mem[TT], value: BigInt, off: Int): Unit = {
def pokeAt[TT <: Element: Pokeable](data: Mem[TT], value: BigInt, off: Int): Unit = {
backend.poke(data, value, Some(off))
}

def peek(signal: Bits):BigInt = {
def peek[T <: Element: Pokeable](signal: T):BigInt = {
if (!signal.isLit) backend.peek(signal, None) else signal.litValue()
}

Expand All @@ -203,27 +211,27 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
}

def peek(signal: Aggregate): Seq[BigInt] = {
extractElementBits(signal) map (x => backend.peek(x.asInstanceOf[Bits], None))
extractElementBits(signal) map (x => backend.peek(x.asInstanceOf[Element], None))
}

/** Populate a map of names ("dotted Bundles) to Bits.
/** Populate a map of names ("dotted Bundles) to Elements.
* TODO: Deal with Vecs
*
* @param map the map to be constructed
* @param indexPrefix an array of Bundle name prefixes
* @param signalName the signal to be added to the map
* @param signalData the signal object to be added to the map
*/
private def setBundleElement(map: mutable.LinkedHashMap[String, Bits], indexPrefix: ArrayBuffer[String], signalName: String, signalData: Data): Unit = {
private def setBundleElement(map: mutable.LinkedHashMap[String, Element], indexPrefix: ArrayBuffer[String], signalName: String, signalData: Data): Unit = {
indexPrefix += signalName
signalData match {
case bundle: Bundle =>
for ((name, value) <- bundle.elements) {
setBundleElement(map, indexPrefix, name, value)
}
case bits: Bits =>
case elem: Element =>
val index = indexPrefix.mkString(".")
map(index) = bits
map(index) = elem
}
indexPrefix.remove(indexPrefix.size - 1)
}
Expand All @@ -234,20 +242,22 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
* @return a map of signal names ("dotted" Bundle) to BigInt values.
*/
def peek(signal: Bundle): mutable.LinkedHashMap[String, BigInt] = {
val bitsMap = mutable.LinkedHashMap[String, Bits]()
val elemMap = mutable.LinkedHashMap[String, Element]()
val index = ArrayBuffer[String]()
// Populate the Bits map.
// Populate the Element map.
for ((elementName, elementValue) <- signal.elements) {
setBundleElement(bitsMap, index, elementName, elementValue)
setBundleElement(elemMap, index, elementName, elementValue)
}
val bigIntMap = mutable.LinkedHashMap[String, BigInt]()
for ((name, bits) <- bitsMap) {
bigIntMap(name) = peek(bits)
elemMap.foreach {
case (name, Pokeable(e)) => bigIntMap(name) = peek(e)
case default => throw new Exception(s"Cannot peek type ${default.getClass.getName}")
}

bigIntMap
}

def peekAt[TT <: Bits](data: Mem[TT], off: Int): BigInt = {
def peekAt[TT <: Element: Pokeable](data: Mem[TT], off: Int): BigInt = {
backend.peek(data, Some(off))
}

Expand All @@ -257,15 +267,15 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
good
}

def expect(signal: Bits, expected: BigInt, msg: => String = ""): Boolean = {
def expect[T <: Element: Pokeable](signal: T, expected: BigInt, msg: => String = ""): Boolean = {
if (!signal.isLit) {
val good = backend.expect(signal, expected, msg)
if (!good) fail
good
} else expect(signal.litValue() == expected, s"${signal.litValue()} == $expected")
}

def expect(signal: Bits, expected: Int, msg: => String): Boolean = {
def expect[T <: Element: Pokeable](signal: T, expected: Int, msg: => String): Boolean = {
expect(signal, BigInt(expected), msg)
}

Expand All @@ -276,7 +286,12 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
}

def expect (signal: Aggregate, expected: IndexedSeq[BigInt]): Boolean = {
(extractElementBits(signal), expected.reverse).zipped.foldLeft(true) { (result, x) => result && expect(x._1.asInstanceOf[Bits], x._2)}
(extractElementBits(signal), expected.reverse).zipped.forall { case (elem, value) =>
elem match {
case Pokeable(e) => expect(e, value)
case default => throw new Exception(s"Cannot expect type ${default.getClass.getName}")
}
}
}

/** Return true or false if an aggregate signal (Bundle) matches the expected map of values.
Expand All @@ -287,12 +302,17 @@ abstract class PeekPokeTester[+T <: MultiIOModule](
* @return true if the specified values match, false otherwise.
*/
def expect (signal: Bundle, expected: Map[String, BigInt]): Boolean = {
val bitsMap = mutable.LinkedHashMap[String, Bits]()
val elemMap = mutable.LinkedHashMap[String, Element]()
val index = ArrayBuffer[String]()
for ((elementName, elementValue) <- signal.elements) {
setBundleElement(bitsMap, index, elementName, elementValue)
setBundleElement(elemMap, index, elementName, elementValue)
}
expected.forall { case (name, value) =>
elemMap(name) match {
case Pokeable(e) => expect(e, value)
case default => throw new Exception(s"Cannot expect type ${default.getClass.getName}")
}
}
expected.forall{ case ((name, value)) => expect(bitsMap(name), value) }
}

def finish: Boolean = {
Expand Down
Loading