From 6d035af5b8638f3eed9f6cca4de3ce4cfba26c77 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Wed, 17 Jul 2024 19:46:09 +0200 Subject: [PATCH 01/29] Add methods to check stream compatibility. Tiny bit of refactoring. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 168 ++++++++++++++---- 1 file changed, 130 insertions(+), 38 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index d321c22..3c86c9f 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -2,13 +2,14 @@ package nl.tudelft.tydi_chisel import scala.collection.mutable import scala.collection.mutable.ListBuffer - import chisel3._ import chisel3.experimental.{BaseModule, ExtModule} -import chisel3.util.{log2Ceil, Cat} +import chisel3.util.{Cat, log2Ceil} import nl.tudelft.tydi_chisel.ReverseTranspiler._ import nl.tudelft.tydi_chisel.utils.ComplexityConverter +import scala.reflect.runtime.universe._ + trait TranspileExtend { /** @@ -198,6 +199,14 @@ object BitsEl { def apply(width: Width): BitsEl = new BitsEl(width) } +object CompatCheck extends Enumeration { + type CompatCheckType = Value + val Params, Strict = Value +} + +final case class TydiStreamCompatException(private val message: String = "", private val cause: Throwable = None.orNull) + extends Exception(message, cause) + /** * Physical stream signal definitions. * @param e Element type @@ -209,6 +218,8 @@ object BitsEl { abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, val c: Int, private val u: Data) extends TydiEl { override val isStream: Boolean = true + override val elWidth: Int = e.getDataElementsRec.map(_.getWidth).sum + val userElWidth: Int = u.getWidth require(n >= 1) require(1 <= c && c <= 8) @@ -320,6 +331,40 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, /** [[strb]] signal as a boolean vector */ def strbVec: Vec[Bool] = VecInit(strb.asBools) + /** + * Check if the parameters of a source and sink stream match. + * @param toConnect Source stream to drive this stream with. + */ + def paramCheck(toConnect: PhysicalStreamBase): Unit = { + // Number of lanes should be the same + if (toConnect.n != this.n) { + throw TydiStreamCompatException("Number of lanes between source and sink is not equal") + } + // Dimensionality should be the same + if (toConnect.d != this.d) { + throw TydiStreamCompatException("Dimensionality of source and sink is not equal") + } + // Sink C >= source C for compatibility + if (toConnect.c > this.c) { + throw TydiStreamCompatException("Complexity of source stream > sink") + } + } + + /** + * Meta-connect function. Connects all metadata signals but not the data or user signals. + * @param bundle Source stream to drive this stream with. + */ + def :~=(bundle: PhysicalStreamBase): Unit = { + paramCheck(bundle) + // This could be done with a :<>= but I like being explicit here to catch possible errors. + this.endi := bundle.endi + this.stai := bundle.stai + this.strb := bundle.strb + this.last := bundle.last.asUInt + this.valid := bundle.valid + bundle.ready := this.ready + } + def tydiCode: String = { val elName = e.fingerprint val usName = u.fingerprint @@ -357,11 +402,9 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, */ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 0, c: Int, private val u: Data = Null()) extends PhysicalStreamBase(e, n, d, c, u) { - override val elWidth: Int = e.getDataElementsRec.map(_.getWidth).sum - val userElWidth: Int = u.getWidth - val data: UInt = Output(UInt((elWidth * n).W)) - val user: UInt = Output(UInt(userElWidth.W)) - val last: UInt = Output(UInt(lastWidth.W)) + val data: UInt = Output(UInt((elWidth * n).W)) + val user: UInt = Output(UInt(userElWidth.W)) + val last: UInt = Output(UInt(lastWidth.W)) def lastVec: Vec[UInt] = { if (d > 0) @@ -370,15 +413,24 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 0, c: Int, priv VecInit.tabulate(n)(i => 0.U(0.W)) } - // Stream mounting function + def elementCheck(toConnect: PhysicalStreamBase): Unit = { + if (this.elWidth != toConnect.elWidth) { + throw TydiStreamCompatException("Size of stream elements is not equal") + } + if (this.userElWidth != toConnect.userElWidth) { + throw TydiStreamCompatException("Size of stream elements is not equal") + } + } + + /** + * Stream mounting function. + * @param bundle Source stream to drive this stream with. + * @tparam Tel Element signal type. + * @tparam Tus User signal type. + */ def :=[Tel <: TydiEl, Tus <: Data](bundle: PhysicalStreamDetailed[Tel, Tus]): Unit = { - // This could be done with a :<>= but I like being explicit here to catch possible errors. - this.endi := bundle.endi - this.stai := bundle.stai - this.strb := bundle.strb - this.last := bundle.last.asUInt - this.valid := bundle.valid - bundle.ready := this.ready + this :~= bundle + elementCheck(bundle) if (elWidth > 0) { this.data := bundle.getDataConcat } else { @@ -391,16 +443,15 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 0, c: Int, priv } } + /** + * Stream mounting function. + * @param bundle Source stream to drive this stream with. + */ def :=(bundle: PhysicalStream): Unit = { - // This could be done with a :<>= but I like being explicit here to catch possible errors. - this.endi := bundle.endi - this.stai := bundle.stai - this.strb := bundle.strb - this.last := bundle.last - this.valid := bundle.valid - bundle.ready := this.ready - this.data := bundle.data - this.user := bundle.user + this :~= bundle + elementCheck(bundle) + this.data := bundle.data + this.user := bundle.user } def processWith[T <: SubProcessorSignalDef](module: => T)(implicit parentModule: TydiModuleMixin): PhysicalStream = { @@ -520,16 +571,45 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( io } - // Stream mounting function - def :=[TBel <: TydiEl, TBus <: Data](bundle: PhysicalStreamDetailed[TBel, TBus]): Unit = { + def elementCheck[TBel <: TydiEl: TypeTag, TBus <: Data: TypeTag]( + toConnect: PhysicalStreamDetailed[TBel, TBus] + ): Unit = { + /*if (!(typeOf[TBel] =:= typeOf[Tel])) { + throw TydiStreamCompatException("Type of stream elements is not equal") + } + if (!(typeOf[TBus] =:= typeOf[Tus])) { + throw TydiStreamCompatException("Type of user elements is not equal") + }*/ + /*if (this.data(0).typeName != toConnect.data(0).typeName) { + throw TydiStreamCompatException("Type of stream elements is not equal") + }*/ + /*if (this.user.typeName != toConnect.user.typeName) { + throw TydiStreamCompatException("Type of user elements is not equal") + }*/ + } + + def elementCheck2[TAel <: TydiEl: TypeTag, TAus <: Data: TypeTag, TBel <: TydiEl: TypeTag, TBus <: Data: TypeTag]( + a: PhysicalStreamDetailed[TAel, TAus], + toConnect: PhysicalStreamDetailed[TBel, TBus] + ): Unit = { + if (!(typeOf[TBel] =:= typeOf[TAel])) { + throw TydiStreamCompatException("Type of stream elements is not equal") + } + if (!(typeOf[TBus] =:= typeOf[TAus])) { + throw TydiStreamCompatException("Type of user elements is not equal") + } + } + + // Require the element and user signal types to be the same as this stream in the function signature. + /** + * Stream mounting function. + * @param bundle Source stream to drive this stream with. + */ + def :=(bundle: PhysicalStreamDetailed[Tel, Tus]): Unit = { + elementCheck2(this, bundle) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { - this.endi := bundle.endi - this.stai := bundle.stai - this.strb := bundle.strb - this.last := bundle.last - this.valid := bundle.valid - bundle.ready := this.ready + this :~= bundle // The following would work if we would know with certainty that the signals are oriented the right way, // but we do not -.- // (this.data: Data) :<>= (bundle.data: Data) @@ -547,12 +627,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( } (this.user: Data) :<>= (bundle.user: Data) } else { - bundle.endi := this.endi - bundle.stai := this.stai - bundle.strb := this.strb - bundle.last := this.last - bundle.valid := this.valid - this.ready := bundle.ready + bundle :~= this // The following would work if we would know with certainty that the signals are oriented the right way, // but we do not -.- // (bundle.data: Data) :<>= (this.data: Data) @@ -572,7 +647,24 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( } } +// /** +// * @deprecated It seems your element and user types do not match up! +// * @param bundle Source stream to drive this stream with. +// * @tparam TBel Element signal type. +// * @tparam TBus User signal type. +// */ +// def :=[TBel <: TydiEl, TBus <: Data](bundle: PhysicalStreamDetailed[TBel, TBus]): Unit = { +// throw TydiStreamCompatException("Stream or user element types do not match up") +// } + + /** + * Stream mounting function. + * @param bundle Source stream to drive this stream with. + */ def :=(bundle: PhysicalStream): Unit = { + paramCheck(bundle) + bundle.elementCheck(this) + // We cannot use the :~= function here since the last vector must be driven by the bitvector this.endi := bundle.endi this.stai := bundle.stai this.strb := bundle.strb From aa4b319ada875af86b75b745773b092095050201 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Fri, 26 Jul 2024 13:02:06 +0200 Subject: [PATCH 02/29] Improve stream compatibility checking. Type tags are generally not available, unless implemented everywhere in the toolchain. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 69 +++++++------------ 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 3c86c9f..7264019 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -350,6 +350,15 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, } } + def elementCheck(toConnect: PhysicalStreamBase): Unit = { + if (this.elWidth != toConnect.elWidth) { + throw TydiStreamCompatException("Size of stream elements is not equal") + } + if (this.userElWidth != toConnect.userElWidth) { + throw TydiStreamCompatException("Size of stream elements is not equal") + } + } + /** * Meta-connect function. Connects all metadata signals but not the data or user signals. * @param bundle Source stream to drive this stream with. @@ -413,15 +422,6 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 0, c: Int, priv VecInit.tabulate(n)(i => 0.U(0.W)) } - def elementCheck(toConnect: PhysicalStreamBase): Unit = { - if (this.elWidth != toConnect.elWidth) { - throw TydiStreamCompatException("Size of stream elements is not equal") - } - if (this.userElWidth != toConnect.userElWidth) { - throw TydiStreamCompatException("Size of stream elements is not equal") - } - } - /** * Stream mounting function. * @param bundle Source stream to drive this stream with. @@ -571,32 +571,19 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( io } - def elementCheck[TBel <: TydiEl: TypeTag, TBus <: Data: TypeTag]( - toConnect: PhysicalStreamDetailed[TBel, TBus] - ): Unit = { - /*if (!(typeOf[TBel] =:= typeOf[Tel])) { - throw TydiStreamCompatException("Type of stream elements is not equal") - } - if (!(typeOf[TBus] =:= typeOf[Tus])) { - throw TydiStreamCompatException("Type of user elements is not equal") - }*/ - /*if (this.data(0).typeName != toConnect.data(0).typeName) { - throw TydiStreamCompatException("Type of stream elements is not equal") - }*/ - /*if (this.user.typeName != toConnect.user.typeName) { - throw TydiStreamCompatException("Type of user elements is not equal") - }*/ - } - - def elementCheck2[TAel <: TydiEl: TypeTag, TAus <: Data: TypeTag, TBel <: TydiEl: TypeTag, TBus <: Data: TypeTag]( - a: PhysicalStreamDetailed[TAel, TAus], - toConnect: PhysicalStreamDetailed[TBel, TBus] + def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( + toConnect: PhysicalStreamDetailed[TBel, TBus], + typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict ): Unit = { - if (!(typeOf[TBel] =:= typeOf[TAel])) { - throw TydiStreamCompatException("Type of stream elements is not equal") - } - if (!(typeOf[TBus] =:= typeOf[TAus])) { - throw TydiStreamCompatException("Type of user elements is not equal") + if (typeCheck == CompatCheck.Strict) { + if (this.getDataType.getClass != toConnect.getDataType.getClass) { + throw TydiStreamCompatException("Type of stream elements is not equal") + } + if (this.user.getClass != toConnect.user.getClass) { + throw TydiStreamCompatException("Type of user elements is not equal") + } + } else { + super.elementCheck(toConnect) } } @@ -605,8 +592,8 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStreamDetailed[Tel, Tus]): Unit = { - elementCheck2(this, bundle) + def :=(bundle: PhysicalStreamDetailed[Tel, Tus], typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict): Unit = { + elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { this :~= bundle @@ -647,16 +634,6 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( } } -// /** -// * @deprecated It seems your element and user types do not match up! -// * @param bundle Source stream to drive this stream with. -// * @tparam TBel Element signal type. -// * @tparam TBus User signal type. -// */ -// def :=[TBel <: TydiEl, TBus <: Data](bundle: PhysicalStreamDetailed[TBel, TBus]): Unit = { -// throw TydiStreamCompatException("Stream or user element types do not match up") -// } - /** * Stream mounting function. * @param bundle Source stream to drive this stream with. From 9819111b2b9c224fcadb6f408a85f41a8c1c7c32 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Fri, 26 Jul 2024 15:44:34 +0200 Subject: [PATCH 03/29] Fix type check argument. Make errors more informative. Fix tests. Default dimensionality is now 1 instead of 0. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 40 +++++++++++++------ .../TimestampedMessage.scala | 4 +- .../utils/ComplexityConverterTest.scala | 2 +- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 7264019..29a00f0 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -2,14 +2,13 @@ package nl.tudelft.tydi_chisel import scala.collection.mutable import scala.collection.mutable.ListBuffer + import chisel3._ import chisel3.experimental.{BaseModule, ExtModule} -import chisel3.util.{Cat, log2Ceil} +import chisel3.util.{log2Ceil, Cat} import nl.tudelft.tydi_chisel.ReverseTranspiler._ import nl.tudelft.tydi_chisel.utils.ComplexityConverter -import scala.reflect.runtime.universe._ - trait TranspileExtend { /** @@ -338,15 +337,21 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, def paramCheck(toConnect: PhysicalStreamBase): Unit = { // Number of lanes should be the same if (toConnect.n != this.n) { - throw TydiStreamCompatException("Number of lanes between source and sink is not equal") + throw TydiStreamCompatException( + s"Number of lanes between source and sink is not equal. ${this.instanceName} has n=${this.n}, ${toConnect} has n=${toConnect.n}" + ) } // Dimensionality should be the same if (toConnect.d != this.d) { - throw TydiStreamCompatException("Dimensionality of source and sink is not equal") + throw TydiStreamCompatException( + s"Dimensionality of source and sink is not equal. ${this.instanceName} has d=${this.d}, ${toConnect} has d=${toConnect.d}" + ) } // Sink C >= source C for compatibility if (toConnect.c > this.c) { - throw TydiStreamCompatException("Complexity of source stream > sink") + throw TydiStreamCompatException( + s"Complexity of source stream > sink. ${this.instanceName} has c=${this.c}, ${toConnect} has c=${toConnect.c}" + ) } } @@ -369,9 +374,18 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, this.endi := bundle.endi this.stai := bundle.stai this.strb := bundle.strb - this.last := bundle.last.asUInt this.valid := bundle.valid bundle.ready := this.ready + + if (this.d > 0) { + (this.last, bundle.last) match { + case (_: UInt, _: UInt) | (_: Vec[_], _: Vec[_]) => this.last := bundle.last + case (_: UInt, _: Vec[_]) => this.last := bundle.last.asUInt + } + } else { + this.last := DontCare + bundle.last := DontCare + } } def tydiCode: String = { @@ -409,7 +423,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, * @param c Complexity * @param u User signals */ -class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 0, c: Int, private val u: Data = Null()) +class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, private val u: Data = Null()) extends PhysicalStreamBase(e, n, d, c, u) { val data: UInt = Output(UInt((elWidth * n).W)) val user: UInt = Output(UInt(userElWidth.W)) @@ -479,7 +493,7 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 0, c: Int, priv } object PhysicalStream { - def apply(e: TydiEl, n: Int = 1, d: Int = 0, c: Int, u: Data = Null()): PhysicalStream = + def apply(e: TydiEl, n: Int = 1, d: Int = 1, c: Int, u: Data = Null()): PhysicalStream = new PhysicalStream(e, n, d, c, u) } @@ -497,7 +511,7 @@ object PhysicalStream { class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( private val e: Tel, n: Int = 1, - d: Int = 0, + d: Int = 1, c: Int, var r: Boolean = false, private val u: Tus = Null() @@ -592,7 +606,9 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStreamDetailed[Tel, Tus], typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict): Unit = { + def :=[TBel <: TydiEl, TBus <: Data]( + bundle: PhysicalStreamDetailed[TBel, TBus] + )(implicit typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { @@ -680,7 +696,7 @@ object PhysicalStreamDetailed { def apply[Tel <: TydiEl, Tus <: Data]( e: Tel, n: Int = 1, - d: Int = 0, + d: Int = 1, c: Int, r: Boolean = false, u: Tus = Null() diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/examples/timestamped_message/TimestampedMessage.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/examples/timestamped_message/TimestampedMessage.scala index c5919b4..943cf76 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/examples/timestamped_message/TimestampedMessage.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/examples/timestamped_message/TimestampedMessage.scala @@ -24,7 +24,7 @@ class TimestampedMessageBundle extends Group { val a: UInt = UInt(8.W) val b: Bool = Bool() }*/ - val message = new PhysicalStreamDetailed(BitsEl(charWidth), n = 3, d = 1, c = 7) + val message = new PhysicalStreamDetailed(BitsEl(charWidth), n = 3, d = 2, c = 7) } // Declaration of the module @@ -67,7 +67,7 @@ class TimestampedMessageModuleOut extends TydiModule { } class TimestampedMessageModuleIn extends TydiModule { - val io1 = IO(Flipped(new PhysicalStream(new TimestampedMessageBundle, n = 1, d = 2, c = 7, u = new Null()))) + val io1 = IO(Flipped(new PhysicalStream(new TimestampedMessageBundle, n = 1, d = 1, c = 7, u = new Null()))) val io2 = IO(Flipped(new PhysicalStream(BitsEl(8.W), n = 3, d = 2, c = 7, u = new Null()))) io1 :<= DontCare io1.ready := DontCare diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/utils/ComplexityConverterTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/utils/ComplexityConverterTest.scala index ff6ca09..a935f06 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/utils/ComplexityConverterTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/utils/ComplexityConverterTest.scala @@ -200,7 +200,7 @@ class ComplexityConverterTest extends AnyFlatSpec with ChiselScalatestTester { } it should "work with fancy wrapper" in { - val stream = PhysicalStream(new MyEl, n = 1, d = 1, c = 7) + val stream = PhysicalStream(new MyEl, n = 1, d = 1, c = 8) // test case body here test(new ManualComplexityConverterFancyWrapper(new MyEl, stream, 10)) { c => From 77898bc31d3f1f6fc1277dbcb9ea2c582524ca5a Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Sun, 28 Jul 2024 14:29:53 +0200 Subject: [PATCH 04/29] Improve error strings more. --- .../scala/nl/tudelft/tydi_chisel/TydiLib.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 29a00f0..e5ec0d4 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -338,29 +338,29 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, // Number of lanes should be the same if (toConnect.n != this.n) { throw TydiStreamCompatException( - s"Number of lanes between source and sink is not equal. ${this.instanceName} has n=${this.n}, ${toConnect} has n=${toConnect.n}" + s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect.toString()} has n=${toConnect.n}" ) } // Dimensionality should be the same if (toConnect.d != this.d) { throw TydiStreamCompatException( - s"Dimensionality of source and sink is not equal. ${this.instanceName} has d=${this.d}, ${toConnect} has d=${toConnect.d}" + s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}" ) } // Sink C >= source C for compatibility if (toConnect.c > this.c) { throw TydiStreamCompatException( - s"Complexity of source stream > sink. ${this.instanceName} has c=${this.c}, ${toConnect} has c=${toConnect.c}" + s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}" ) } } def elementCheck(toConnect: PhysicalStreamBase): Unit = { if (this.elWidth != toConnect.elWidth) { - throw TydiStreamCompatException("Size of stream elements is not equal") + throw TydiStreamCompatException(s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}") } if (this.userElWidth != toConnect.userElWidth) { - throw TydiStreamCompatException("Size of stream elements is not equal") + throw TydiStreamCompatException(s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}") } } @@ -591,10 +591,10 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { - throw TydiStreamCompatException("Type of stream elements is not equal") + throw TydiStreamCompatException(s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}") } if (this.user.getClass != toConnect.user.getClass) { - throw TydiStreamCompatException("Type of user elements is not equal") + throw TydiStreamCompatException(s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}") } } else { super.elementCheck(toConnect) From 81397bfbe3e94a7abb856531ffcb2042c644bfc7 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Sun, 28 Jul 2024 14:41:03 +0200 Subject: [PATCH 05/29] Make option to print warnings instead of throwing errors for compat problems. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 71 +++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index e5ec0d4..acdaa6f 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -203,6 +203,11 @@ object CompatCheck extends Enumeration { val Params, Strict = Value } +object CompatCheckResult extends Enumeration { + type Type = Value + val Warning, Error = Value +} + final case class TydiStreamCompatException(private val message: String = "", private val cause: Throwable = None.orNull) extends Exception(message, cause) @@ -330,37 +335,70 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, /** [[strb]] signal as a boolean vector */ def strbVec: Vec[Bool] = VecInit(strb.asBools) + protected def printWarning(message: String): Unit = { + // ANSI escape codes for bold and orange text + val bold = "\u001b[1m" + val orange = "\u001b[38;5;214m" + val reset = "\u001b[0m" + + // Print the formatted message + println(s"$bold$orange$message$reset") + } + + protected def reportProblem(problemStr: String, typeCheckResult: CompatCheckResult.Type): Unit = { + typeCheckResult match { + case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) + case CompatCheckResult.Warning => printWarning(problemStr) + } + } + /** * Check if the parameters of a source and sink stream match. * @param toConnect Source stream to drive this stream with. */ - def paramCheck(toConnect: PhysicalStreamBase): Unit = { + def paramCheck( + toConnect: PhysicalStreamBase, + typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error + ): Unit = { // Number of lanes should be the same if (toConnect.n != this.n) { - throw TydiStreamCompatException( - s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect.toString()} has n=${toConnect.n}" + reportProblem( + s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect + .toString()} has n=${toConnect.n}", + typeCheckResult ) } // Dimensionality should be the same if (toConnect.d != this.d) { - throw TydiStreamCompatException( - s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}" + reportProblem( + s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}", + typeCheckResult ) } // Sink C >= source C for compatibility if (toConnect.c > this.c) { - throw TydiStreamCompatException( - s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}" + reportProblem( + s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}", + typeCheckResult ) } } - def elementCheck(toConnect: PhysicalStreamBase): Unit = { + def elementCheck( + toConnect: PhysicalStreamBase, + typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error + ): Unit = { if (this.elWidth != toConnect.elWidth) { - throw TydiStreamCompatException(s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}") + reportProblem( + s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}", + typeCheckResult + ) } if (this.userElWidth != toConnect.userElWidth) { - throw TydiStreamCompatException(s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}") + reportProblem( + s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}", + typeCheckResult + ) } } @@ -587,14 +625,21 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( toConnect: PhysicalStreamDetailed[TBel, TBus], - typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict + typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict, + typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { - throw TydiStreamCompatException(s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}") + reportProblem( + s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}", + typeCheckResult + ) } if (this.user.getClass != toConnect.user.getClass) { - throw TydiStreamCompatException(s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}") + reportProblem( + s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}", + typeCheckResult + ) } } else { super.elementCheck(toConnect) From 0e00a998de7f8a6fcaa6252050054ea16b5b4e02 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Sun, 28 Jul 2024 14:41:25 +0200 Subject: [PATCH 06/29] Use implicit parameters instead. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 44 ++++++------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index acdaa6f..afbca1b 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -345,7 +345,9 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, println(s"$bold$orange$message$reset") } - protected def reportProblem(problemStr: String, typeCheckResult: CompatCheckResult.Type): Unit = { + protected def reportProblem( + problemStr: String + )(implicit typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error): Unit = { typeCheckResult match { case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) case CompatCheckResult.Warning => printWarning(problemStr) @@ -356,48 +358,33 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, * Check if the parameters of a source and sink stream match. * @param toConnect Source stream to drive this stream with. */ - def paramCheck( - toConnect: PhysicalStreamBase, - typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error - ): Unit = { + def paramCheck(toConnect: PhysicalStreamBase): Unit = { // Number of lanes should be the same if (toConnect.n != this.n) { - reportProblem( - s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect - .toString()} has n=${toConnect.n}", - typeCheckResult - ) + reportProblem(s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect + .toString()} has n=${toConnect.n}") } // Dimensionality should be the same if (toConnect.d != this.d) { reportProblem( - s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}", - typeCheckResult + s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}" ) } // Sink C >= source C for compatibility if (toConnect.c > this.c) { - reportProblem( - s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}", - typeCheckResult - ) + reportProblem(s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}") } } - def elementCheck( - toConnect: PhysicalStreamBase, - typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error - ): Unit = { + def elementCheck(toConnect: PhysicalStreamBase): Unit = { if (this.elWidth != toConnect.elWidth) { reportProblem( - s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}", - typeCheckResult + s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}" ) } if (this.userElWidth != toConnect.userElWidth) { reportProblem( - s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}", - typeCheckResult + s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}" ) } } @@ -625,20 +612,17 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( toConnect: PhysicalStreamDetailed[TBel, TBus], - typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict, - typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error + typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { reportProblem( - s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}", - typeCheckResult + s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}" ) } if (this.user.getClass != toConnect.user.getClass) { reportProblem( - s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}", - typeCheckResult + s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}" ) } } else { From d67787b193e5d4099e4830ba5fd267b4f135e9d2 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 16:40:57 +0200 Subject: [PATCH 07/29] Add boilerplate for stream compatibility check test. --- .../tydi_chisel/StreamCompatCheckTest.scala | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala new file mode 100644 index 0000000..f45b704 --- /dev/null +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -0,0 +1,43 @@ +package nl.tudelft.tydi_chisel + +import chisel3._ +import chisel3.experimental.BundleLiterals.AddBundleLiteralConstructor +import chiseltest._ +import nl.tudelft.tydi_chisel_test.Conversions._ +import org.scalatest.flatspec.AnyFlatSpec + +class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { + class MyBundle extends Group { + val a: UInt = UInt(8.W) + val b: Bool = Bool() + } + + class MyBundle2 extends MyBundle + + class StreamConnectMod(in: PhysicalStream, out: PhysicalStream) extends TydiModule { + private val inStream = Wire(in) + private val outStream = Wire(out) + outStream := inStream + out := in + } + + class DetailedStreamConnectMod[TIel <: TydiEl, TIus <: Data, TOel <: TydiEl, TOus <: Data]( + in: PhysicalStreamDetailed[TIel, TIus], + out: PhysicalStreamDetailed[TOel, TOus] + ) extends TydiModule { + private val inStream = Wire(in) + private val outStream = Wire(out) + outStream := inStream + } + + private val myBundleStream = new PhysicalStreamDetailed(new MyBundle, c=8) + private val myBundle2Stream = new PhysicalStreamDetailed(new MyBundle2, c=8) + + behavior of "Stream compatibility check" + + it should "check type" in { + intercept[TydiStreamCompatException] { + test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } + } + } +} From 1900c32b32043fc017e7e759b40972efd3fe451b Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 16:57:35 +0200 Subject: [PATCH 08/29] Fix uninitialized signal errors. --- .../tydi_chisel/StreamCompatCheckTest.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index f45b704..39b1d23 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -15,27 +15,27 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class MyBundle2 extends MyBundle class StreamConnectMod(in: PhysicalStream, out: PhysicalStream) extends TydiModule { - private val inStream = Wire(in) - private val outStream = Wire(out) + val inStream: PhysicalStream = IO(Flipped(in)) + val outStream: PhysicalStream = IO(out) outStream := inStream - out := in } class DetailedStreamConnectMod[TIel <: TydiEl, TIus <: Data, TOel <: TydiEl, TOus <: Data]( in: PhysicalStreamDetailed[TIel, TIus], out: PhysicalStreamDetailed[TOel, TOus] ) extends TydiModule { - private val inStream = Wire(in) - private val outStream = Wire(out) + val inStream: PhysicalStreamDetailed[TIel, TIus] = IO(Flipped(in)).flip + val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) outStream := inStream } - private val myBundleStream = new PhysicalStreamDetailed(new MyBundle, c=8) - private val myBundle2Stream = new PhysicalStreamDetailed(new MyBundle2, c=8) + private val myBundleStream = new PhysicalStreamDetailed(new MyBundle, c = 8) + private val myBundle2Stream = new PhysicalStreamDetailed(new MyBundle2, c = 8) behavior of "Stream compatibility check" it should "check type" in { + test(new DetailedStreamConnectMod(myBundleStream, myBundleStream)) { _ => } intercept[TydiStreamCompatException] { test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } } From 3e2ae05bf90b2bba773eb13d2c14a0e4351388ae Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 17:12:20 +0200 Subject: [PATCH 09/29] Check stream parameters. --- .../tydi_chisel/StreamCompatCheckTest.scala | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 39b1d23..b87325c 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -29,6 +29,11 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { outStream := inStream } + class DataBundle extends Bundle { + val c: UInt = UInt(10.W) + val d: Bool = Bool() + } + private val myBundleStream = new PhysicalStreamDetailed(new MyBundle, c = 8) private val myBundle2Stream = new PhysicalStreamDetailed(new MyBundle2, c = 8) @@ -40,4 +45,27 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } } } + + it should "check parameters" in { + val baseStream = PhysicalStream(new MyBundle, n = 1, d = 1, c = 1, new DataBundle) + + // Same parameters + test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 1, d = 1, c = 1, new DataBundle))) { _ => } + + // Test unequal n parameter + intercept[TydiStreamCompatException] { + test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle))) { _ => } + } + + // Test unequal d parameter + intercept[TydiStreamCompatException] { + test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 1, d = 2, c = 1, new DataBundle))) { _ => } + } + + // Test c parameter inequality. Csink >= Csource is okay, else an exception is thrown. + test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 1, d = 1, c = 7, new DataBundle))) { _ => } + intercept[TydiStreamCompatException] { + test(new StreamConnectMod(PhysicalStream(new MyBundle, n = 1, d = 2, c = 7, new DataBundle), baseStream)) { _ => } + } + } } From 3ca88751ba1db2b90727b20f378bc6a8f4702cfb Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 17:47:35 +0200 Subject: [PATCH 10/29] Create weak type check. Try moving the implicit parameter definition around. --- .../src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 5 +++-- .../nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index afbca1b..a6e55ef 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -612,7 +612,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( toConnect: PhysicalStreamDetailed[TBel, TBus], - typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict + typeCheck: CompatCheck.CompatCheckType ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { @@ -637,7 +637,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ def :=[TBel <: TydiEl, TBus <: Data]( bundle: PhysicalStreamDetailed[TBel, TBus] - )(implicit typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict): Unit = { + )(implicit typeCheck: CompatCheck.CompatCheckType): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { @@ -733,6 +733,7 @@ object PhysicalStreamDetailed { } trait TydiModuleMixin extends BaseModule with TranspileExtend { + implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict implicit var parentModule: TydiModuleMixin = this private val moduleList = ListBuffer[TydiModuleMixin]() diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index b87325c..f264d3f 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -24,6 +24,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { in: PhysicalStreamDetailed[TIel, TIus], out: PhysicalStreamDetailed[TOel, TOus] ) extends TydiModule { + override implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params val inStream: PhysicalStreamDetailed[TIel, TIus] = IO(Flipped(in)).flip val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) outStream := inStream @@ -46,6 +47,12 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { } } + it should "weak check type" in { + implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params + implicit val integer: Int = 5 + test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } + } + it should "check parameters" in { val baseStream = PhysicalStream(new MyBundle, n = 1, d = 1, c = 1, new DataBundle) From d06199b1515487011ecf062a6cd4a5d8fae28164 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 17:57:41 +0200 Subject: [PATCH 11/29] Move the implicit variable again. --- library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 1 - library/src/main/scala/nl/tudelft/tydi_chisel/package.scala | 2 ++ .../scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index a6e55ef..3edf8f8 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -733,7 +733,6 @@ object PhysicalStreamDetailed { } trait TydiModuleMixin extends BaseModule with TranspileExtend { - implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict implicit var parentModule: TydiModuleMixin = this private val moduleList = ListBuffer[TydiModuleMixin]() diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index ad06d5b..239e8a9 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -4,4 +4,6 @@ package object tydi_chisel { val firNoOptimizationOpts: Array[String] = Array("-disable-opt", "-disable-all-randomization", "-strip-debug-info") val firNormalOpts: Array[String] = Array("-O=debug", "-disable-all-randomization", "-strip-debug-info") val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") + + implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index f264d3f..3ab2212 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -24,7 +24,8 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { in: PhysicalStreamDetailed[TIel, TIus], out: PhysicalStreamDetailed[TOel, TOus] ) extends TydiModule { - override implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params + // The following works for overriding the implicit variable from the package object: + // implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params val inStream: PhysicalStreamDetailed[TIel, TIus] = IO(Flipped(in)).flip val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) outStream := inStream @@ -48,6 +49,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { } it should "weak check type" in { + // The following does not work for overriding the implicit variable from the package object: implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params implicit val integer: Int = 5 test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } From 261f084d4fcb89ea3d3cba848ec63b62123cd09d Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 18:05:41 +0200 Subject: [PATCH 12/29] Successful override of implicit argument. --- .../tydi_chisel/StreamCompatCheckTest.scala | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 3ab2212..e25ea04 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -22,13 +22,22 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class DetailedStreamConnectMod[TIel <: TydiEl, TIus <: Data, TOel <: TydiEl, TOus <: Data]( in: PhysicalStreamDetailed[TIel, TIus], - out: PhysicalStreamDetailed[TOel, TOus] + out: PhysicalStreamDetailed[TOel, TOus], + typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict ) extends TydiModule { // The following works for overriding the implicit variable from the package object: // implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params val inStream: PhysicalStreamDetailed[TIel, TIus] = IO(Flipped(in)).flip val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) - outStream := inStream + + // Just to check override + implicit val typeCheckImplicit: CompatCheck.CompatCheckType = CompatCheck.Strict + + { + // Value gets correctly overridden + implicit val typeCheckImplicit: CompatCheck.CompatCheckType = typeCheck + outStream := inStream + } } class DataBundle extends Bundle { @@ -50,9 +59,9 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { it should "weak check type" in { // The following does not work for overriding the implicit variable from the package object: - implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params - implicit val integer: Int = 5 - test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } +// implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params +// implicit val integer: Int = 5 + test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream, CompatCheck.Params)) { _ => } } it should "check parameters" in { From 552a19067a650a41d02c366c5c49e2f752d0bcea Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 18:09:09 +0200 Subject: [PATCH 13/29] Clean up implicits experimentation. --- .../main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 5 ++--- .../main/scala/nl/tudelft/tydi_chisel/package.scala | 2 +- .../tudelft/tydi_chisel/StreamCompatCheckTest.scala | 12 ++---------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 3edf8f8..31ea445 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -199,7 +199,6 @@ object BitsEl { } object CompatCheck extends Enumeration { - type CompatCheckType = Value val Params, Strict = Value } @@ -612,7 +611,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( toConnect: PhysicalStreamDetailed[TBel, TBus], - typeCheck: CompatCheck.CompatCheckType + typeCheck: CompatCheck.Value ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { @@ -637,7 +636,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ def :=[TBel <: TydiEl, TBus <: Data]( bundle: PhysicalStreamDetailed[TBel, TBus] - )(implicit typeCheck: CompatCheck.CompatCheckType): Unit = { + )(implicit typeCheck: CompatCheck.Value): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index 239e8a9..4e1f2b1 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -5,5 +5,5 @@ package object tydi_chisel { val firNormalOpts: Array[String] = Array("-O=debug", "-disable-all-randomization", "-strip-debug-info") val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") - implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict + implicit val typeCheck: CompatCheck.Value = CompatCheck.Strict } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index e25ea04..a0fb2bb 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -23,19 +23,14 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class DetailedStreamConnectMod[TIel <: TydiEl, TIus <: Data, TOel <: TydiEl, TOus <: Data]( in: PhysicalStreamDetailed[TIel, TIus], out: PhysicalStreamDetailed[TOel, TOus], - typeCheck: CompatCheck.CompatCheckType = CompatCheck.Strict + typeCheck: CompatCheck.Value = CompatCheck.Strict ) extends TydiModule { - // The following works for overriding the implicit variable from the package object: - // implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params val inStream: PhysicalStreamDetailed[TIel, TIus] = IO(Flipped(in)).flip val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) - // Just to check override - implicit val typeCheckImplicit: CompatCheck.CompatCheckType = CompatCheck.Strict - { // Value gets correctly overridden - implicit val typeCheckImplicit: CompatCheck.CompatCheckType = typeCheck + implicit val typeCheckImplicit: CompatCheck.Value = typeCheck outStream := inStream } } @@ -58,9 +53,6 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { } it should "weak check type" in { - // The following does not work for overriding the implicit variable from the package object: -// implicit val typeCheck: CompatCheck.CompatCheckType = CompatCheck.Params -// implicit val integer: Int = 5 test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream, CompatCheck.Params)) { _ => } } From dbeb0858c15750a8043635904c525e2a59809bfd Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 18:32:15 +0200 Subject: [PATCH 14/29] Attempt to do the same with the CompatCheckResult. --- .../scala/nl/tudelft/tydi_chisel/TydiLib.scala | 3 +-- .../scala/nl/tudelft/tydi_chisel/package.scala | 1 + .../tydi_chisel/StreamCompatCheckTest.scala | 18 +++++++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 31ea445..52937c7 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -203,7 +203,6 @@ object CompatCheck extends Enumeration { } object CompatCheckResult extends Enumeration { - type Type = Value val Warning, Error = Value } @@ -346,7 +345,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, protected def reportProblem( problemStr: String - )(implicit typeCheckResult: CompatCheckResult.Type = CompatCheckResult.Error): Unit = { + )(implicit typeCheckResult: CompatCheckResult.Value): Unit = { typeCheckResult match { case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) case CompatCheckResult.Warning => printWarning(problemStr) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index 4e1f2b1..f41e75f 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -6,4 +6,5 @@ package object tydi_chisel { val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") implicit val typeCheck: CompatCheck.Value = CompatCheck.Strict + implicit val typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index a0fb2bb..cce6580 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -14,7 +14,12 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class MyBundle2 extends MyBundle - class StreamConnectMod(in: PhysicalStream, out: PhysicalStream) extends TydiModule { + class StreamConnectMod( + in: PhysicalStream, + out: PhysicalStream, + errorReporting: CompatCheckResult.Value = CompatCheckResult.Error + ) extends TydiModule { + implicit val errorReportingImplicit: CompatCheckResult.Value = errorReporting val inStream: PhysicalStream = IO(Flipped(in)) val outStream: PhysicalStream = IO(out) outStream := inStream @@ -78,4 +83,15 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { test(new StreamConnectMod(PhysicalStream(new MyBundle, n = 1, d = 2, c = 7, new DataBundle), baseStream)) { _ => } } } + + it should "print warnings" in { + val baseStream = PhysicalStream(new MyBundle, n = 1, d = 1, c = 1, new DataBundle) + class StreamConnectWarningsMod(in: PhysicalStream, out: PhysicalStream) + extends StreamConnectMod(in: PhysicalStream, out: PhysicalStream) { + implicit val errorReporting: CompatCheckResult.Value = CompatCheckResult.Warning + } + + // Same parameters + test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), CompatCheckResult.Warning)) { _ => } + } } From 0f4c4ba5eebfd2ce7c4fa25f7049bd86e265df86 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 20 Aug 2024 18:50:19 +0200 Subject: [PATCH 15/29] Attempt to add CompatCheckResult implicit parameter everywhere. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 52937c7..95608a0 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -343,9 +343,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, println(s"$bold$orange$message$reset") } - protected def reportProblem( - problemStr: String - )(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + protected def reportProblem(problemStr: String)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { typeCheckResult match { case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) case CompatCheckResult.Warning => printWarning(problemStr) @@ -356,7 +354,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, * Check if the parameters of a source and sink stream match. * @param toConnect Source stream to drive this stream with. */ - def paramCheck(toConnect: PhysicalStreamBase): Unit = { + def paramCheck(toConnect: PhysicalStreamBase)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { // Number of lanes should be the same if (toConnect.n != this.n) { reportProblem(s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect @@ -374,7 +372,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, } } - def elementCheck(toConnect: PhysicalStreamBase): Unit = { + def elementCheck(toConnect: PhysicalStreamBase)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { if (this.elWidth != toConnect.elWidth) { reportProblem( s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}" @@ -391,7 +389,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, * Meta-connect function. Connects all metadata signals but not the data or user signals. * @param bundle Source stream to drive this stream with. */ - def :~=(bundle: PhysicalStreamBase): Unit = { + def :~=(bundle: PhysicalStreamBase)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { paramCheck(bundle) // This could be done with a :<>= but I like being explicit here to catch possible errors. this.endi := bundle.endi @@ -465,7 +463,9 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * @tparam Tel Element signal type. * @tparam Tus User signal type. */ - def :=[Tel <: TydiEl, Tus <: Data](bundle: PhysicalStreamDetailed[Tel, Tus]): Unit = { + def :=[Tel <: TydiEl, Tus <: Data]( + bundle: PhysicalStreamDetailed[Tel, Tus] + )(implicit typeCheckResult: CompatCheckResult.Value): Unit = { this :~= bundle elementCheck(bundle) if (elWidth > 0) { @@ -484,7 +484,7 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream): Unit = { + def :=(bundle: PhysicalStream)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { this :~= bundle elementCheck(bundle) this.data := bundle.data @@ -611,7 +611,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( toConnect: PhysicalStreamDetailed[TBel, TBus], typeCheck: CompatCheck.Value - ): Unit = { + )(implicit typeCheckResult: CompatCheckResult.Value): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { reportProblem( @@ -635,7 +635,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ def :=[TBel <: TydiEl, TBus <: Data]( bundle: PhysicalStreamDetailed[TBel, TBus] - )(implicit typeCheck: CompatCheck.Value): Unit = { + )(implicit typeCheck: CompatCheck.Value, typeCheckResult: CompatCheckResult.Value): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { @@ -681,7 +681,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream): Unit = { + def :=(bundle: PhysicalStream)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { paramCheck(bundle) bundle.elementCheck(this) // We cannot use the :~= function here since the last vector must be driven by the bitvector From 6c11a462aea46dab315f4faea93cd71e824b4bbc Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Thu, 22 Aug 2024 19:59:09 +0200 Subject: [PATCH 16/29] Find out issue about implicit/explicit variable shadowing. --- .../scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index cce6580..2b8198a 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -17,9 +17,10 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class StreamConnectMod( in: PhysicalStream, out: PhysicalStream, - errorReporting: CompatCheckResult.Value = CompatCheckResult.Error + // This only works if it shadows the name of the package implicit definition + typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error ) extends TydiModule { - implicit val errorReportingImplicit: CompatCheckResult.Value = errorReporting + implicit val errorReportingImplicit: CompatCheckResult.Value = typeCheckResult val inStream: PhysicalStream = IO(Flipped(in)) val outStream: PhysicalStream = IO(out) outStream := inStream From 4473ab0db800a74850d346e1bacb5e49061fe6f6 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Fri, 23 Aug 2024 13:20:33 +0200 Subject: [PATCH 17/29] Better default implicit for typeCheck. --- library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 2 +- library/src/main/scala/nl/tudelft/tydi_chisel/package.scala | 2 +- .../scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 95608a0..833d0d0 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -635,7 +635,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ def :=[TBel <: TydiEl, TBus <: Data]( bundle: PhysicalStreamDetailed[TBel, TBus] - )(implicit typeCheck: CompatCheck.Value, typeCheckResult: CompatCheckResult.Value): Unit = { + )(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict, typeCheckResult: CompatCheckResult.Value): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index f41e75f..aebccdd 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -5,6 +5,6 @@ package object tydi_chisel { val firNormalOpts: Array[String] = Array("-O=debug", "-disable-all-randomization", "-strip-debug-info") val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") - implicit val typeCheck: CompatCheck.Value = CompatCheck.Strict +// implicit val typeCheck: CompatCheck.Value = CompatCheck.Strict implicit val typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 2b8198a..ccae1e4 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -29,14 +29,14 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class DetailedStreamConnectMod[TIel <: TydiEl, TIus <: Data, TOel <: TydiEl, TOus <: Data]( in: PhysicalStreamDetailed[TIel, TIus], out: PhysicalStreamDetailed[TOel, TOus], - typeCheck: CompatCheck.Value = CompatCheck.Strict + typeCheckSelect: CompatCheck.Value = CompatCheck.Strict ) extends TydiModule { val inStream: PhysicalStreamDetailed[TIel, TIus] = IO(Flipped(in)).flip val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) { // Value gets correctly overridden - implicit val typeCheckImplicit: CompatCheck.Value = typeCheck + implicit val typeCheckImplicit: CompatCheck.Value = typeCheckSelect outStream := inStream } } From 3bce3d6acb38a26d8b9ec16646f6a438099d7396 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 15:28:47 +0200 Subject: [PATCH 18/29] Attempt the same for typeCheckResult. --- .../scala/nl/tudelft/tydi_chisel/TydiLib.scala | 18 +++++++++--------- .../scala/nl/tudelft/tydi_chisel/package.scala | 2 +- .../tydi_chisel/StreamCompatCheckTest.scala | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 833d0d0..fe274c8 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -343,7 +343,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, println(s"$bold$orange$message$reset") } - protected def reportProblem(problemStr: String)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + protected def reportProblem(problemStr: String)(implicit typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error): Unit = { typeCheckResult match { case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) case CompatCheckResult.Warning => printWarning(problemStr) @@ -354,7 +354,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, * Check if the parameters of a source and sink stream match. * @param toConnect Source stream to drive this stream with. */ - def paramCheck(toConnect: PhysicalStreamBase)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + def paramCheck(toConnect: PhysicalStreamBase): Unit = { // Number of lanes should be the same if (toConnect.n != this.n) { reportProblem(s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect @@ -372,7 +372,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, } } - def elementCheck(toConnect: PhysicalStreamBase)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + def elementCheck(toConnect: PhysicalStreamBase): Unit = { if (this.elWidth != toConnect.elWidth) { reportProblem( s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}" @@ -389,7 +389,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, * Meta-connect function. Connects all metadata signals but not the data or user signals. * @param bundle Source stream to drive this stream with. */ - def :~=(bundle: PhysicalStreamBase)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + def :~=(bundle: PhysicalStreamBase): Unit = { paramCheck(bundle) // This could be done with a :<>= but I like being explicit here to catch possible errors. this.endi := bundle.endi @@ -465,7 +465,7 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv */ def :=[Tel <: TydiEl, Tus <: Data]( bundle: PhysicalStreamDetailed[Tel, Tus] - )(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + ): Unit = { this :~= bundle elementCheck(bundle) if (elWidth > 0) { @@ -484,7 +484,7 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + def :=(bundle: PhysicalStream): Unit = { this :~= bundle elementCheck(bundle) this.data := bundle.data @@ -611,7 +611,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( toConnect: PhysicalStreamDetailed[TBel, TBus], typeCheck: CompatCheck.Value - )(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { reportProblem( @@ -635,7 +635,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ def :=[TBel <: TydiEl, TBus <: Data]( bundle: PhysicalStreamDetailed[TBel, TBus] - )(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict, typeCheckResult: CompatCheckResult.Value): Unit = { + )(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { @@ -681,7 +681,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream)(implicit typeCheckResult: CompatCheckResult.Value): Unit = { + def :=(bundle: PhysicalStream): Unit = { paramCheck(bundle) bundle.elementCheck(this) // We cannot use the :~= function here since the last vector must be driven by the bitvector diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index aebccdd..4940274 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -6,5 +6,5 @@ package object tydi_chisel { val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") // implicit val typeCheck: CompatCheck.Value = CompatCheck.Strict - implicit val typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error +// implicit val typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index ccae1e4..9b5058c 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -18,9 +18,9 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { in: PhysicalStream, out: PhysicalStream, // This only works if it shadows the name of the package implicit definition - typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error + errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ) extends TydiModule { - implicit val errorReportingImplicit: CompatCheckResult.Value = typeCheckResult + implicit val errorReportingImplicit: CompatCheckResult.Value = errorReporting val inStream: PhysicalStream = IO(Flipped(in)) val outStream: PhysicalStream = IO(out) outStream := inStream From 7adcc065da01a892bfe6cd71e3a27ea74a1fd995 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 16:02:04 +0200 Subject: [PATCH 19/29] Use package variable for the error reporting method. --- .../src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 4 ++-- .../src/main/scala/nl/tudelft/tydi_chisel/package.scala | 9 +++++++-- .../nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index fe274c8..fbe559a 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -343,8 +343,8 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, println(s"$bold$orange$message$reset") } - protected def reportProblem(problemStr: String)(implicit typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error): Unit = { - typeCheckResult match { + protected def reportProblem(problemStr: String): Unit = { + compatCheckResult match { case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) case CompatCheckResult.Warning => printWarning(problemStr) } diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index 4940274..b344d64 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -5,6 +5,11 @@ package object tydi_chisel { val firNormalOpts: Array[String] = Array("-O=debug", "-disable-all-randomization", "-strip-debug-info") val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") -// implicit val typeCheck: CompatCheck.Value = CompatCheck.Strict -// implicit val typeCheckResult: CompatCheckResult.Value = CompatCheckResult.Error + private[this] var _compatCheckResult: CompatCheckResult.Value = CompatCheckResult.Error + + def compatCheckResult: CompatCheckResult.Value = _compatCheckResult + + def setCompatCheckResult(value: CompatCheckResult.Value): Unit = { + _compatCheckResult = value + } } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 9b5058c..0122fea 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -20,7 +20,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { // This only works if it shadows the name of the package implicit definition errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ) extends TydiModule { - implicit val errorReportingImplicit: CompatCheckResult.Value = errorReporting + nl.tudelft.tydi_chisel setCompatCheckResult errorReporting val inStream: PhysicalStream = IO(Flipped(in)) val outStream: PhysicalStream = IO(out) outStream := inStream From dd8498c9815800c8714c0ed831c1547d77104e42 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 16:13:57 +0200 Subject: [PATCH 20/29] Print warnings to stderr and test this. --- .../src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 2 +- .../nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index fbe559a..8ad3d1c 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -340,7 +340,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, val reset = "\u001b[0m" // Print the formatted message - println(s"$bold$orange$message$reset") + Console.err.println(s"$bold$orange$message$reset") } protected def reportProblem(problemStr: String): Unit = { diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 0122fea..7601687 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -93,6 +93,11 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { } // Same parameters - test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), CompatCheckResult.Warning)) { _ => } + val stream = new java.io.ByteArrayOutputStream() + Console.withErr(stream) { + test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), CompatCheckResult.Warning)) { _ => } + } + // Check if error was written to console + assert(stream.toString contains "Number of lanes between source and sink is not equal.") } } From 17131ab49df4d1d0d7e2429b309b2496205623ff Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 16:43:15 +0200 Subject: [PATCH 21/29] Run formatting. --- .../src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala | 4 +--- .../nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 8 +++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 8ad3d1c..72f80f7 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -463,9 +463,7 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * @tparam Tel Element signal type. * @tparam Tus User signal type. */ - def :=[Tel <: TydiEl, Tus <: Data]( - bundle: PhysicalStreamDetailed[Tel, Tus] - ): Unit = { + def :=[Tel <: TydiEl, Tus <: Data](bundle: PhysicalStreamDetailed[Tel, Tus]): Unit = { this :~= bundle elementCheck(bundle) if (elWidth > 0) { diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 7601687..7dff567 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -95,7 +95,13 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { // Same parameters val stream = new java.io.ByteArrayOutputStream() Console.withErr(stream) { - test(new StreamConnectMod(baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), CompatCheckResult.Warning)) { _ => } + test( + new StreamConnectMod( + baseStream, + PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), + CompatCheckResult.Warning + ) + ) { _ => } } // Check if error was written to console assert(stream.toString contains "Number of lanes between source and sink is not equal.") From 2b4244426d7dbaa67ab43d3b98651e0d7171d3b1 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 18:50:14 +0200 Subject: [PATCH 22/29] Update readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8c3218..9bd40c6 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,7 @@ Concretely, this project contains: - Being able to work with the detailed bundles inside your components - Compliant with [Tydi-standard](https://abs-tudelft.github.io/tydi/specification/physical.html) for communication with components created outside of Chisel - Simple stream connection + - Stream compatibility checks - Helper functions for common signal use-cases - A stream-processing component chaining syntax - Testing utilities @@ -252,7 +253,6 @@ Concretely, this project contains: - Create interoperability with [Fletcher](https://github.com/abs-tudelft/fletcher) - Investigate adoption of other hardware description languages - Library - - Stream compatibility checks - Better Union support - Interoperability with other streaming standards - Improved error handling and design rule checks From 5e97e6ece912cc5b5bf1d73ce67ca6f9d4b1d225 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 18:56:50 +0200 Subject: [PATCH 23/29] Clean up. --- .../nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 7dff567..be8328d 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -1,9 +1,7 @@ package nl.tudelft.tydi_chisel import chisel3._ -import chisel3.experimental.BundleLiterals.AddBundleLiteralConstructor import chiseltest._ -import nl.tudelft.tydi_chisel_test.Conversions._ import org.scalatest.flatspec.AnyFlatSpec class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { @@ -17,7 +15,6 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class StreamConnectMod( in: PhysicalStream, out: PhysicalStream, - // This only works if it shadows the name of the package implicit definition errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ) extends TydiModule { nl.tudelft.tydi_chisel setCompatCheckResult errorReporting @@ -87,12 +84,8 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { it should "print warnings" in { val baseStream = PhysicalStream(new MyBundle, n = 1, d = 1, c = 1, new DataBundle) - class StreamConnectWarningsMod(in: PhysicalStream, out: PhysicalStream) - extends StreamConnectMod(in: PhysicalStream, out: PhysicalStream) { - implicit val errorReporting: CompatCheckResult.Value = CompatCheckResult.Warning - } - // Same parameters + // Create a module with warning output and give it incompatible streams. val stream = new java.io.ByteArrayOutputStream() Console.withErr(stream) { test( From 7370d9ba2fe7cca00a4869ea62f73c029b0c3518 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 19:28:49 +0200 Subject: [PATCH 24/29] Attempt to add the strong type check for all connections. Multiple overloaded methods cannot define default arguments, however. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 51 +++++++++---------- .../tydi_chisel/StreamCompatCheckTest.scala | 14 +++-- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 72f80f7..f033e3f 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -385,6 +385,23 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, } } + def elementCheckTyped(toConnect: PhysicalStreamBase, typeCheck: CompatCheck.Value): Unit = { + if (typeCheck == CompatCheck.Strict) { + if (this.getDataType.getClass != toConnect.getDataType.getClass) { + reportProblem( + s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}" + ) + } + if (this.user.getClass != toConnect.user.getClass) { + reportProblem( + s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}" + ) + } + } else { + elementCheck(toConnect) + } + } + /** * Meta-connect function. Connects all metadata signals but not the data or user signals. * @param bundle Source stream to drive this stream with. @@ -463,9 +480,11 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * @tparam Tel Element signal type. * @tparam Tus User signal type. */ - def :=[Tel <: TydiEl, Tus <: Data](bundle: PhysicalStreamDetailed[Tel, Tus]): Unit = { + def :=[Tel <: TydiEl, Tus <: Data]( + bundle: PhysicalStreamDetailed[Tel, Tus] + )(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { this :~= bundle - elementCheck(bundle) + elementCheckTyped(bundle, typeCheck) if (elWidth > 0) { this.data := bundle.getDataConcat } else { @@ -482,9 +501,9 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream): Unit = { + def :=(bundle: PhysicalStream)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { this :~= bundle - elementCheck(bundle) + elementCheckTyped(bundle, typeCheck) this.data := bundle.data this.user := bundle.user } @@ -606,26 +625,6 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( io } - def elementCheckTyped[TBel <: TydiEl, TBus <: Data]( - toConnect: PhysicalStreamDetailed[TBel, TBus], - typeCheck: CompatCheck.Value - ): Unit = { - if (typeCheck == CompatCheck.Strict) { - if (this.getDataType.getClass != toConnect.getDataType.getClass) { - reportProblem( - s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}" - ) - } - if (this.user.getClass != toConnect.user.getClass) { - reportProblem( - s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}" - ) - } - } else { - super.elementCheck(toConnect) - } - } - // Require the element and user signal types to be the same as this stream in the function signature. /** * Stream mounting function. @@ -679,9 +678,9 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream): Unit = { + def :=(bundle: PhysicalStream)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { paramCheck(bundle) - bundle.elementCheck(this) + elementCheckTyped(bundle, typeCheck) // We cannot use the :~= function here since the last vector must be driven by the bitvector this.endi := bundle.endi this.stai := bundle.stai diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index be8328d..06e3870 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -15,12 +15,17 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { class StreamConnectMod( in: PhysicalStream, out: PhysicalStream, + typeCheckSelect: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ) extends TydiModule { nl.tudelft.tydi_chisel setCompatCheckResult errorReporting val inStream: PhysicalStream = IO(Flipped(in)) val outStream: PhysicalStream = IO(out) - outStream := inStream + + { + implicit val typeCheckImplicit: CompatCheck.Value = typeCheckSelect + outStream := inStream + } } class DetailedStreamConnectMod[TIel <: TydiEl, TIus <: Data, TOel <: TydiEl, TOus <: Data]( @@ -32,7 +37,6 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { val outStream: PhysicalStreamDetailed[TOel, TOus] = IO(out) { - // Value gets correctly overridden implicit val typeCheckImplicit: CompatCheck.Value = typeCheckSelect outStream := inStream } @@ -53,10 +57,14 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { intercept[TydiStreamCompatException] { test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream)) { _ => } } + intercept[TydiStreamCompatException] { + test(new StreamConnectMod(PhysicalStream(new MyBundle, c = 1), PhysicalStream(new MyBundle2, c = 1))) { _ => } + } } it should "weak check type" in { test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream, CompatCheck.Params)) { _ => } + test(new StreamConnectMod(PhysicalStream(new MyBundle, c = 1), PhysicalStream(new MyBundle2, c = 1))) { _ => } } it should "check parameters" in { @@ -92,7 +100,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { new StreamConnectMod( baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), - CompatCheckResult.Warning + errorReporting=CompatCheckResult.Warning ) ) { _ => } } From 82214a3c2b90fa2ff2f240905061c982a1a67a44 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 19:51:24 +0200 Subject: [PATCH 25/29] Avoid overloaded method issues by upcasting. This has the issue that type parameters are not checked. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 28 ++++++++++++------- .../tydi_chisel/StreamCompatCheckTest.scala | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index f033e3f..e052cb5 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -217,7 +217,7 @@ final case class TydiStreamCompatException(private val message: String = "", pri * @param c Complexity * @param u User signals */ -abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, val c: Int, private val u: Data) +sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, val c: Int, private val u: Data) extends TydiEl { override val isStream: Boolean = true override val elWidth: Int = e.getDataElementsRec.map(_.getWidth).sum @@ -392,7 +392,7 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}" ) } - if (this.user.getClass != toConnect.user.getClass) { + if (this.getUserType.getClass != toConnect.getUserType.getClass) { reportProblem( s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}" ) @@ -426,6 +426,16 @@ abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val d: Int, } } + def :=[TBel <: TydiEl, TBus <: Data](bundle: PhysicalStreamBase)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + // TBel and TBus checking is not possible because of erasure. + (this, bundle) match { + case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck) + case (x: PhysicalStream, y: PhysicalStreamDetailed[TBel, TBus]) => x.connectDetailed(y, typeCheck) + case (x: PhysicalStreamDetailed[TBel, TBus], y: PhysicalStream) => x.connectSimple(y, typeCheck) + case (x: PhysicalStreamDetailed[TBel, TBus], y: PhysicalStreamDetailed[TBel, TBus]) => x.connectDetailed(y, typeCheck) + } + } + def tydiCode: String = { val elName = e.fingerprint val usName = u.fingerprint @@ -480,9 +490,8 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * @tparam Tel Element signal type. * @tparam Tus User signal type. */ - def :=[Tel <: TydiEl, Tus <: Data]( - bundle: PhysicalStreamDetailed[Tel, Tus] - )(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + private[tydi_chisel] def connectDetailed[Tel <: TydiEl, Tus <: Data]( + bundle: PhysicalStreamDetailed[Tel, Tus], typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { this :~= bundle elementCheckTyped(bundle, typeCheck) if (elWidth > 0) { @@ -501,7 +510,7 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + private[tydi_chisel] def connectSimple(bundle: PhysicalStream, typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { this :~= bundle elementCheckTyped(bundle, typeCheck) this.data := bundle.data @@ -630,9 +639,8 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=[TBel <: TydiEl, TBus <: Data]( - bundle: PhysicalStreamDetailed[TBel, TBus] - )(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + private[tydi_chisel] def connectDetailed[TBel <: TydiEl, TBus <: Data]( + bundle: PhysicalStreamDetailed[TBel, TBus], typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { @@ -678,7 +686,7 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - def :=(bundle: PhysicalStream)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + private[tydi_chisel] def connectSimple(bundle: PhysicalStream, typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { paramCheck(bundle) elementCheckTyped(bundle, typeCheck) // We cannot use the :~= function here since the last vector must be driven by the bitvector diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 06e3870..43ceda3 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -64,7 +64,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { it should "weak check type" in { test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream, CompatCheck.Params)) { _ => } - test(new StreamConnectMod(PhysicalStream(new MyBundle, c = 1), PhysicalStream(new MyBundle2, c = 1))) { _ => } + test(new StreamConnectMod(PhysicalStream(new MyBundle, c = 1), PhysicalStream(new MyBundle2, c = 1), CompatCheck.Params)) { _ => } } it should "check parameters" in { From 6d691c6debc3a5a13b2adf4dfcb24d898bef67c6 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 19:52:48 +0200 Subject: [PATCH 26/29] Format. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index e052cb5..06f8e54 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -426,13 +426,12 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val } } - def :=[TBel <: TydiEl, TBus <: Data](bundle: PhysicalStreamBase)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { - // TBel and TBus checking is not possible because of erasure. + def :=(bundle: PhysicalStreamBase)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { (this, bundle) match { - case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck) - case (x: PhysicalStream, y: PhysicalStreamDetailed[TBel, TBus]) => x.connectDetailed(y, typeCheck) - case (x: PhysicalStreamDetailed[TBel, TBus], y: PhysicalStream) => x.connectSimple(y, typeCheck) - case (x: PhysicalStreamDetailed[TBel, TBus], y: PhysicalStreamDetailed[TBel, TBus]) => x.connectDetailed(y, typeCheck) + case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck) + case (x: PhysicalStream, y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck) + case (x: PhysicalStreamDetailed[_, _], y: PhysicalStream) => x.connectSimple(y, typeCheck) + case (x: PhysicalStreamDetailed[_, _], y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck) } } @@ -491,7 +490,9 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * @tparam Tus User signal type. */ private[tydi_chisel] def connectDetailed[Tel <: TydiEl, Tus <: Data]( - bundle: PhysicalStreamDetailed[Tel, Tus], typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + bundle: PhysicalStreamDetailed[Tel, Tus], + typeCheck: CompatCheck.Value = CompatCheck.Strict + ): Unit = { this :~= bundle elementCheckTyped(bundle, typeCheck) if (elWidth > 0) { @@ -510,7 +511,10 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - private[tydi_chisel] def connectSimple(bundle: PhysicalStream, typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + private[tydi_chisel] def connectSimple( + bundle: PhysicalStream, + typeCheck: CompatCheck.Value = CompatCheck.Strict + ): Unit = { this :~= bundle elementCheckTyped(bundle, typeCheck) this.data := bundle.data @@ -640,7 +644,9 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * @param bundle Source stream to drive this stream with. */ private[tydi_chisel] def connectDetailed[TBel <: TydiEl, TBus <: Data]( - bundle: PhysicalStreamDetailed[TBel, TBus], typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + bundle: PhysicalStreamDetailed[TBel, TBus], + typeCheck: CompatCheck.Value = CompatCheck.Strict + ): Unit = { elementCheckTyped(bundle, typeCheck) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { @@ -686,7 +692,10 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( * Stream mounting function. * @param bundle Source stream to drive this stream with. */ - private[tydi_chisel] def connectSimple(bundle: PhysicalStream, typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + private[tydi_chisel] def connectSimple( + bundle: PhysicalStream, + typeCheck: CompatCheck.Value = CompatCheck.Strict + ): Unit = { paramCheck(bundle) elementCheckTyped(bundle, typeCheck) // We cannot use the :~= function here since the last vector must be driven by the bitvector From 6a587c3243e31155ab5551ed220af13dc253bf33 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Tue, 3 Sep 2024 20:08:14 +0200 Subject: [PATCH 27/29] Attempt to convert check result back to implicit. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 83 ++++++++++++------- .../nl/tudelft/tydi_chisel/package.scala | 8 -- .../tydi_chisel/StreamCompatCheckTest.scala | 2 +- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 06f8e54..43f99e2 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -343,7 +343,7 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val Console.err.println(s"$bold$orange$message$reset") } - protected def reportProblem(problemStr: String): Unit = { + protected def reportProblem(problemStr: String, compatCheckResult: CompatCheckResult.Value): Unit = { compatCheckResult match { case CompatCheckResult.Error => throw TydiStreamCompatException(problemStr) case CompatCheckResult.Warning => printWarning(problemStr) @@ -354,51 +354,66 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val * Check if the parameters of a source and sink stream match. * @param toConnect Source stream to drive this stream with. */ - def paramCheck(toConnect: PhysicalStreamBase): Unit = { + def paramCheck(toConnect: PhysicalStreamBase, compatCheckResult: CompatCheckResult.Value): Unit = { // Number of lanes should be the same if (toConnect.n != this.n) { - reportProblem(s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect - .toString()} has n=${toConnect.n}") + reportProblem( + s"Number of lanes between source and sink is not equal. ${this} has n=${this.n}, ${toConnect + .toString()} has n=${toConnect.n}", + compatCheckResult + ) } // Dimensionality should be the same if (toConnect.d != this.d) { reportProblem( - s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}" + s"Dimensionality of source and sink is not equal. ${this} has d=${this.d}, ${toConnect} has d=${toConnect.d}", + compatCheckResult ) } // Sink C >= source C for compatibility if (toConnect.c > this.c) { - reportProblem(s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}") + reportProblem( + s"Complexity of source stream > sink. ${this} has c=${this.c}, ${toConnect} has c=${toConnect.c}", + compatCheckResult + ) } } - def elementCheck(toConnect: PhysicalStreamBase): Unit = { + def elementCheck(toConnect: PhysicalStreamBase, compatCheckResult: CompatCheckResult.Value): Unit = { if (this.elWidth != toConnect.elWidth) { reportProblem( - s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}" + s"Size of stream elements is not equal. ${this} has |e|=${this.elWidth}, ${toConnect} has |e|=${toConnect.elWidth}", + compatCheckResult ) } if (this.userElWidth != toConnect.userElWidth) { reportProblem( - s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}" + s"Size of stream elements is not equal. ${this} has |u|=${this.userElWidth}, ${toConnect} has |u|=${toConnect.userElWidth}", + compatCheckResult ) } } - def elementCheckTyped(toConnect: PhysicalStreamBase, typeCheck: CompatCheck.Value): Unit = { + def elementCheckTyped( + toConnect: PhysicalStreamBase, + typeCheck: CompatCheck.Value, + compatCheckResult: CompatCheckResult.Value + ): Unit = { if (typeCheck == CompatCheck.Strict) { if (this.getDataType.getClass != toConnect.getDataType.getClass) { reportProblem( - s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}" + s"Type of stream elements is not equal. ${this} has e=${this.getDataType.getClass}, ${toConnect} has e=${toConnect.getDataType.getClass}", + compatCheckResult ) } if (this.getUserType.getClass != toConnect.getUserType.getClass) { reportProblem( - s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}" + s"Type of user elements is not equal. ${this} has u=${this.getUserType.getClass}, ${toConnect} has u=${toConnect.getUserType.getClass}", + compatCheckResult ) } } else { - elementCheck(toConnect) + elementCheck(toConnect, compatCheckResult) } } @@ -406,8 +421,10 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val * Meta-connect function. Connects all metadata signals but not the data or user signals. * @param bundle Source stream to drive this stream with. */ - def :~=(bundle: PhysicalStreamBase): Unit = { - paramCheck(bundle) + def :~=( + bundle: PhysicalStreamBase + )(implicit compatCheckResult: CompatCheckResult.Value = CompatCheckResult.Error): Unit = { + paramCheck(bundle, compatCheckResult) // This could be done with a :<>= but I like being explicit here to catch possible errors. this.endi := bundle.endi this.stai := bundle.stai @@ -426,12 +443,16 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val } } - def :=(bundle: PhysicalStreamBase)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict): Unit = { + def :=(bundle: PhysicalStreamBase)(implicit + typeCheck: CompatCheck.Value = CompatCheck.Strict, + errorReporting: CompatCheckResult.Value = CompatCheckResult.Error + ): Unit = { (this, bundle) match { - case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck) - case (x: PhysicalStream, y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck) - case (x: PhysicalStreamDetailed[_, _], y: PhysicalStream) => x.connectSimple(y, typeCheck) - case (x: PhysicalStreamDetailed[_, _], y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck) + case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck, errorReporting) + case (x: PhysicalStream, y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck, errorReporting) + case (x: PhysicalStreamDetailed[_, _], y: PhysicalStream) => x.connectSimple(y, typeCheck, errorReporting) + case (x: PhysicalStreamDetailed[_, _], y: PhysicalStreamDetailed[_, _]) => + x.connectDetailed(y, typeCheck, errorReporting) } } @@ -491,10 +512,11 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv */ private[tydi_chisel] def connectDetailed[Tel <: TydiEl, Tus <: Data]( bundle: PhysicalStreamDetailed[Tel, Tus], - typeCheck: CompatCheck.Value = CompatCheck.Strict + typeCheck: CompatCheck.Value = CompatCheck.Strict, + errorReporting: CompatCheckResult.Value ): Unit = { this :~= bundle - elementCheckTyped(bundle, typeCheck) + elementCheckTyped(bundle, typeCheck, errorReporting) if (elWidth > 0) { this.data := bundle.getDataConcat } else { @@ -513,10 +535,11 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv */ private[tydi_chisel] def connectSimple( bundle: PhysicalStream, - typeCheck: CompatCheck.Value = CompatCheck.Strict + typeCheck: CompatCheck.Value, + errorReporting: CompatCheckResult.Value ): Unit = { this :~= bundle - elementCheckTyped(bundle, typeCheck) + elementCheckTyped(bundle, typeCheck, errorReporting) this.data := bundle.data this.user := bundle.user } @@ -645,9 +668,10 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ private[tydi_chisel] def connectDetailed[TBel <: TydiEl, TBus <: Data]( bundle: PhysicalStreamDetailed[TBel, TBus], - typeCheck: CompatCheck.Value = CompatCheck.Strict + typeCheck: CompatCheck.Value = CompatCheck.Strict, + errorReporting: CompatCheckResult.Value ): Unit = { - elementCheckTyped(bundle, typeCheck) + elementCheckTyped(bundle, typeCheck, errorReporting) // This could be done with a :<>= but I like being explicit here to catch possible errors. if (bundle.r && !this.r) { this :~= bundle @@ -694,10 +718,11 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( */ private[tydi_chisel] def connectSimple( bundle: PhysicalStream, - typeCheck: CompatCheck.Value = CompatCheck.Strict + typeCheck: CompatCheck.Value = CompatCheck.Strict, + errorReporting: CompatCheckResult.Value ): Unit = { - paramCheck(bundle) - elementCheckTyped(bundle, typeCheck) + paramCheck(bundle, errorReporting) + elementCheckTyped(bundle, typeCheck, errorReporting) // We cannot use the :~= function here since the last vector must be driven by the bitvector this.endi := bundle.endi this.stai := bundle.stai diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala index b344d64..ad06d5b 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/package.scala @@ -4,12 +4,4 @@ package object tydi_chisel { val firNoOptimizationOpts: Array[String] = Array("-disable-opt", "-disable-all-randomization", "-strip-debug-info") val firNormalOpts: Array[String] = Array("-O=debug", "-disable-all-randomization", "-strip-debug-info") val firReleaseOpts: Array[String] = Array("-O=release", "-disable-all-randomization", "-strip-debug-info") - - private[this] var _compatCheckResult: CompatCheckResult.Value = CompatCheckResult.Error - - def compatCheckResult: CompatCheckResult.Value = _compatCheckResult - - def setCompatCheckResult(value: CompatCheckResult.Value): Unit = { - _compatCheckResult = value - } } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 43ceda3..28d2dc2 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -18,12 +18,12 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { typeCheckSelect: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ) extends TydiModule { - nl.tudelft.tydi_chisel setCompatCheckResult errorReporting val inStream: PhysicalStream = IO(Flipped(in)) val outStream: PhysicalStream = IO(out) { implicit val typeCheckImplicit: CompatCheck.Value = typeCheckSelect + implicit val typeCheckResultImplicit: CompatCheckResult.Value = errorReporting outStream := inStream } } From b1f9666983bf270af59c26ff5408df4e6ce5a089 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Mon, 9 Sep 2024 16:08:17 +0200 Subject: [PATCH 28/29] Lift meta connection and type check to common function call. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 83 ++++++------------- 1 file changed, 25 insertions(+), 58 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 43f99e2..6497c2d 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -436,6 +436,11 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val (this.last, bundle.last) match { case (_: UInt, _: UInt) | (_: Vec[_], _: Vec[_]) => this.last := bundle.last case (_: UInt, _: Vec[_]) => this.last := bundle.last.asUInt + case (thisLast: Vec[_], bundleLast: UInt) => + for ((lastLane, i) <- thisLast.zipWithIndex) { + // Assign a slice of the bitvector to the respective lane in the vector + lastLane := bundleLast((i + 1) * d - 1, i * d) + } } } else { this.last := DontCare @@ -447,6 +452,8 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val typeCheck: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ): Unit = { + this :~= bundle + elementCheckTyped(bundle, typeCheck, errorReporting) (this, bundle) match { case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck, errorReporting) case (x: PhysicalStream, y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck, errorReporting) @@ -515,8 +522,6 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv typeCheck: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value ): Unit = { - this :~= bundle - elementCheckTyped(bundle, typeCheck, errorReporting) if (elWidth > 0) { this.data := bundle.getDataConcat } else { @@ -538,8 +543,6 @@ class PhysicalStream(private val e: TydiEl, n: Int = 1, d: Int = 1, c: Int, priv typeCheck: CompatCheck.Value, errorReporting: CompatCheckResult.Value ): Unit = { - this :~= bundle - elementCheckTyped(bundle, typeCheck, errorReporting) this.data := bundle.data this.user := bundle.user } @@ -671,45 +674,25 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( typeCheck: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value ): Unit = { - elementCheckTyped(bundle, typeCheck, errorReporting) - // This could be done with a :<>= but I like being explicit here to catch possible errors. - if (bundle.r && !this.r) { - this :~= bundle - // The following would work if we would know with certainty that the signals are oriented the right way, - // but we do not -.- - // (this.data: Data) :<>= (bundle.data: Data) - - // Using the recursive function leads to duplicate connections when connecting sub-streams, but the non-recursive - // version cannot be used, since non-stream elements could still contain stream items. - for ((thisData, bundleData) <- this.getDataElementsRec.zip(bundle.getDataElementsRec)) { - thisData :<>= bundleData - } - for ( - (thisStream: PhysicalStreamDetailed[_, _], bundleStream: PhysicalStreamDetailed[_, _]) <- this.getStreamElements - .zip(bundle.getStreamElements) - ) { - thisStream := bundleStream - } - (this.user: Data) :<>= (bundle.user: Data) - } else { - bundle :~= this - // The following would work if we would know with certainty that the signals are oriented the right way, - // but we do not -.- - // (bundle.data: Data) :<>= (this.data: Data) - - // Using the recursive function leads to duplicate connections when connecting sub-streams, but the non-recursive - // version cannot be used, since non-stream elements could still contain stream items. - for ((thisData, bundleData) <- this.getDataElementsRec.zip(bundle.getDataElementsRec)) { - bundleData :<>= thisData - } - for ( - (thisStream: PhysicalStreamDetailed[_, _], bundleStream: PhysicalStreamDetailed[_, _]) <- this.getStreamElements - .zip(bundle.getStreamElements) - ) { - bundleStream := thisStream - } - (bundle.user: Data) :<>= (this.user: Data) + if (!bundle.r || this.r) { + throw new Exception("Attempting to connect an input to an output. Reverse the connection.") + } + // The following would work if we would know with certainty that the signals are oriented the right way, + // but we do not -.- + // (this.data: Data) :<>= (bundle.data: Data) + + // Using the recursive function leads to duplicate connections when connecting sub-streams, but the non-recursive + // version cannot be used, since non-stream elements could still contain stream items. + for ((thisData, bundleData) <- this.getDataElementsRec.zip(bundle.getDataElementsRec)) { + thisData :<>= bundleData } + for ( + (thisStream: PhysicalStreamDetailed[_, _], bundleStream: PhysicalStreamDetailed[_, _]) <- this.getStreamElements + .zip(bundle.getStreamElements) + ) { + thisStream := bundleStream + } + (this.user: Data) :<>= (bundle.user: Data) } /** @@ -721,22 +704,6 @@ class PhysicalStreamDetailed[Tel <: TydiEl, Tus <: Data]( typeCheck: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value ): Unit = { - paramCheck(bundle, errorReporting) - elementCheckTyped(bundle, typeCheck, errorReporting) - // We cannot use the :~= function here since the last vector must be driven by the bitvector - this.endi := bundle.endi - this.stai := bundle.stai - this.strb := bundle.strb - // There are only last bits if there is dimensionality - if (d > 0) { - for ((lastLane, i) <- this.last.zipWithIndex) { - lastLane := bundle.last((i + 1) * d - 1, i * d) - } - } else { - this.last := DontCare - } - this.valid := bundle.valid - bundle.ready := this.ready // Connect data bitvector back to bundle for ((dataLane, i) <- this.data.zipWithIndex) { val dataWidth = bundle.elWidth From ec48f85f0a8e29540558722eb39acbbefe961cf7 Mon Sep 17 00:00:00 2001 From: Casper Cromjongh Date: Mon, 9 Sep 2024 16:22:16 +0200 Subject: [PATCH 29/29] Finishing touches to connect functions. Run formatting. --- .../nl/tudelft/tydi_chisel/TydiLib.scala | 27 ++++++++++++++++--- .../tydi_chisel/StreamCompatCheckTest.scala | 12 ++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala index 6497c2d..b4ae148 100644 --- a/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala +++ b/library/src/main/scala/nl/tudelft/tydi_chisel/TydiLib.scala @@ -420,8 +420,9 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val /** * Meta-connect function. Connects all metadata signals but not the data or user signals. * @param bundle Source stream to drive this stream with. + * @param compatCheckResult Whether to report stream compatibility issues as errors or warnings. */ - def :~=( + def :@=( bundle: PhysicalStreamBase )(implicit compatCheckResult: CompatCheckResult.Value = CompatCheckResult.Error): Unit = { paramCheck(bundle, compatCheckResult) @@ -448,18 +449,38 @@ sealed abstract class PhysicalStreamBase(private val e: TydiEl, val n: Int, val } } + /** + * Shortcut for stream mounting with weak type check. + * @param bundle Source stream to drive this stream with. + * @param errorReporting Whether to report stream compatibility issues as errors or warnings. + */ + def :~=( + bundle: PhysicalStreamBase + )(implicit errorReporting: CompatCheckResult.Value = CompatCheckResult.Error): Unit = { + implicit val errorReporting: CompatCheck.Value = CompatCheck.Params + this := bundle + } + + /** + * Stream mounting function. + * @param bundle Source stream to drive this stream with. + * @param errorReporting Whether to report stream compatibility issues as errors or warnings. + * @param typeCheck Whether to conduct a strong or weak type check. A weak type check only verifies the number of bits. + */ def :=(bundle: PhysicalStreamBase)(implicit typeCheck: CompatCheck.Value = CompatCheck.Strict, errorReporting: CompatCheckResult.Value = CompatCheckResult.Error ): Unit = { - this :~= bundle - elementCheckTyped(bundle, typeCheck, errorReporting) + this :@= bundle // Connect meta signals and check parameters + elementCheckTyped(bundle, typeCheck, errorReporting) // Check data types + // Call the right connect method (this, bundle) match { case (x: PhysicalStream, y: PhysicalStream) => x.connectSimple(y, typeCheck, errorReporting) case (x: PhysicalStream, y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck, errorReporting) case (x: PhysicalStreamDetailed[_, _], y: PhysicalStream) => x.connectSimple(y, typeCheck, errorReporting) case (x: PhysicalStreamDetailed[_, _], y: PhysicalStreamDetailed[_, _]) => x.connectDetailed(y, typeCheck, errorReporting) + case _ => throw new Exception("Could not determine data connection method.") } } diff --git a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala index 28d2dc2..d1676e1 100644 --- a/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala +++ b/testing/src/test/scala/nl/tudelft/tydi_chisel/StreamCompatCheckTest.scala @@ -22,7 +22,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { val outStream: PhysicalStream = IO(out) { - implicit val typeCheckImplicit: CompatCheck.Value = typeCheckSelect + implicit val typeCheckImplicit: CompatCheck.Value = typeCheckSelect implicit val typeCheckResultImplicit: CompatCheckResult.Value = errorReporting outStream := inStream } @@ -64,7 +64,13 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { it should "weak check type" in { test(new DetailedStreamConnectMod(myBundleStream, myBundle2Stream, CompatCheck.Params)) { _ => } - test(new StreamConnectMod(PhysicalStream(new MyBundle, c = 1), PhysicalStream(new MyBundle2, c = 1), CompatCheck.Params)) { _ => } + test( + new StreamConnectMod( + PhysicalStream(new MyBundle, c = 1), + PhysicalStream(new MyBundle2, c = 1), + CompatCheck.Params + ) + ) { _ => } } it should "check parameters" in { @@ -100,7 +106,7 @@ class StreamCompatCheckTest extends AnyFlatSpec with ChiselScalatestTester { new StreamConnectMod( baseStream, PhysicalStream(new MyBundle, n = 2, d = 1, c = 1, new DataBundle), - errorReporting=CompatCheckResult.Warning + errorReporting = CompatCheckResult.Warning ) ) { _ => } }