2016-11-28 01:16:37 +01:00
// See LICENSE.SiFive for license details.
2016-10-04 00:17:36 +02:00
2017-07-07 19:48:16 +02:00
package freechips.rocketchip.diplomacy
2016-10-04 00:17:36 +02:00
import Chisel._
import chisel3.internal.sourceinfo.SourceInfo
2017-09-07 00:30:25 +02:00
import freechips.rocketchip.config. { Parameters , Field }
2017-07-07 19:48:16 +02:00
import freechips.rocketchip.util.HeterogeneousBag
import scala.collection.mutable.ListBuffer
2017-09-26 02:49:45 +02:00
import scala.util.matching._
2016-10-04 00:17:36 +02:00
2017-09-07 00:30:25 +02:00
object CardinalityInferenceDirection {
val cases = Seq ( SOURCE_TO_SINK , SINK_TO_SOURCE , NO_INFERENCE )
sealed trait T {
def flip = this match {
case SOURCE_TO_SINK => SINK_TO_SOURCE
case SINK_TO_SOURCE => SOURCE_TO_SINK
case NO_INFERENCE => NO_INFERENCE
}
}
case object SOURCE_TO_SINK extends T
case object SINK_TO_SOURCE extends T
case object NO_INFERENCE extends T
}
2017-09-07 23:25:33 +02:00
private case object CardinalityInferenceDirectionKey extends
2017-09-07 22:33:07 +02:00
Field [ CardinalityInferenceDirection . T ] ( CardinalityInferenceDirection . NO_INFERENCE )
2017-09-07 00:30:25 +02:00
2017-09-27 09:57:18 +02:00
case object MonitorsEnabled extends Field [ Boolean ] ( true )
case object RenderFlipped extends Field [ Boolean ] ( false )
2017-09-26 22:23:54 +02:00
case class RenderedEdge (
colour : String ,
label : String = "" ,
flipped : Boolean = false ) // prefer to draw the arrow pointing the opposite direction of other edges
2017-09-07 23:25:33 +02:00
2016-10-04 00:17:36 +02:00
// DI = Downwards flowing Parameters received on the inner side of the node
// UI = Upwards flowing Parameters generated by the inner side of the node
// EI = Edge Parameters describing a connection on the inner side of the node
// BI = Bundle type used when connecting to the inner side of the node
trait InwardNodeImp [ DI , UI , EI , BI <: Data ]
{
2017-09-23 07:23:58 +02:00
def edgeI ( pd : DI , pu : UI , p : Parameters , sourceInfo : SourceInfo ) : EI
2017-02-23 02:05:22 +01:00
def bundleI ( ei : EI ) : BI
2017-09-26 22:23:54 +02:00
// Edge functions
2017-09-23 01:55:12 +02:00
def monitor ( bundle : BI , edge : EI ) { }
2017-09-26 22:23:54 +02:00
def render ( e : EI ) : RenderedEdge
2016-10-15 01:18:57 +02:00
// optional methods to track node graph
def mixI ( pu : UI , node : InwardNode [ DI , UI , BI ] ) : UI = pu // insert node into parameters
def getO ( pu : UI ) : Option [ BaseNode ] = None // most-outward common node
2016-10-04 00:17:36 +02:00
}
2016-10-15 01:18:57 +02:00
// DO = Downwards flowing Parameters generated by the outer side of the node
// UO = Upwards flowing Parameters received on the outer side of the node
2016-10-04 00:17:36 +02:00
// EO = Edge Parameters describing a connection on the outer side of the node
// BO = Bundle type used when connecting to the outer side of the node
trait OutwardNodeImp [ DO , UO , EO , BO <: Data ]
{
2017-09-23 07:23:58 +02:00
def edgeO ( pd : DO , pu : UO , p : Parameters , sourceInfo : SourceInfo ) : EO
2017-02-23 02:05:22 +01:00
def bundleO ( eo : EO ) : BO
2016-10-15 01:18:57 +02:00
// optional methods to track node graph
def mixO ( pd : DO , node : OutwardNode [ DO , UO , BO ] ) : DO = pd // insert node into parameters
def getI ( pd : DO ) : Option [ BaseNode ] = None // most-inward common node
2016-10-04 00:17:36 +02:00
}
abstract class NodeImp [ D , U , EO , EI , B <: Data ]
extends Object with InwardNodeImp [ D , U , EI , B ] with OutwardNodeImp [ D , U , EO , B ]
2017-09-26 21:28:59 +02:00
// If your edges have the same direction, using this saves you some typing
abstract class SimpleNodeImp [ D , U , E , B <: Data ]
extends NodeImp [ D , U , E , E , B ]
{
def edge ( pd : D , pu : U , p : Parameters , sourceInfo : SourceInfo ) : E
def edgeO ( pd : D , pu : U , p : Parameters , sourceInfo : SourceInfo ) = edge ( pd , pu , p , sourceInfo )
def edgeI ( pd : D , pu : U , p : Parameters , sourceInfo : SourceInfo ) = edge ( pd , pu , p , sourceInfo )
def bundle ( e : E ) : B
def bundleO ( e : E ) = bundle ( e )
def bundleI ( e : E ) = bundle ( e )
}
2017-09-12 08:33:44 +02:00
abstract class BaseNode ( implicit val valName : ValName )
2016-10-04 00:17:36 +02:00
{
2017-09-26 23:56:50 +02:00
require ( LazyModule . scope . isDefined , "You cannot create a node outside a LazyModule!" )
2016-10-04 00:17:36 +02:00
2017-09-26 23:56:50 +02:00
val lazyModule = LazyModule . scope . get
2016-10-04 00:17:36 +02:00
val index = lazyModule . nodes . size
lazyModule . nodes = this : : lazyModule.nodes
2017-09-14 03:06:03 +02:00
val serial = BaseNode . serial
BaseNode . serial = BaseNode . serial + 1
protected [ diplomacy ] def instantiate ( ) : Seq [ Dangle ]
2017-02-10 19:19:22 +01:00
2017-09-14 03:06:03 +02:00
def name = lazyModule . name + "." + valName . name
2016-10-04 00:17:36 +02:00
def omitGraphML = outputs . isEmpty && inputs . isEmpty
2017-04-14 23:21:22 +02:00
lazy val nodedebugstring : String = ""
2016-10-04 00:17:36 +02:00
2017-09-26 02:49:45 +02:00
def wirePrefix = {
val camelCase = "([a-z])([A-Z])" . r
val decamel = camelCase . replaceAllIn ( valName . name , _ match { case camelCase ( l , h ) => l + "_" + h } )
val trimNode = "_?node$" . r
val name = trimNode . replaceFirstIn ( decamel . toLowerCase , "" )
if ( name . isEmpty ) "" else name + "_"
}
2016-10-15 01:18:57 +02:00
protected [ diplomacy ] def gci : Option [ BaseNode ] // greatest common inner
protected [ diplomacy ] def gco : Option [ BaseNode ] // greatest common outer
2017-09-26 22:23:54 +02:00
protected [ diplomacy ] def inputs : Seq [ ( BaseNode , RenderedEdge ) ]
protected [ diplomacy ] def outputs : Seq [ ( BaseNode , RenderedEdge ) ]
2016-10-04 00:17:36 +02:00
}
2017-09-14 03:06:03 +02:00
object BaseNode
{
protected [ diplomacy ] var serial = 0
}
2017-09-15 23:44:07 +02:00
// !!! rename the nodes we bind?
2016-10-08 08:35:20 +02:00
case class NodeHandle [ DI , UI , BI <: Data , DO , UO , BO <: Data ]
2017-09-27 03:47:16 +02:00
( inwardHandle : InwardNodeHandle [ DI , UI , BI ] , outwardHandle : OutwardNodeHandle [ DO , UO , BO ] )
2016-10-08 08:35:20 +02:00
extends Object with InwardNodeHandle [ DI , UI , BI ] with OutwardNodeHandle [ DO , UO , BO ]
2017-09-27 03:47:16 +02:00
{
val inward = inwardHandle . inward
val outward = outwardHandle . outward
}
2016-10-08 08:35:20 +02:00
trait InwardNodeHandle [ DI , UI , BI <: Data ]
2016-10-04 00:17:36 +02:00
{
2017-09-07 23:33:09 +02:00
protected [ diplomacy ] val inward : InwardNode [ DI , UI , BI ]
2017-09-23 01:55:12 +02:00
def : = ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) { inward . : = ( h ) ( p , sourceInfo ) }
def : *= ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) { inward . : *= ( h ) ( p , sourceInfo ) }
def : = * ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) { inward . : = * ( h ) ( p , sourceInfo ) }
def : = ? ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) { inward . : = ? ( h ) ( p , sourceInfo ) }
2016-10-08 08:35:20 +02:00
}
2017-01-29 06:20:34 +01:00
sealed trait NodeBinding
case object BIND_ONCE extends NodeBinding
case object BIND_QUERY extends NodeBinding
case object BIND_STAR extends NodeBinding
2016-10-08 08:35:20 +02:00
trait InwardNode [ DI , UI , BI <: Data ] extends BaseNode with InwardNodeHandle [ DI , UI , BI ]
{
2017-09-07 23:33:09 +02:00
protected [ diplomacy ] val inward = this
2016-10-08 08:35:20 +02:00
2016-10-04 00:17:36 +02:00
protected [ diplomacy ] val numPI : Range.Inclusive
require ( ! numPI . isEmpty , s" No number of inputs would be acceptable to ${ name } ${ lazyModule . line } " )
require ( numPI . start >= 0 , s" ${ name } accepts a negative number of inputs ${ lazyModule . line } " )
2017-09-23 07:23:58 +02:00
private val accPI = ListBuffer [ ( Int , OutwardNode [ DI , UI , BI ] , NodeBinding , Parameters , SourceInfo ) ] ( )
2016-10-04 00:17:36 +02:00
private var iRealized = false
protected [ diplomacy ] def iPushed = accPI . size
2017-09-07 23:56:09 +02:00
protected [ diplomacy ] def iPush ( index : Int , node : OutwardNode [ DI , UI , BI ] , binding : NodeBinding ) ( implicit p : Parameters , sourceInfo : SourceInfo ) {
2016-10-04 00:17:36 +02:00
val info = sourceLine ( sourceInfo , " at " , "" )
val noIs = numPI . size == 1 && numPI . contains ( 0 )
require ( ! noIs , s" ${ name } ${ lazyModule . line } was incorrectly connected as a sink " + info )
2017-09-22 23:57:36 +02:00
require ( ! iRealized , s" ${ name } ${ lazyModule . line } was incorrectly connected as a sink after its .module was used " + info )
2017-09-23 07:23:58 +02:00
accPI += ( ( index , node , binding , p , sourceInfo ) )
2016-10-04 00:17:36 +02:00
}
2017-01-29 06:20:34 +01:00
protected [ diplomacy ] lazy val iBindings = { iRealized = true ; accPI . result ( ) }
2016-10-04 00:17:36 +02:00
2017-01-29 06:20:34 +01:00
protected [ diplomacy ] val iStar : Int
protected [ diplomacy ] val iPortMapping : Seq [ ( Int , Int ) ]
2016-10-04 00:17:36 +02:00
protected [ diplomacy ] val iParams : Seq [ UI ]
}
2016-10-08 08:35:20 +02:00
trait OutwardNodeHandle [ DO , UO , BO <: Data ]
2016-10-04 00:17:36 +02:00
{
2017-09-07 23:33:09 +02:00
protected [ diplomacy ] val outward : OutwardNode [ DO , UO , BO ]
2016-10-08 08:35:20 +02:00
}
trait OutwardNode [ DO , UO , BO <: Data ] extends BaseNode with OutwardNodeHandle [ DO , UO , BO ]
{
2017-09-07 23:33:09 +02:00
protected [ diplomacy ] val outward = this
2016-10-08 08:35:20 +02:00
2016-10-04 00:17:36 +02:00
protected [ diplomacy ] val numPO : Range.Inclusive
require ( ! numPO . isEmpty , s" No number of outputs would be acceptable to ${ name } ${ lazyModule . line } " )
require ( numPO . start >= 0 , s" ${ name } accepts a negative number of outputs ${ lazyModule . line } " )
2017-09-23 07:23:58 +02:00
private val accPO = ListBuffer [ ( Int , InwardNode [ DO , UO , BO ] , NodeBinding , Parameters , SourceInfo ) ] ( )
2016-10-04 00:17:36 +02:00
private var oRealized = false
protected [ diplomacy ] def oPushed = accPO . size
2017-09-07 23:56:09 +02:00
protected [ diplomacy ] def oPush ( index : Int , node : InwardNode [ DO , UO , BO ] , binding : NodeBinding ) ( implicit p : Parameters , sourceInfo : SourceInfo ) {
2016-10-04 00:17:36 +02:00
val info = sourceLine ( sourceInfo , " at " , "" )
val noOs = numPO . size == 1 && numPO . contains ( 0 )
require ( ! noOs , s" ${ name } ${ lazyModule . line } was incorrectly connected as a source " + info )
2017-09-22 23:57:36 +02:00
require ( ! oRealized , s" ${ name } ${ lazyModule . line } was incorrectly connected as a source after its .module was used " + info )
2017-09-23 07:23:58 +02:00
accPO += ( ( index , node , binding , p , sourceInfo ) )
2016-10-04 00:17:36 +02:00
}
2017-01-29 06:20:34 +01:00
protected [ diplomacy ] lazy val oBindings = { oRealized = true ; accPO . result ( ) }
2016-10-04 00:17:36 +02:00
2017-01-29 06:20:34 +01:00
protected [ diplomacy ] val oStar : Int
protected [ diplomacy ] val oPortMapping : Seq [ ( Int , Int ) ]
2016-10-04 00:17:36 +02:00
protected [ diplomacy ] val oParams : Seq [ DO ]
}
2017-09-15 23:44:07 +02:00
case class Edges [ EI , EO ] ( in : EI , out : EO )
2017-09-14 03:06:03 +02:00
sealed abstract class MixedNode [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ] (
2016-10-04 00:17:36 +02:00
inner : InwardNodeImp [ DI , UI , EI , BI ] ,
outer : OutwardNodeImp [ DO , UO , EO , BO ] ) (
protected [ diplomacy ] val numPO : Range . Inclusive ,
2017-09-12 08:33:44 +02:00
protected [ diplomacy ] val numPI : Range . Inclusive ) (
implicit valName : ValName )
2016-10-04 00:17:36 +02:00
extends BaseNode with InwardNode [ DI , UI , BI ] with OutwardNode [ DO , UO , BO ]
{
2017-05-19 21:52:01 +02:00
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStar : Int , oStar : Int ) : ( Int , Int )
2017-01-29 22:55:53 +01:00
protected [ diplomacy ] def mapParamsD ( n : Int , p : Seq [ DI ] ) : Seq [ DO ]
protected [ diplomacy ] def mapParamsU ( n : Int , p : Seq [ UO ] ) : Seq [ UI ]
2017-01-29 06:20:34 +01:00
protected [ diplomacy ] lazy val ( oPortMapping , iPortMapping , oStar , iStar ) = {
2017-09-23 07:23:58 +02:00
val oStars = oBindings . filter { case ( _ , _ , b , _ , _ ) => b == BIND_STAR } . size
val iStars = iBindings . filter { case ( _ , _ , b , _ , _ ) => b == BIND_STAR } . size
val oKnown = oBindings . map { case ( _ , n , b , _ , _ ) => b match {
2017-01-29 06:20:34 +01:00
case BIND_ONCE => 1
case BIND_QUERY => n . iStar
case BIND_STAR => 0 } } . foldLeft ( 0 ) ( _ + _ )
2017-09-23 07:23:58 +02:00
val iKnown = iBindings . map { case ( _ , n , b , _ , _ ) => b match {
2017-01-29 06:20:34 +01:00
case BIND_ONCE => 1
case BIND_QUERY => n . oStar
case BIND_STAR => 0 } } . foldLeft ( 0 ) ( _ + _ )
2017-05-19 21:52:01 +02:00
val ( iStar , oStar ) = resolveStar ( iKnown , oKnown , iStars , oStars )
2017-09-23 07:23:58 +02:00
val oSum = oBindings . map { case ( _ , n , b , _ , _ ) => b match {
2017-01-29 06:20:34 +01:00
case BIND_ONCE => 1
case BIND_QUERY => n . iStar
case BIND_STAR => oStar } } . scanLeft ( 0 ) ( _ + _ )
2017-09-23 07:23:58 +02:00
val iSum = iBindings . map { case ( _ , n , b , _ , _ ) => b match {
2017-01-29 06:20:34 +01:00
case BIND_ONCE => 1
case BIND_QUERY => n . oStar
case BIND_STAR => iStar } } . scanLeft ( 0 ) ( _ + _ )
val oTotal = oSum . lastOption . getOrElse ( 0 )
val iTotal = iSum . lastOption . getOrElse ( 0 )
require ( numPO . contains ( oTotal ) , s" ${ name } has ${ oTotal } outputs, expected ${ numPO } ${ lazyModule . line } " )
require ( numPI . contains ( iTotal ) , s" ${ name } has ${ iTotal } inputs, expected ${ numPI } ${ lazyModule . line } " )
( oSum . init zip oSum . tail , iSum . init zip iSum . tail , oStar , iStar )
}
2017-09-23 07:23:58 +02:00
lazy val oPorts = oBindings . flatMap { case ( i , n , _ , p , s ) =>
2017-01-29 06:20:34 +01:00
val ( start , end ) = n . iPortMapping ( i )
2017-09-23 07:23:58 +02:00
( start until end ) map { j => ( j , n , p , s ) }
2017-01-29 06:20:34 +01:00
}
2017-09-23 07:23:58 +02:00
lazy val iPorts = iBindings . flatMap { case ( i , n , _ , p , s ) =>
2017-01-29 06:20:34 +01:00
val ( start , end ) = n . oPortMapping ( i )
2017-09-23 07:23:58 +02:00
( start until end ) map { j => ( j , n , p , s ) }
2017-01-29 06:20:34 +01:00
}
2016-10-04 00:17:36 +02:00
protected [ diplomacy ] lazy val oParams : Seq [ DO ] = {
2017-09-23 07:23:58 +02:00
val o = mapParamsD ( oPorts . size , iPorts . map { case ( i , n , _ , _ ) => n . oParams ( i ) } )
2017-01-29 22:55:53 +01:00
require ( o . size == oPorts . size , s" Bug in diplomacy; ${ name } has ${ o . size } != ${ oPorts . size } down/up outer parameters ${ lazyModule . line } " )
2016-10-04 00:17:36 +02:00
o . map ( outer . mixO ( _ , this ) )
}
protected [ diplomacy ] lazy val iParams : Seq [ UI ] = {
2017-09-23 07:23:58 +02:00
val i = mapParamsU ( iPorts . size , oPorts . map { case ( o , n , _ , _ ) => n . iParams ( o ) } )
2017-01-29 22:55:53 +01:00
require ( i . size == iPorts . size , s" Bug in diplomacy; ${ name } has ${ i . size } != ${ iPorts . size } up/down inner parameters ${ lazyModule . line } " )
2016-10-04 00:17:36 +02:00
i . map ( inner . mixI ( _ , this ) )
}
2016-10-15 01:18:57 +02:00
protected [ diplomacy ] def gco = if ( iParams . size != 1 ) None else inner . getO ( iParams ( 0 ) )
protected [ diplomacy ] def gci = if ( oParams . size != 1 ) None else outer . getI ( oParams ( 0 ) )
2017-09-23 07:23:58 +02:00
protected [ diplomacy ] lazy val edgesOut = ( oPorts zip oParams ) . map { case ( ( i , n , p , s ) , o ) => outer . edgeO ( o , n . iParams ( i ) , p , s ) }
protected [ diplomacy ] lazy val edgesIn = ( iPorts zip iParams ) . map { case ( ( o , n , p , s ) , i ) => inner . edgeI ( n . oParams ( o ) , i , p , s ) }
2017-09-14 03:06:03 +02:00
// If you need access to the edges of a foreign Node, use this method (in/out create bundles)
2017-09-15 23:44:07 +02:00
lazy val edges = Edges ( edgesIn , edgesOut )
2016-10-04 00:17:36 +02:00
2017-09-14 03:06:03 +02:00
protected [ diplomacy ] lazy val bundleOut : Seq [ BO ] = edgesOut . map ( e => Wire ( outer . bundleO ( e ) ) )
protected [ diplomacy ] lazy val bundleIn : Seq [ BI ] = edgesIn . map ( e => Wire ( inner . bundleI ( e ) ) )
2017-09-23 07:23:58 +02:00
protected [ diplomacy ] def danglesOut : Seq [ Dangle ] = oPorts . zipWithIndex . map { case ( ( j , n , _ , _ ) , i ) =>
2017-09-14 03:06:03 +02:00
Dangle (
source = HalfEdge ( serial , i ) ,
sink = HalfEdge ( n . serial , j ) ,
flipped = false ,
2017-09-26 02:49:45 +02:00
name = wirePrefix + "out" ,
2017-09-14 03:06:03 +02:00
data = bundleOut ( i ) )
}
2017-09-23 07:23:58 +02:00
protected [ diplomacy ] def danglesIn : Seq [ Dangle ] = iPorts . zipWithIndex . map { case ( ( j , n , _ , _ ) , i ) =>
2017-09-14 03:06:03 +02:00
Dangle (
source = HalfEdge ( n . serial , j ) ,
sink = HalfEdge ( serial , i ) ,
flipped = true ,
2017-09-26 02:49:45 +02:00
name = wirePrefix + "in" ,
2017-09-14 03:06:03 +02:00
data = bundleIn ( i ) )
}
2017-09-07 23:56:09 +02:00
2017-09-14 03:06:03 +02:00
private var bundlesSafeNow = false
// Accessors to the result of negotiation to be used in LazyModuleImp:
def out : Seq [ ( BO , EO ) ] = {
2017-09-22 23:57:36 +02:00
require ( bundlesSafeNow , s" ${ name } .out should only be called from the context of its module implementation " )
2017-09-14 03:06:03 +02:00
bundleOut zip edgesOut
}
def in : Seq [ ( BI , EI ) ] = {
2017-09-22 23:57:36 +02:00
require ( bundlesSafeNow , s" ${ name } .in should only be called from the context of its module implementation " )
2017-09-14 03:06:03 +02:00
bundleIn zip edgesIn
}
2016-10-04 00:17:36 +02:00
2017-09-23 01:55:12 +02:00
// Used by LazyModules.module.instantiate
protected val identity = false
protected [ diplomacy ] def instantiate ( ) = {
bundlesSafeNow = true
if ( ! identity ) {
( iPorts zip in ) foreach {
case ( ( _ , _ , p , _ ) , ( b , e ) ) => if ( p ( MonitorsEnabled ) ) inner . monitor ( b , e )
} }
danglesOut ++ danglesIn
}
2016-10-04 00:17:36 +02:00
// connects the outward part of a node with the inward part of this node
2017-09-23 01:55:12 +02:00
private def bind ( h : OutwardNodeHandle [ DI , UI , BI ] , binding : NodeBinding ) ( implicit p : Parameters , sourceInfo : SourceInfo ) {
2016-10-04 00:17:36 +02:00
val x = this // x := y
2016-10-08 08:35:20 +02:00
val y = h . outward
2016-10-04 00:17:36 +02:00
val info = sourceLine ( sourceInfo , " at " , "" )
val i = x . iPushed
val o = y . oPushed
2017-01-29 06:20:34 +01:00
y . oPush ( i , x , binding match {
case BIND_ONCE => BIND_ONCE
case BIND_STAR => BIND_QUERY
case BIND_QUERY => BIND_STAR } )
x . iPush ( o , y , binding )
2016-10-04 00:17:36 +02:00
}
2017-01-29 06:20:34 +01:00
2017-09-23 01:55:12 +02:00
override def : = ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) = bind ( h , BIND_ONCE )
override def : *= ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) = bind ( h , BIND_STAR )
override def : = * ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) = bind ( h , BIND_QUERY )
override def : = ? ( h : OutwardNodeHandle [ DI , UI , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) = {
2017-09-07 22:33:07 +02:00
p ( CardinalityInferenceDirectionKey ) match {
case CardinalityInferenceDirection . SOURCE_TO_SINK => this : = * h
case CardinalityInferenceDirection . SINK_TO_SOURCE => this : *= h
case CardinalityInferenceDirection . NO_INFERENCE => this : = h
2017-09-07 00:30:25 +02:00
}
}
2017-06-29 06:48:10 +02:00
2017-01-29 06:20:34 +01:00
// meta-data for printing the node graph
2017-09-26 22:23:54 +02:00
protected [ diplomacy ] def inputs = ( iPorts zip edgesIn ) map { case ( ( _ , n , p , _ ) , e ) =>
val re = inner . render ( e )
( n , re . copy ( flipped = re . flipped != p ( RenderFlipped ) ) )
}
protected [ diplomacy ] def outputs = oPorts map { case ( i , n , _ , _ ) => ( n , n . inputs ( i ) . _2 ) }
2016-10-04 00:17:36 +02:00
}
2017-05-20 02:29:22 +02:00
abstract class MixedCustomNode [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ] (
inner : InwardNodeImp [ DI , UI , EI , BI ] ,
outer : OutwardNodeImp [ DO , UO , EO , BO ] ) (
numPO : Range . Inclusive ,
2017-09-12 08:33:44 +02:00
numPI : Range . Inclusive ) (
implicit valName : ValName )
2017-05-20 02:29:22 +02:00
extends MixedNode ( inner , outer ) ( numPO , numPI )
{
def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int )
def mapParamsD ( n : Int , p : Seq [ DI ] ) : Seq [ DO ]
def mapParamsU ( n : Int , p : Seq [ UO ] ) : Seq [ UI ]
}
abstract class CustomNode [ D , U , EO , EI , B <: Data ] ( imp : NodeImp [ D , U , EO , EI , B ] ) (
numPO : Range . Inclusive ,
2017-09-12 08:33:44 +02:00
numPI : Range . Inclusive ) (
implicit valName : ValName )
2017-05-20 02:29:22 +02:00
extends MixedCustomNode ( imp , imp ) ( numPO , numPI )
2017-01-29 22:55:53 +01:00
class MixedAdapterNode [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ] (
inner : InwardNodeImp [ DI , UI , EI , BI ] ,
outer : OutwardNodeImp [ DO , UO , EO , BO ] ) (
dFn : DI => DO ,
uFn : UO => UI ,
2017-09-12 08:33:44 +02:00
num : Range . Inclusive = 0 to 999 ) (
implicit valName : ValName )
2017-01-29 22:55:53 +01:00
extends MixedNode ( inner , outer ) ( num , num )
{
2017-05-19 21:52:01 +02:00
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int ) = {
require ( oStars + iStars <= 1 , s" ${ name } (an adapter) appears left of a :*= ${ iStars } times and right of a :=* ${ oStars } times; at most once is allowed ${ lazyModule . line } " )
if ( oStars > 0 ) {
require ( iKnown >= oKnown , s" ${ name } (an adapter) has ${ oKnown } outputs and ${ iKnown } inputs; cannot assign ${ iKnown - oKnown } edges to resolve :=* ${ lazyModule . line } " )
( 0 , iKnown - oKnown )
} else {
require ( oKnown >= iKnown , s" ${ name } (an adapter) has ${ oKnown } outputs and ${ iKnown } inputs; cannot assign ${ oKnown - iKnown } edges to resolve :*= ${ lazyModule . line } " )
( oKnown - iKnown , 0 )
}
2017-01-29 22:55:53 +01:00
}
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 )
}
}
2016-10-04 00:17:36 +02:00
2017-09-14 03:06:03 +02:00
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 ) (
implicit valName : ValName )
extends MixedAdapterNode [ D , U , EI , B , D , U , EO , B ] ( imp , imp ) ( dFn , uFn , num )
// IdentityNodes automatically connect their inputs to outputs
class IdentityNode [ D , U , EO , EI , B <: Data ] ( imp : NodeImp [ D , U , EO , EI , B ] ) ( ) ( implicit valName : ValName )
extends AdapterNode ( imp ) ( { s => s } , { s => s } )
{
2017-09-23 01:55:12 +02:00
protected override val identity = true
2017-09-14 03:06:03 +02:00
override protected [ diplomacy ] def instantiate ( ) = {
val dangles = super . instantiate ( )
( out zip in ) map { case ( ( o , _ ) , ( i , _ ) ) => o <> i }
dangles
}
}
2017-01-29 22:55:53 +01:00
class MixedNexusNode [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ] (
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 ,
2017-09-12 08:33:44 +02:00
numPI : Range . Inclusive = 1 to 999 ) (
implicit valName : ValName )
2017-01-29 22:55:53 +01:00
extends MixedNode ( inner , outer ) ( numPO , numPI )
{
2017-03-02 06:57:00 +01:00
// require (numPO.end >= 1, s"${name} does not accept outputs${lazyModule.line}")
// require (numPI.end >= 1, s"${name} does not accept inputs${lazyModule.line}")
2017-02-10 19:19:22 +01:00
2017-05-19 21:52:01 +02:00
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int ) = {
require ( iStars == 0 , s" ${ name } (a nexus) appears left of :*= (perhaps you should flip the '*' to :=*?) ${ lazyModule . line } " )
require ( oStars == 0 , s" ${ name } (a nexus) appears right of a :=* (perhaps you should flip the '*' to :*=?) ${ lazyModule . line } " )
( 0 , 0 )
2017-01-29 22:55:53 +01:00
}
2017-07-13 00:03:17 +02:00
protected [ diplomacy ] def mapParamsD ( n : Int , p : Seq [ DI ] ) : Seq [ DO ] = { val a = dFn ( p ) ; Seq . fill ( n ) ( a ) }
protected [ diplomacy ] def mapParamsU ( n : Int , p : Seq [ UO ] ) : Seq [ UI ] = { val a = uFn ( p ) ; Seq . fill ( n ) ( a ) }
2017-01-29 22:55:53 +01:00
}
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 ,
2017-09-12 08:33:44 +02:00
numPI : Range . Inclusive = 1 to 999 ) (
implicit valName : ValName )
2017-01-29 22:55:53 +01:00
extends MixedNexusNode [ D , U , EI , B , D , U , EO , B ] ( imp , imp ) ( dFn , uFn , numPO , numPI )
2017-05-19 23:34:54 +02:00
2017-09-14 03:06:03 +02:00
// There are no Mixed SourceNodes
2017-09-12 08:33:44 +02:00
class SourceNode [ D , U , EO , EI , B <: Data ] ( imp : NodeImp [ D , U , EO , EI , B ] ) ( po : Seq [ D ] ) ( implicit valName : ValName )
2017-01-29 22:55:53 +01:00
extends MixedNode ( imp , imp ) ( po . size to po . size , 0 to 0 )
2016-10-04 00:17:36 +02:00
{
2017-05-19 21:52:01 +02:00
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int ) = {
require ( oStars <= 1 , s" ${ name } (a source) appears right of a :=* ${ oStars } times; at most once is allowed ${ lazyModule . line } " )
require ( iStars == 0 , s" ${ name } (a source) cannot appear left of a :*= ${ lazyModule . line } " )
require ( iKnown == 0 , s" ${ name } (a source) cannot appear left of a := ${ lazyModule . line } " )
require ( po . size >= oKnown , s" ${ name } (a source) has ${ oKnown } outputs out of ${ po . size } ; cannot assign ${ po . size - oKnown } edges to resolve :=* ${ lazyModule . line } " )
( 0 , po . size - oKnown )
2017-01-29 22:55:53 +01:00
}
protected [ diplomacy ] def mapParamsD ( n : Int , p : Seq [ D ] ) : Seq [ D ] = po
protected [ diplomacy ] def mapParamsU ( n : Int , p : Seq [ U ] ) : Seq [ U ] = Seq ( )
2016-10-04 00:17:36 +02:00
}
2017-09-14 03:06:03 +02:00
// There are no Mixed SinkNodes
2017-09-12 08:33:44 +02:00
class SinkNode [ D , U , EO , EI , B <: Data ] ( imp : NodeImp [ D , U , EO , EI , B ] ) ( pi : Seq [ U ] ) ( implicit valName : ValName )
2017-01-29 22:55:53 +01:00
extends MixedNode ( imp , imp ) ( 0 to 0 , pi . size to pi . size )
2016-10-04 00:17:36 +02:00
{
2017-05-19 21:52:01 +02:00
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int ) = {
require ( iStars <= 1 , s" ${ name } (a sink) appears left of a :*= ${ iStars } times; at most once is allowed ${ lazyModule . line } " )
require ( oStars == 0 , s" ${ name } (a sink) cannot appear right of a :=* ${ lazyModule . line } " )
require ( oKnown == 0 , s" ${ name } (a sink) cannot appear right of a := ${ lazyModule . line } " )
require ( pi . size >= iKnown , s" ${ name } (a sink) has ${ iKnown } inputs out of ${ pi . size } ; cannot assign ${ pi . size - iKnown } edges to resolve :*= ${ lazyModule . line } " )
( pi . size - iKnown , 0 )
2017-01-29 22:55:53 +01:00
}
protected [ diplomacy ] def mapParamsD ( n : Int , p : Seq [ D ] ) : Seq [ D ] = Seq ( )
protected [ diplomacy ] def mapParamsU ( n : Int , p : Seq [ U ] ) : Seq [ U ] = pi
2016-10-29 06:20:49 +02:00
}