Skip to content

Commit dbb9393

Browse files
committed
reorganize + cleanup code and tests
1 parent fd65700 commit dbb9393

File tree

3 files changed

+198
-97
lines changed

3 files changed

+198
-97
lines changed

src/main/scala/chisel3/simulator/PeekPokeAPI.scala

+59-46
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ trait Peekable[T <: Data] {
4848
def expect(expected: T)(implicit sourceInfo: SourceInfo): Unit =
4949
expect(expected, (observed, expected) => s"Expectation failed: observed value $observed != $expected")
5050

51-
private[simulator] final def dataToString(data: Data): String = {
52-
data match {
51+
private[simulator] def dataToString(value: Data): String = {
52+
value match {
5353
case x: Bundle =>
5454
x.elements.map { case (name, elt) =>
5555
s"$name: ${dataToString(elt)}"
5656
}.mkString("{", ", ", "}")
5757
case x: Vec[_] => x.getElements.map(dataToString).mkString("[", ", ", "]")
5858
case x: EnumType => x.toString
5959
case x if x.isLit => x.litValue.toString
60-
case _ => data.toString
60+
case _ => value.toString
6161
}
6262
}
6363
}
@@ -75,9 +75,9 @@ trait Pokable[T <: Data] {
7575
sealed trait AnyTestableData[T <: Data] {
7676
protected def data: T
7777

78-
protected def simulatedModule = AnySimulatedModule.current
78+
protected def simulatedModule: AnySimulatedModule = AnySimulatedModule.current
7979

80-
protected def simulationPort = simulatedModule.port(data)
80+
protected def simulationPort: Simulation.Port = simulatedModule.port(data)
8181
}
8282

8383
trait PeekPokable[T <: Data] extends Peekable[T] with Pokable[T] with AnyTestableData[T]
@@ -305,8 +305,6 @@ object PeekPokeAPI {
305305
}
306306
}
307307

308-
def poke(value: Boolean): Unit = poke(value.B)
309-
310308
def peekBoolean(): Boolean = peek().litToBoolean
311309

312310
override def expect(expected: Bool)(implicit sourceInfo: SourceInfo): Unit = expect[Bool](
@@ -318,12 +316,14 @@ object PeekPokeAPI {
318316
)
319317

320318
def expect(value: Boolean)(implicit sourceInfo: SourceInfo): Unit = expect(value.B)
321-
}
322319

323-
implicit final class TestableReset(val data: Reset) extends TestableElement[Reset] {
324320
def poke(value: Boolean): Unit = poke(value.B)
321+
}
325322

323+
implicit final class TestableReset(val data: Reset) extends TestableElement[Reset] {
326324
def encode(width: Int, value: BigInt): Reset = TestableBool(data.asBool).encode(width, value)
325+
326+
def poke(value: Boolean): Unit = poke(value.B)
327327
}
328328

329329
implicit class TestableEnum[T <: EnumType](val data: T) extends TestableElement[T] {
@@ -333,7 +333,6 @@ object PeekPokeAPI {
333333
}
334334

335335
implicit class TestableRecord[T <: Record](val data: T) extends PeekPokable[T] {
336-
337336
override def peek(): T = {
338337
chiselTypeOf(data).Lit(
339338
data.elements.toSeq.map { case (name: String, elt: Data) =>
@@ -342,22 +341,15 @@ object PeekPokeAPI {
342341
)
343342
}
344343

345-
override def poke(value: T): Unit = data.elements.foreach { case (name, d) =>
346-
val valueEl = value.elements(name)
347-
require(
348-
d.getClass == valueEl.getClass,
349-
s"Type mismatch for Record element '$name': expected ${d.getClass}, got ${valueEl.getClass}"
350-
)
351-
d.poke(valueEl)
352-
}
353-
354344
def expect(expected: T, buildMessage: (T, T, String) => String, allowPartial: Boolean)(
355345
implicit sourceInfo: SourceInfo
356346
): Unit = {
357347
require(DataMirror.checkTypeEquivalence(data, expected), "Type mismatch")
358348

359-
// FIXME: I can't understand why but _not_ getting the peeked value as a `val` beforehand results in infinite recursion
360-
val peekedValue = peek()
349+
// Not peeking the value beforehand or using `def` or `lazy val` results in a mysterious infinite recursion and StackOverflowError
350+
// The value is not used if the expected value matches and incurs an overhead
351+
// TODO: dig deeper amd see if we can avoid this
352+
val peekedValue = data.peek()
361353

362354
data.elements.foreach { case (elName, elData) =>
363355
expected.elements(elName) match {
@@ -398,6 +390,15 @@ object PeekPokeAPI {
398390

399391
override def expect(expected: T)(implicit sourceInfo: SourceInfo): Unit =
400392
expect(expected, (obs: T, exp: T) => "", allowPartial = false)
393+
394+
override def poke(literal: T): Unit = data.elements.foreach { case (name, dataEl) =>
395+
val valueEl = literal.elements(name)
396+
require(
397+
dataEl.getClass == valueEl.getClass,
398+
s"Type mismatch for Record element '$name': expected ${dataEl.getClass}, got ${valueEl.getClass}"
399+
)
400+
dataEl.poke(valueEl)
401+
}
401402
}
402403

403404
implicit class TestableVec[T <: Data](val data: Vec[T]) extends PeekPokable[Vec[T]] {
@@ -406,21 +407,6 @@ object PeekPokeAPI {
406407
chiselTypeOf(data).Lit(elementValues.zipWithIndex.map { _.swap }: _*)
407408
}
408409

409-
// internal
410-
private[simulator] final def _poke[U <: Data](literal: Seq[U]): Unit = {
411-
require(data.length == literal.length, s"Vec length mismatch: expected ${data.length}, got ${literal.length}")
412-
data.getElements.zip(literal).foreach {
413-
case (portEl, valueEl) if portEl.getClass == valueEl.getClass =>
414-
portEl.poke(valueEl)
415-
case (portEl, valueEl) =>
416-
throw new Exception(
417-
s"Port element type: ${portEl.getClass} != literal element ${valueEl.getClass}"
418-
)
419-
}
420-
}
421-
422-
override def poke(literal: Vec[T]): Unit = _poke[T](literal)
423-
424410
// internal
425411
private[simulator] final def _expect[U <: Data](expected: Vec[U], buildMessage: (Vec[T], Vec[U], Int) => String)(
426412
implicit sourceInfo: SourceInfo
@@ -429,7 +415,12 @@ object PeekPokeAPI {
429415
expected.length == data.length,
430416
s"Vec length mismatch: Data port has ${data.length} elements while the expected value is of length ${expected.length}"
431417
)
418+
419+
// Not peeking the value beforehand or using `def` or `lazy val` results in a mysterious infinite recursion and StackOverflowError
420+
// The value is not used if the expected value matches and incurs an overhead
421+
// TODO: dig deeper amd see if we can avoid this
432422
val peekedValue = data.peek()
423+
433424
data.zip(expected).zipWithIndex.foreach { case ((datEl, expEl), index) =>
434425
expEl match {
435426
case DontCare =>
@@ -447,14 +438,42 @@ object PeekPokeAPI {
447438
}
448439
}
449440

441+
private[simulator] def _expect[U <: Data](
442+
expected: Vec[U],
443+
buildMessage: (Vec[T], Vec[U]) => String,
444+
appendFailedIndexToMsg: Boolean
445+
)(
446+
implicit sourceInfo: SourceInfo
447+
): Unit =
448+
_expect[U](
449+
expected,
450+
(observed: Vec[T], expected: Vec[U], idx: Int) =>
451+
buildMessage(observed, expected) + (if (appendFailedIndexToMsg) s"; First mismatch at index $idx" else "")
452+
)
453+
450454
override def expect(expected: Vec[T], buildMessage: (Vec[T], Vec[T]) => String)(
451455
implicit sourceInfo: SourceInfo
452456
): Unit =
453457
_expect[T](
454458
expected,
455-
(observed: Vec[T], expected: Vec[T], idx: Int) =>
456-
buildMessage(observed, expected) + s". First mismatch at index $idx."
459+
buildMessage,
460+
appendFailedIndexToMsg = true
457461
)
462+
463+
// for internal use
464+
private[simulator] final def _poke[U <: Data](literal: Vec[U]): Unit = {
465+
require(data.length == literal.length, s"Vec length mismatch: expected ${data.length}, got ${literal.length}")
466+
data.getElements.zip(literal).foreach {
467+
case (portEl, valueEl) if portEl.getClass == valueEl.getClass =>
468+
portEl.poke(valueEl)
469+
case (portEl, valueEl) =>
470+
throw new Exception(
471+
s"Port element type: ${portEl.getClass} != literal element ${valueEl.getClass}"
472+
)
473+
}
474+
}
475+
476+
override def poke(literal: Vec[T]): Unit = _poke[T](literal)
458477
}
459478

460479
implicit class TestableData[T <: Data](val data: T) extends PeekPokable[T] {
@@ -493,14 +512,8 @@ object PeekPokeAPI {
493512
case (dat: Record, exp: Record) =>
494513
new TestableRecord(dat).expect(exp, buildMsgFn _)
495514
case (dat: Vec[_], exp: Vec[_]) =>
496-
new TestableVec(dat)._expect(
497-
exp,
498-
(obs: Vec[_], _: Vec[_], idx: Int) => {
499-
require(obs.getClass == exp.getClass, s"Type mismatch: ${obs.getClass} != ${exp.getClass}")
500-
buildMessage(obs.asInstanceOf[T], expected.asInstanceOf[T]) + s". First mismatch at index $idx."
501-
}
502-
)
503-
case x => throw new Exception(s"don't know how to expect $x")
515+
new TestableVec(dat)._expect(exp, buildMsgFn _, appendFailedIndexToMsg = true)
516+
case x => throw new Exception(s"Don't know how to expect $x")
504517
}
505518
}
506519

0 commit comments

Comments
 (0)