diplomacy: make flexible-port adapters possible
This commit is contained in:
		| @@ -143,15 +143,18 @@ trait OutwardNode[DO, UO, BO <: Data] extends BaseNode with OutwardNodeHandle[DO | |||||||
|   val bundleOut: Vec[BO] |   val bundleOut: Vec[BO] | ||||||
| } | } | ||||||
|  |  | ||||||
| class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | ||||||
|   inner: InwardNodeImp [DI, UI, EI, BI], |   inner: InwardNodeImp [DI, UI, EI, BI], | ||||||
|   outer: OutwardNodeImp[DO, UO, EO, BO])( |   outer: OutwardNodeImp[DO, UO, EO, BO])( | ||||||
|   private val dFn: (Int, Seq[DI]) => Seq[DO], |  | ||||||
|   private val uFn: (Int, Seq[UO]) => Seq[UI], |  | ||||||
|   protected[diplomacy] val numPO: Range.Inclusive, |   protected[diplomacy] val numPO: Range.Inclusive, | ||||||
|   protected[diplomacy] val numPI: Range.Inclusive) |   protected[diplomacy] val numPI: Range.Inclusive) | ||||||
|   extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] |   extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] | ||||||
| { | { | ||||||
|  |   protected[diplomacy] def resolveStarO(i: Int, o: Int): Int | ||||||
|  |   protected[diplomacy] def resolveStarI(i: Int, o: Int): Int | ||||||
|  |   protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] | ||||||
|  |   protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] | ||||||
|  |  | ||||||
|   protected[diplomacy] lazy val (oPortMapping, iPortMapping, oStar, iStar) = { |   protected[diplomacy] lazy val (oPortMapping, iPortMapping, oStar, iStar) = { | ||||||
|     val oStars = oBindings.filter { case (_,_,b) => b == BIND_STAR }.size |     val oStars = oBindings.filter { case (_,_,b) => b == BIND_STAR }.size | ||||||
|     val iStars = iBindings.filter { case (_,_,b) => b == BIND_STAR }.size |     val iStars = iBindings.filter { case (_,_,b) => b == BIND_STAR }.size | ||||||
| @@ -164,10 +167,8 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | |||||||
|       case BIND_ONCE  => 1 |       case BIND_ONCE  => 1 | ||||||
|       case BIND_QUERY => n.oStar |       case BIND_QUERY => n.oStar | ||||||
|       case BIND_STAR  => 0 }}.foldLeft(0)(_+_) |       case BIND_STAR  => 0 }}.foldLeft(0)(_+_) | ||||||
|     val oStar = iKnown - oKnown |     val oStar = if (oStars > 0) resolveStarO(iKnown, oKnown) else 0 | ||||||
|     val iStar = -oStar |     val iStar = if (iStars > 0) resolveStarI(iKnown, oKnown) else 0 | ||||||
|     require (oStars == 0 || oStar >= 0, s"${name} has ${oKnown} outputs and ${iKnown} inputs; cannot assign ${oStar} edges to resolve :=*${lazyModule.line}") |  | ||||||
|     require (iStars == 0 || iStar >= 0, s"${name} has ${oKnown} outputs and ${iKnown} inputs; cannot assign ${iStar} edges to resolve :*=${lazyModule.line}") |  | ||||||
|     val oSum = oBindings.map { case (_, n, b) => b match { |     val oSum = oBindings.map { case (_, n, b) => b match { | ||||||
|       case BIND_ONCE  => 1 |       case BIND_ONCE  => 1 | ||||||
|       case BIND_QUERY => n.iStar |       case BIND_QUERY => n.iStar | ||||||
| @@ -192,15 +193,14 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | |||||||
|     (start until end) map { j => (j, n) } |     (start until end) map { j => (j, n) } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}") |  | ||||||
|   protected[diplomacy] lazy val oParams: Seq[DO] = { |   protected[diplomacy] lazy val oParams: Seq[DO] = { | ||||||
|     val o = dFn(oPorts.size, iPorts.map { case (i, n) => n.oParams(i) }) |     val o = mapParamsD(oPorts.size, iPorts.map { case (i, n) => n.oParams(i) }) | ||||||
|     reqE(oPorts.size, o.size) |     require (o.size == oPorts.size, s"Bug in diplomacy; ${name} has ${o.size} != ${oPorts.size} down/up outer parameters${lazyModule.line}") | ||||||
|     o.map(outer.mixO(_, this)) |     o.map(outer.mixO(_, this)) | ||||||
|   } |   } | ||||||
|   protected[diplomacy] lazy val iParams: Seq[UI] = { |   protected[diplomacy] lazy val iParams: Seq[UI] = { | ||||||
|     val i = uFn(iPorts.size, oPorts.map { case (o, n) => n.iParams(o) }) |     val i = mapParamsU(iPorts.size, oPorts.map { case (o, n) => n.iParams(o) }) | ||||||
|     reqE(i.size, iPorts.size) |     require (i.size == iPorts.size, s"Bug in diplomacy; ${name} has ${i.size} != ${iPorts.size} up/down inner parameters${lazyModule.line}") | ||||||
|     i.map(inner.mixI(_, this)) |     i.map(inner.mixI(_, this)) | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -256,72 +256,139 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | |||||||
|   protected[diplomacy] def inputs  = iPorts.map(_._2) zip edgesIn .map(e => inner.labelI(e)) |   protected[diplomacy] def inputs  = iPorts.map(_._2) zip edgesIn .map(e => inner.labelI(e)) | ||||||
| } | } | ||||||
|  |  | ||||||
| class SimpleNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( | class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | ||||||
|   oFn: (Int, Seq[D]) => Seq[D], |   inner: InwardNodeImp [DI, UI, EI, BI], | ||||||
|   iFn: (Int, Seq[U]) => Seq[U], |   outer: OutwardNodeImp[DO, UO, EO, BO])( | ||||||
|   numPO: Range.Inclusive, |   dFn: DI => DO, | ||||||
|   numPI: Range.Inclusive) |   uFn: UO => UI, | ||||||
|     extends MixedNode[D, U, EI, B, D, U, EO, B](imp, imp)(oFn, iFn, numPO, numPI) |   num: Range.Inclusive = 0 to 999) | ||||||
|  |   extends MixedNode(inner, outer)(num, num) | ||||||
|  | { | ||||||
|  |   protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = { | ||||||
|  |     require (i >= o, s"${name} has ${o} outputs and ${i} inputs; cannot assign ${i-o} edges to resolve :=*${lazyModule.line}") | ||||||
|  |     i - o | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = { | ||||||
|  |     require (o >= i, s"${name} has ${o} outputs and ${i} inputs; cannot assign ${o-i} edges to resolve :*=${lazyModule.line}") | ||||||
|  |     o - i | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { | ||||||
|  |     require(n == p.size, s"${name} has ${p.size} inputs and ${n} outputs; they must match${lazyModule.line}") | ||||||
|  |     p.map(dFn) | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { | ||||||
|  |     require(n == p.size, s"${name} has ${n} inputs and ${p.size} outputs; they must match${lazyModule.line}") | ||||||
|  |     p.map(uFn) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) | class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | ||||||
|   extends SimpleNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999) |   inner: InwardNodeImp [DI, UI, EI, BI], | ||||||
|  |   outer: OutwardNodeImp[DO, UO, EO, BO])( | ||||||
|  |   dFn: Seq[DI] => DO, | ||||||
|  |   uFn: Seq[UO] => UI, | ||||||
|  |   numPO: Range.Inclusive = 1 to 999, | ||||||
|  |   numPI: Range.Inclusive = 1 to 999) | ||||||
|  |   extends MixedNode(inner, outer)(numPO, numPI) | ||||||
|  | { | ||||||
|  |   require (numPO.end >= 1, s"${name} does not accept outputs${lazyModule.line}") | ||||||
|  |   require (numPI.end >= 1, s"${name} does not accept inputs${lazyModule.line}") | ||||||
|  |   protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = { | ||||||
|  |     require (false, "${name} cannot resolve :=*${lazyModule.line}") | ||||||
|  |     0 | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = { | ||||||
|  |     require (false, s"${name} cannot resolve :*=${lazyModule.line}") | ||||||
|  |     0 | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = Seq.fill(n) { dFn(p) } | ||||||
|  |   protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = Seq.fill(n) { uFn(p) } | ||||||
|  | } | ||||||
|  |  | ||||||
| class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) | class AdapterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( | ||||||
|  |   dFn: D => D, | ||||||
|  |   uFn: U => U, | ||||||
|  |   num: Range.Inclusive = 0 to 999) | ||||||
|  |     extends MixedAdapterNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, num) | ||||||
|  |  | ||||||
|  | class NexusNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( | ||||||
|  |   dFn: Seq[D] => D, | ||||||
|  |   uFn: Seq[U] => U, | ||||||
|  |   numPO: Range.Inclusive = 1 to 999, | ||||||
|  |   numPI: Range.Inclusive = 1 to 999) | ||||||
|  |     extends MixedNexusNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, numPO, numPI) | ||||||
|  |  | ||||||
|  | class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B]) | ||||||
|  |   extends AdapterNode(imp)({s => s}, {s => s}) | ||||||
|  |  | ||||||
|  | class OutputNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B]) extends IdentityNode(imp) | ||||||
| { | { | ||||||
|   override lazy val bundleIn = bundleOut |   override lazy val bundleIn = bundleOut | ||||||
| } | } | ||||||
|  |  | ||||||
| class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) | class InputNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B]) extends IdentityNode(imp) | ||||||
| { | { | ||||||
|   override lazy val bundleOut = bundleIn |   override lazy val bundleOut = bundleIn | ||||||
| } | } | ||||||
|  |  | ||||||
| class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1) | class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D]) | ||||||
|   extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0) |   extends MixedNode(imp, imp)(po.size to po.size, 0 to 0) | ||||||
| { | { | ||||||
|   require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}") |   protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = { | ||||||
|  |     require (po.size >= o, s"${name} has ${o} outputs out of ${po.size}; cannot assign ${po.size - o} edges to resolve :=*${lazyModule.line}") | ||||||
|  |     po.size - o | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = { | ||||||
|  |     require (false, s"${name} cannot resolve :*=${lazyModule.line}") | ||||||
|  |     0 | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = po | ||||||
|  |   protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = Seq() | ||||||
|  |  | ||||||
|   override lazy val bundleIn = { require(false, s"${name} has no bundleIn; try bundleOut?"); bundleOut } |   override lazy val bundleIn = { require(false, s"${name} has no bundleIn; try bundleOut?"); bundleOut } | ||||||
| } | } | ||||||
|  |  | ||||||
| class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1) | class SinkNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U]) | ||||||
|   extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num) |   extends MixedNode(imp, imp)(0 to 0, pi.size to pi.size) | ||||||
| { | { | ||||||
|   require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}") |   protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = { | ||||||
|  |     require (false, s"${name} cannot resolve :=*${lazyModule.line}") | ||||||
|  |     0 | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = { | ||||||
|  |     require (pi.size >= i, s"${name} has ${i} inputs out of ${pi.size}; cannot assign ${pi.size - i} edges to resolve :*=${lazyModule.line}") | ||||||
|  |     pi.size - i | ||||||
|  |   } | ||||||
|  |   protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = Seq() | ||||||
|  |   protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = pi | ||||||
|  |  | ||||||
|   override lazy val bundleOut = { require(false, s"${name} has no bundleOut; try bundleIn?"); bundleIn } |   override lazy val bundleOut = { require(false, s"${name} has no bundleOut; try bundleIn?"); bundleIn } | ||||||
| } | } | ||||||
|  |  | ||||||
| class BlindOutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: Seq[PI]) | class BlindOutputNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U]) | ||||||
|   extends SimpleNode(imp)({case (0, _) => Seq()}, {case (_, Seq()) => pi}, 0 to 0, pi.size to pi.size) |   extends SinkNode(imp)(pi) | ||||||
| { | { | ||||||
|   override val flip = true |   override val flip = true | ||||||
|   override lazy val bundleOut = bundleIn |   override lazy val bundleOut = bundleIn | ||||||
| } | } | ||||||
|  |  | ||||||
| class BlindInputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: Seq[PO]) | class BlindInputNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D]) | ||||||
|   extends SimpleNode(imp)({case (_, Seq()) => po}, {case (0, _) => Seq()}, po.size to po.size, 0 to 0) |   extends SourceNode(imp)(po) | ||||||
| { | { | ||||||
|   override val flip = true |   override val flip = true | ||||||
|   override lazy val bundleIn = bundleOut |   override lazy val bundleIn = bundleOut | ||||||
| } | } | ||||||
|  |  | ||||||
| class InternalOutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: Seq[PI]) | class InternalOutputNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U]) | ||||||
|   extends SimpleNode(imp)({case (0, _) => Seq()}, {case (_, Seq()) => pi}, 0 to 0, pi.size to pi.size) |   extends SinkNode(imp)(pi) | ||||||
| { | { | ||||||
|   override val wire = true |   override val wire = true | ||||||
|   override lazy val bundleOut = bundleIn |   override lazy val bundleOut = bundleIn | ||||||
| } | } | ||||||
|  |  | ||||||
| class InternalInputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: Seq[PO]) | class InternalInputNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D]) | ||||||
|   extends SimpleNode(imp)({case (_, Seq()) => po}, {case (0, _) => Seq()}, po.size to po.size, 0 to 0) |   extends SourceNode(imp)(po) | ||||||
| { | { | ||||||
|   override val wire = true |   override val wire = true | ||||||
|   override lazy val bundleIn = bundleOut |   override lazy val bundleIn = bundleOut | ||||||
| } | } | ||||||
|  |  | ||||||
| class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) |  | ||||||
|   (oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive) |  | ||||||
|   extends SimpleNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI) |  | ||||||
| { |  | ||||||
|   require (numPO.end >= 1, s"${name} is an adapter which does not accept outputs${lazyModule.line}") |  | ||||||
|   require (numPI.end >= 1, s"${name} is an adapter which does not accept inputs${lazyModule.line}") |  | ||||||
| } |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user