diff --git a/src/main/scala/amba/axis/Bundles.scala b/src/main/scala/amba/axis/Bundles.scala index be107726cab..c8a7832d8e2 100644 --- a/src/main/scala/amba/axis/Bundles.scala +++ b/src/main/scala/amba/axis/Bundles.scala @@ -18,10 +18,7 @@ case class AXISIdField (width: Int) extends SimpleBundleField(AXISId) (Output( case class AXISDestField(width: Int) extends SimpleBundleField(AXISDest)(Output(UInt(width.W)), 0.U) case class AXISKeepField(width: Int) extends SimpleBundleField(AXISKeep)(Output(UInt(width.W)), ~0.U(width.W)) case class AXISStrbField(width: Int) extends SimpleBundleField(AXISStrb)(Output(UInt(width.W)), ~0.U(width.W)) -case class AXISDataField(width: Int) extends BundleField(AXISData) { - def data = Output(UInt(width.W)) - def default(x: UInt): Unit = { x := DontCare } -} +case class AXISDataField(width: Int) extends BundleField[UInt](AXISData, Output(UInt(width.W)), _ := DontCare) class AXISBundleBits(val params: AXISBundleParameters) extends BundleMap(AXISBundle.keys(params)) { def last = if (params.hasLast) apply(AXISLast) else true.B diff --git a/src/main/scala/amba/package.scala b/src/main/scala/amba/package.scala index 11c9f5e1cea..2af015abd9b 100644 --- a/src/main/scala/amba/package.scala +++ b/src/main/scala/amba/package.scala @@ -17,23 +17,18 @@ package object amba { } case object AMBAProt extends ControlKey[AMBAProtBundle]("amba_prot") - case class AMBAProtField() extends BundleField(AMBAProt) { - def data = Output(new AMBAProtBundle) - def default(x: AMBAProtBundle): Unit = { - x.bufferable := false.B - x.modifiable := false.B - x.readalloc := false.B - x.writealloc := false.B - x.privileged := true.B - x.secure := true.B - x.fetch := false.B - } - } + + case class AMBAProtField() extends BundleField[AMBAProtBundle](AMBAProt, Output(new AMBAProtBundle), x => { + x.bufferable := false.B + x.modifiable := false.B + x.readalloc := false.B + x.writealloc := false.B + x.privileged := true.B + x.secure := true.B + x.fetch := false.B + }) // Used to convert a TileLink corrupt signal into an AMBA user bit case object AMBACorrupt extends DataKey[Bool]("corrupt") - case class AMBACorruptField() extends BundleField(AMBACorrupt) { - def data = Output(Bool()) - def default(x: Bool): Unit = { x := false.B } - } -} + case class AMBACorruptField() extends BundleField[Bool](AMBACorrupt, Output(Bool()), x => x := false.B) +} \ No newline at end of file diff --git a/src/main/scala/tilelink/RegisterRouter.scala b/src/main/scala/tilelink/RegisterRouter.scala index 76b6f6ad7dc..5a76cce107e 100644 --- a/src/main/scala/tilelink/RegisterRouter.scala +++ b/src/main/scala/tilelink/RegisterRouter.scala @@ -18,13 +18,10 @@ class TLRegisterRouterExtraBundle(val sourceBits: Int, val sizeBits: Int) extend } case object TLRegisterRouterExtra extends ControlKey[TLRegisterRouterExtraBundle]("tlrr_extra") -case class TLRegisterRouterExtraField(sourceBits: Int, sizeBits: Int) extends BundleField(TLRegisterRouterExtra) { - def data = Output(new TLRegisterRouterExtraBundle(sourceBits, sizeBits)) - def default(x: TLRegisterRouterExtraBundle) = { - x.size := 0.U - x.source := 0.U - } -} +case class TLRegisterRouterExtraField(sourceBits: Int, sizeBits: Int) extends BundleField[TLRegisterRouterExtraBundle](TLRegisterRouterExtra, Output(new TLRegisterRouterExtraBundle(sourceBits, sizeBits)), x => { + x.size := 0.U + x.source := 0.U +}) /** TLRegisterNode is a specialized TL SinkNode that encapsulates MMIO registers. * It provides functionality for describing and outputting metdata about the registers in several formats. diff --git a/src/main/scala/tilelink/ToAXI4.scala b/src/main/scala/tilelink/ToAXI4.scala index 92cc088516d..2c8ab84bb31 100644 --- a/src/main/scala/tilelink/ToAXI4.scala +++ b/src/main/scala/tilelink/ToAXI4.scala @@ -16,13 +16,10 @@ class AXI4TLStateBundle(val sourceBits: Int) extends Bundle { } case object AXI4TLState extends ControlKey[AXI4TLStateBundle]("tl_state") -case class AXI4TLStateField(sourceBits: Int) extends BundleField(AXI4TLState) { - def data = Output(new AXI4TLStateBundle(sourceBits)) - def default(x: AXI4TLStateBundle) = { - x.size := 0.U - x.source := 0.U - } -} +case class AXI4TLStateField(sourceBits: Int) extends BundleField[AXI4TLStateBundle](AXI4TLState, Output(new AXI4TLStateBundle(sourceBits)), x => { + x.size := 0.U + x.source := 0.U +}) /** TLtoAXI4IdMap serves as a record for the translation performed between id spaces. * diff --git a/src/main/scala/util/BundleMap.scala b/src/main/scala/util/BundleMap.scala index 5cae5fbf027..57dd5153043 100644 --- a/src/main/scala/util/BundleMap.scala +++ b/src/main/scala/util/BundleMap.scala @@ -2,9 +2,10 @@ package freechips.rocketchip.util import chisel3._ -import chisel3.experimental.DataMirror -import scala.collection.immutable.ListMap -import scala.collection.mutable.HashMap +import chisel3.reflect.DataMirror + +import scala.collection.immutable.SeqMap +import scala.collection.immutable.HashMap /* BundleMaps include IOs for every BundleField they are constructed with. * A given BundleField in a BundleMap is accessed by a BundleKey. @@ -35,21 +36,14 @@ sealed trait BundleFieldBase { } } -/* Always extends BundleField with a case class. - * This will ensure that there is an appropriate equals() operator to detect name conflicts. - */ -abstract class BundleField[T <: Data](val key: BundleKey[T]) extends BundleFieldBase -{ - def data: T - def default(x: T): Unit +abstract class BundleField[T <: Data](val key: BundleKey[T], typeT: => T, val default: T => Unit) extends BundleFieldBase { + def data: T = typeT + def defaultFlip(x: T): Unit = {} def setDataDefault(x: Data): Unit = default(x.asInstanceOf[T]) + def setDataDefaultFlip(x: Data): Unit = defaultFlip(x.asInstanceOf[T]) } -abstract class SimpleBundleField[T <: Data](key: BundleKey[T])(typeT: => T, defaultT: => T) extends BundleField(key) -{ - def data = typeT - def default(x: T): Unit = { x := defaultT } -} +abstract class SimpleBundleField[T <: Data](key: BundleKey[T])(typeT: => T, defaultT: => T) extends BundleField(key, typeT, { x: T => x := defaultT }) object BundleField { /* Consider an arbiter that receives two request streams A and B and combines them to C. @@ -100,11 +94,11 @@ abstract class DataKey [T <: Data](name: String) extends BundleKey[T](name) wi * Generally, this categorization belongs in different BundleMaps */ -class BundleMap(val fields: Seq[BundleFieldBase]) extends Record with CustomBulkAssignable { +class BundleMap(val fields: Seq[BundleFieldBase]) extends Record { // All fields must have distinct key.names require(fields.map(_.key.name).distinct.size == fields.size) - val elements: ListMap[String, Data] = ListMap(fields.map { bf => bf.key.name -> chisel3.experimental.DataMirror.internal.chiselTypeClone(bf.data) } :_*) + val elements: SeqMap[String, Data] = SeqMap(fields.map { bf => bf.key.name -> chisel3.reflect.DataMirror.internal.chiselTypeClone(bf.data) } :_*) // A BundleMap is best viewed as a map from BundleKey to Data def keydata: Seq[(BundleKeyBase, Data)] = (fields zip elements) map { case (field, (_, data)) => (field.key, data) } @@ -121,142 +115,45 @@ class BundleMap(val fields: Seq[BundleFieldBase]) extends Record with CustomBulk out :<= this out } - - // Assign all outputs of this from either: - // outputs of that (if they exist) - // or the default value for the BundleField - def assignL(that: CustomBulkAssignable): Unit = { // this/bx :<= that/by - require(that.isInstanceOf[BundleMap], s"Illegal attempt to drive BundleMap ${this} :<= non-BundleMap ${that}") - val bx = this - val by = that.asInstanceOf[BundleMap] - val hy = HashMap(by.elements.toList:_*) - (bx.fields zip bx.elements) foreach { case (field, (_, vx)) => - hy.lift(field.key.name) match { - case Some(vy) => FixChisel3.descendL(vx, vy) - case None => DataMirror.specifiedDirectionOf(vx) match { - case SpecifiedDirection.Output => field.setDataDefault(vx) - case SpecifiedDirection.Input => () - case _ => require(false, s"Attempt to assign ${bx} :<= ${by}, where RHS is missing directional field ${field}") - } - } - } - // it's ok to have excess elements in 'hy' - } - - // Assign all inputs of that from either: - // inputs of this (if they exist) - // or the default value for the BundleField - def assignR(that: CustomBulkAssignable): Unit = { // this/bx :=> that/by - require(that.isInstanceOf[BundleMap], s"Illegal attempt to drive BundleMap ${this} :=> non-BundleMap ${that}") - def bx = this - def by = that.asInstanceOf[BundleMap] - val hx = HashMap(bx.elements.toList:_*) - (by.fields zip by.elements) foreach { case (field, (_, vy)) => - hx.lift(field.key.name) match { - case Some(vx) => FixChisel3.descendR(vx, vy) - case None => DataMirror.specifiedDirectionOf(vy) match { - case SpecifiedDirection.Output => () - case SpecifiedDirection.Input => field.setDataDefault(vy) - case _ => require (false, s"Attempt to assign ${bx} :=> ${by}, where LHS is missing directional field ${field}") - } - } - } - // it's ok to have excess elements in 'hx' - } - - // Assign only those outputs of this which exist as outputs in that - def partialAssignL(that: BundleMap): Unit = { - val h = HashMap(that.keydata:_*) - keydata foreach { case (key, vx) => - h.lift(key).foreach { vy => FixChisel3.descendL(vx, vy) } - } - } - - // Assign only those inputs of that which exist as inputs in this - def partialAssignR(that: BundleMap): Unit = { - val h = HashMap(keydata:_*) - that.keydata foreach { case (key, vy) => - h.lift(key).foreach { vx => FixChisel3.descendL(vx, vy) } - } - } } object BundleMap { def apply(fields: Seq[BundleFieldBase] = Nil) = new BundleMap(fields) -} - -trait CustomBulkAssignable { - def assignL(that: CustomBulkAssignable): Unit // Custom implementation of :<= - def assignR(that: CustomBulkAssignable): Unit // Custom implementaiton of :=> -} - -// Implement the primitives of bulk assignment, :<= and :=> -object FixChisel3 { - // Used by :<= for child elements to switch directionality - def descendL(x: Data, y: Data): Unit = { - DataMirror.specifiedDirectionOf(x) match { - case SpecifiedDirection.Unspecified => assignL(x, y) - case SpecifiedDirection.Output => assignL(x, y); assignR(y, x) - case SpecifiedDirection.Input => () - case SpecifiedDirection.Flip => assignR(y, x) - } - } - - // Used by :=> for child elements to switch directionality - def descendR(x: Data, y: Data): Unit = { - DataMirror.specifiedDirectionOf(y) match { - case SpecifiedDirection.Unspecified => assignR(x, y) - case SpecifiedDirection.Output => () - case SpecifiedDirection.Input => assignL(y, x); assignR(x, y) - case SpecifiedDirection.Flip => assignL(y, x) + /** Sets the default values of all bundle map elements that are aligned w.r.t. d */ + def setAlignedDefaults[T <: Data](c: Connectable[T]): Connectable[T] = { + DataMirror.collectAlignedDeep(c.base) { case member: BundleMap => + member.fields.foreach { f => + f.setDataDefault(member.elements(f.key.name)) + } } + c } - - // The default implementation of 'x :<= y' - // Assign all output fields of x from y - def assignL(x: Data, y: Data): Unit = { - (x, y) match { - case (cx: CustomBulkAssignable, cy: CustomBulkAssignable) => cx.assignL(cy) - case (vx: Vec[_], vy: Vec[_]) => { - require (vx.size == vy.size, s"Assignment between vectors of unequal length (${vx.size} != ${vy.size})") - (vx zip vy) foreach { case (ex, ey) => descendL(ex, ey) } + /** Sets the default values of all bundle map elements that are flipped w.r.t. d */ + def setFlippedDefaults[T <: Data](c: Connectable[T]): Connectable[T] = { + DataMirror.collectFlippedDeep(c.base) { case member: BundleMap => + member.fields.foreach { f => + f.setDataDefault(member.elements(f.key.name)) } - case (rx: Record, ry: Record) => { - val hy = HashMap(ry.elements.toList:_*) - rx.elements.foreach { case (key, vx) => - require (hy.contains(key), s"Attempt to assign ${x} :<= ${y}, where RHS is missing field ${key}") - descendL(vx, hy(key)) - } - hy --= rx.elements.keys - require (hy.isEmpty, s"Attempt to assign ${x} :<= ${y}, where RHS has excess field ${hy.last._1}") - } - case (vx: Vec[_], DontCare) => vx.foreach { case ex => descendL(ex, DontCare) } - case (rx: Record, DontCare) => rx.elements.foreach { case (_, dx) => descendL(dx, DontCare) } - case _ => x := y // assign leaf fields (UInt/etc) } + c } - - // The default implementation of 'x :=> y' - // Assign all input fields of y from x - def assignR(x: Data, y: Data) = { - (x, y) match { - case (cx: CustomBulkAssignable, cy: CustomBulkAssignable) => cx.assignR(cy) - case (vx: Vec[_], vy: Vec[_]) => { - require (vx.size == vy.size, s"Assignment between vectors of unequal length (${vx.size} != ${vy.size})") - (vx zip vy) foreach { case (ex, ey) => descendR(ex, ey) } + /** Waives all bundle map elements */ + def waive[T <: Data](c: Connectable[T]): Connectable[T] = { + val bundleFields = DataMirror + .collectMembers(c.base) { case member: BundleMap => + member.getElements } - case (rx: Record, ry: Record) => { - val hx = HashMap(rx.elements.toList:_*) - ry.elements.foreach { case (key, vy) => - require (hx.contains(key), s"Attempt to assign ${x} :=> ${y}, where RHS has excess field ${key}") - descendR(hx(key), vy) - } - hx --= ry.elements.keys - require (hx.isEmpty, s"Attempt to assign ${x} :=> ${y}, where RHS is missing field ${hx.last._1}") - } - case (DontCare, vy: Vec[_]) => vy.foreach { case ey => descendR(DontCare, ey) } - case (DontCare, ry: Record) => ry.elements.foreach { case (_, dy) => descendR(DontCare, dy) } - case _ => // no-op for leaf fields - } + .flatten + Connectable(c.base, bundleFields.toSet) + } + /** Waives all bundle map elements and sets the default values of all bundle map elements that are aligned w.r.t. d */ + def waiveAndSetAlignedDefaults[T <: Data](c: Connectable[T]): Connectable[T] = { + setAlignedDefaults(c) + waive(c) + } + /** Waives all bundle map elements and sets the default values of all bundle map elements that are flipped w.r.t. d */ + def waiveAndSetFlippedDefaults[T <: Data](c: Connectable[T]): Connectable[T] = { + setFlippedDefaults(c) + waive(c) } }