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-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
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-11-09 00:32:45 +01:00
protected [ diplomacy ] def finishInstantiate ( ) : Unit
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-10-20 03:51:00 +02:00
def parents : Seq [ LazyModule ] = lazyModule +: lazyModule . parents
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 + "_"
}
2017-10-27 00:08:06 +02:00
def inputs : Seq [ ( BaseNode , RenderedEdge ) ]
def outputs : Seq [ ( BaseNode , RenderedEdge ) ]
2017-12-02 03:28:37 +01:00
protected [ diplomacy ] val sinkCard : Int
protected [ diplomacy ] val sourceCard : Int
2016-10-04 00:17:36 +02:00
}
2017-09-14 03:06:03 +02:00
object BaseNode
{
protected [ diplomacy ] var serial = 0
}
2017-10-25 08:34:16 +02:00
trait NoHandle
case object NoHandleObject extends NoHandle
2017-11-02 01:03:01 +01:00
trait NodeHandle [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ]
extends InwardNodeHandle [ DI , UI , EI , BI ] with OutwardNodeHandle [ DO , UO , EO , BO ]
2017-10-25 08:34:16 +02:00
{
// connecting two full nodes => full node
2017-11-02 01:03:01 +01:00
override def : = [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NodeHandle [ DX , UX , EX , BX , DO , UO , EO , BO ] = { bind ( h , BIND_ONCE ) ; NodeHandle ( h , this ) }
override def : *= [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NodeHandle [ DX , UX , EX , BX , DO , UO , EO , BO ] = { bind ( h , BIND_STAR ) ; NodeHandle ( h , this ) }
override def : = * [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NodeHandle [ DX , UX , EX , BX , DO , UO , EO , BO ] = { bind ( h , BIND_QUERY ) ; NodeHandle ( h , this ) }
2017-12-02 03:28:37 +01:00
override def : *=* [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NodeHandle [ DX , UX , EX , BX , DO , UO , EO , BO ] = { bind ( h , BIND_FLEX ) ; NodeHandle ( h , this ) }
2017-10-25 08:34:16 +02:00
// connecting a full node with an output => an output
2017-11-02 01:03:01 +01:00
override def : = [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : OutwardNodeHandle [ DO , UO , EO , BO ] = { bind ( h , BIND_ONCE ) ; this }
override def : *= [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : OutwardNodeHandle [ DO , UO , EO , BO ] = { bind ( h , BIND_STAR ) ; this }
override def : = * [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : OutwardNodeHandle [ DO , UO , EO , BO ] = { bind ( h , BIND_QUERY ) ; this }
2017-12-02 03:28:37 +01:00
override def : *=* [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : OutwardNodeHandle [ DO , UO , EO , BO ] = { bind ( h , BIND_FLEX ) ; this }
2017-10-25 08:34:16 +02:00
}
object NodeHandle
{
2017-11-02 01:03:01 +01:00
def apply [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ] ( i : InwardNodeHandle [ DI , UI , EI , BI ] , o : OutwardNodeHandle [ DO , UO , EO , BO ] ) = new NodeHandlePair ( i , o )
2017-10-25 08:34:16 +02:00
}
2017-11-02 01:03:01 +01:00
class NodeHandlePair [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ]
( inwardHandle : InwardNodeHandle [ DI , UI , EI , BI ] , outwardHandle : OutwardNodeHandle [ DO , UO , EO , BO ] )
extends NodeHandle [ DI , UI , EI , BI , DO , UO , EO , BO ]
2017-09-27 03:47:16 +02:00
{
val inward = inwardHandle . inward
val outward = outwardHandle . outward
2017-11-02 01:03:01 +01:00
def inner = inwardHandle . inner
def outer = outwardHandle . outer
2017-09-27 03:47:16 +02:00
}
2016-10-08 08:35:20 +02:00
2017-11-02 01:03:01 +01:00
trait InwardNodeHandle [ DI , UI , EI , BI <: Data ] extends NoHandle
2016-10-04 00:17:36 +02:00
{
2017-10-25 20:17:17 +02:00
def inward : InwardNode [ DI , UI , BI ]
2017-11-02 01:03:01 +01:00
def inner : InwardNodeImp [ DI , UI , EI , BI ]
protected def bind [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] , binding : NodeBinding ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : Unit = inward . bind ( h . outward , binding )
2017-10-25 20:17:17 +02:00
2017-10-25 08:34:16 +02:00
// connecting an input node with a full nodes => an input node
2017-11-02 01:03:01 +01:00
def : = [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : InwardNodeHandle [ DX , UX , EX , BX ] = { bind ( h , BIND_ONCE ) ; h }
def : *= [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : InwardNodeHandle [ DX , UX , EX , BX ] = { bind ( h , BIND_STAR ) ; h }
def : = * [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : InwardNodeHandle [ DX , UX , EX , BX ] = { bind ( h , BIND_QUERY ) ; h }
2017-12-02 03:28:37 +01:00
def : *=* [ DX , UX , EX , BX <: Data , EY ] ( h : NodeHandle [ DX , UX , EX , BX , DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : InwardNodeHandle [ DX , UX , EX , BX ] = { bind ( h , BIND_FLEX ) ; h }
2017-10-25 08:34:16 +02:00
// connecting input node with output node => no node
2017-11-02 01:03:01 +01:00
def : = [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NoHandle = { bind ( h , BIND_ONCE ) ; NoHandleObject }
def : *= [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NoHandle = { bind ( h , BIND_STAR ) ; NoHandleObject }
def : = * [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NoHandle = { bind ( h , BIND_QUERY ) ; NoHandleObject }
2017-12-02 03:28:37 +01:00
def : *=* [ EY ] ( h : OutwardNodeHandle [ DI , UI , EY , BI ] ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : NoHandle = { bind ( h , BIND_FLEX ) ; NoHandleObject }
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
2017-12-02 03:28:37 +01:00
case object BIND_FLEX extends NodeBinding
2017-10-25 08:34:16 +02:00
2017-11-02 01:03:01 +01:00
trait InwardNode [ DI , UI , BI <: Data ] extends BaseNode
2016-10-08 08:35:20 +02:00
{
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 " , "" )
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 ) ]
2017-11-03 01:12:20 +01:00
protected [ diplomacy ] val diParams : Seq [ DI ] // from connected nodes
protected [ diplomacy ] val uiParams : Seq [ UI ] // from this node
2017-10-25 08:34:16 +02:00
2017-10-25 20:17:17 +02:00
protected [ diplomacy ] def bind ( h : OutwardNode [ DI , UI , BI ] , binding : NodeBinding ) ( implicit p : Parameters , sourceInfo : SourceInfo ) : Unit
2016-10-04 00:17:36 +02:00
}
2017-11-02 01:03:01 +01:00
trait OutwardNodeHandle [ DO , UO , EO , BO <: Data ] extends NoHandle
2016-10-04 00:17:36 +02:00
{
2017-10-25 20:17:17 +02:00
def outward : OutwardNode [ DO , UO , BO ]
2017-11-02 01:03:01 +01:00
def outer : OutwardNodeImp [ DO , UO , EO , BO ]
2016-10-08 08:35:20 +02:00
}
2017-11-02 01:03:01 +01:00
trait OutwardNode [ DO , UO , BO <: Data ] extends BaseNode
2016-10-08 08:35:20 +02:00
{
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 " , "" )
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 ) ]
2017-11-03 01:12:20 +01:00
protected [ diplomacy ] val uoParams : Seq [ UO ] // from connected nodes
protected [ diplomacy ] val doParams : Seq [ DO ] // from this node
2016-10-04 00:17:36 +02:00
}
2017-09-27 20:46:06 +02:00
abstract class CycleException ( kind : String , loop : Seq [ String ] ) extends Exception ( s" Diplomatic ${ kind } cycle detected involving ${ loop } " )
case class StarCycleException ( loop : Seq [ String ] = Nil ) extends CycleException ( "star" , loop )
case class DownwardCycleException ( loop : Seq [ String ] = Nil ) extends CycleException ( "downward" , loop )
case class UpwardCycleException ( loop : Seq [ String ] = Nil ) extends CycleException ( "upward" , loop )
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 ] (
2017-11-02 01:03:01 +01:00
val inner : InwardNodeImp [ DI , UI , EI , BI ] ,
val outer : OutwardNodeImp [ DO , UO , EO , BO ] ) (
2017-09-12 08:33:44 +02:00
implicit valName : ValName )
2017-11-02 01:03:01 +01:00
extends BaseNode with NodeHandle [ DI , UI , EI , BI , DO , UO , EO , BO ] with InwardNode [ DI , UI , BI ] with OutwardNode [ DO , UO , BO ]
2016-10-04 00:17:36 +02:00
{
2017-11-02 01:03:01 +01:00
val inward = this
val outward = this
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-12-02 03:28:37 +01:00
protected [ diplomacy ] lazy val sinkCard = oBindings . count ( _ . _3 == BIND_QUERY ) + iBindings . count ( _ . _3 == BIND_STAR )
protected [ diplomacy ] lazy val sourceCard = iBindings . count ( _ . _3 == BIND_QUERY ) + oBindings . count ( _ . _3 == BIND_STAR )
protected [ diplomacy ] lazy val flexOffset = { // positive = sink cardinality; define 0 to be sink (both should work)
def DFS ( v : BaseNode , visited : Set [ BaseNode ] ) : Set [ BaseNode ] = {
if ( visited . contains ( v ) ) {
visited
} else {
val flexes = oBindings . filter ( _ . _3 == BIND_FLEX ) . map ( _ . _2 ) ++ iBindings . filter ( _ . _3 == BIND_FLEX ) . map ( _ . _2 )
flexes . foldLeft ( visited + v ) ( ( sum , n ) => DFS ( n , sum ) )
}
}
val flexSet = DFS ( this , Set ( ) )
val allSink = flexSet . map ( _ . sinkCard ) . sum
val allSource = flexSet . map ( _ . sourceCard ) . sum
require ( flexSet . size == 1 || allSink == 0 || allSource == 0 ,
s" The nodes ${ flexSet . map ( _ . name ) } which are inter-connected by :*=* have ${ allSink } :*= operators and ${ allSource } :=* operators connected to them, making it impossible to determine cardinality inference direction. " )
allSink - allSource
}
2017-09-27 20:46:06 +02:00
private var starCycleGuard = false
2017-01-29 06:20:34 +01:00
protected [ diplomacy ] lazy val ( oPortMapping , iPortMapping , oStar , iStar ) = {
2017-09-27 20:46:06 +02:00
try {
if ( starCycleGuard ) throw StarCycleException ( )
2017-12-02 03:28:37 +01:00
starCycleGuard = true
val oStars = oBindings . count { case ( _ , _ , b , _ , _ ) => b == BIND_STAR || ( b == BIND_FLEX && flexOffset < 0 ) }
val iStars = iBindings . count { case ( _ , _ , b , _ , _ ) => b == BIND_STAR || ( b == BIND_FLEX && flexOffset >= 0 ) }
2017-09-27 20:46:06 +02:00
val oKnown = oBindings . map { case ( _ , n , b , _ , _ ) => b match {
case BIND_ONCE => 1
2017-12-02 03:28:37 +01:00
case BIND_FLEX => { if ( flexOffset < 0 ) 0 else n . iStar }
2017-09-27 20:46:06 +02:00
case BIND_QUERY => n . iStar
case BIND_STAR => 0 } } . foldLeft ( 0 ) ( _ + _ )
val iKnown = iBindings . map { case ( _ , n , b , _ , _ ) => b match {
case BIND_ONCE => 1
2017-12-02 03:28:37 +01:00
case BIND_FLEX => { if ( flexOffset >= 0 ) 0 else n . oStar }
2017-09-27 20:46:06 +02:00
case BIND_QUERY => n . oStar
case BIND_STAR => 0 } } . foldLeft ( 0 ) ( _ + _ )
val ( iStar , oStar ) = resolveStar ( iKnown , oKnown , iStars , oStars )
val oSum = oBindings . map { case ( _ , n , b , _ , _ ) => b match {
case BIND_ONCE => 1
2017-12-02 03:28:37 +01:00
case BIND_FLEX => { if ( flexOffset < 0 ) oStar else n . iStar }
2017-09-27 20:46:06 +02:00
case BIND_QUERY => n . iStar
case BIND_STAR => oStar } } . scanLeft ( 0 ) ( _ + _ )
val iSum = iBindings . map { case ( _ , n , b , _ , _ ) => b match {
case BIND_ONCE => 1
2017-12-02 03:28:37 +01:00
case BIND_FLEX => { if ( flexOffset >= 0 ) iStar else n . oStar }
2017-09-27 20:46:06 +02:00
case BIND_QUERY => n . oStar
case BIND_STAR => iStar } } . scanLeft ( 0 ) ( _ + _ )
val oTotal = oSum . lastOption . getOrElse ( 0 )
val iTotal = iSum . lastOption . getOrElse ( 0 )
( oSum . init zip oSum . tail , iSum . init zip iSum . tail , oStar , iStar )
} catch {
case c : StarCycleException => throw c . copy ( loop = s" ${ name } ${ lazyModule . line } " +: c . loop )
}
2017-01-29 06:20:34 +01:00
}
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
2017-09-27 20:46:06 +02:00
private var oParamsCycleGuard = false
2017-11-03 01:12:20 +01:00
protected [ diplomacy ] lazy val diParams : Seq [ DI ] = iPorts . map { case ( i , n , _ , _ ) => n . doParams ( i ) }
protected [ diplomacy ] lazy val doParams : Seq [ DO ] = {
2017-09-27 20:46:06 +02:00
try {
if ( oParamsCycleGuard ) throw DownwardCycleException ( )
oParamsCycleGuard = true
2017-11-03 01:12:20 +01:00
val o = mapParamsD ( oPorts . size , diParams )
2017-09-27 20:46:06 +02:00
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 ) )
} catch {
case c : DownwardCycleException => throw c . copy ( loop = s" ${ name } ${ lazyModule . line } " +: c . loop )
}
2016-10-04 00:17:36 +02:00
}
2017-09-27 20:46:06 +02:00
private var iParamsCycleGuard = false
2017-11-03 01:12:20 +01:00
protected [ diplomacy ] lazy val uoParams : Seq [ UO ] = oPorts . map { case ( o , n , _ , _ ) => n . uiParams ( o ) }
protected [ diplomacy ] lazy val uiParams : Seq [ UI ] = {
2017-09-27 20:46:06 +02:00
try {
if ( iParamsCycleGuard ) throw UpwardCycleException ( )
iParamsCycleGuard = true
2017-11-03 01:12:20 +01:00
val i = mapParamsU ( iPorts . size , uoParams )
2017-09-27 20:46:06 +02:00
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 ) )
} catch {
case c : UpwardCycleException => throw c . copy ( loop = s" ${ name } ${ lazyModule . line } " +: c . loop )
}
2016-10-04 00:17:36 +02:00
}
2017-11-03 01:12:20 +01:00
protected [ diplomacy ] lazy val edgesOut = ( oPorts zip doParams ) . map { case ( ( i , n , p , s ) , o ) => outer . edgeO ( o , n . uiParams ( i ) , p , s ) }
protected [ diplomacy ] lazy val edgesIn = ( iPorts zip uiParams ) . map { case ( ( o , n , p , s ) , i ) => inner . edgeI ( n . doParams ( 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
}
2017-11-09 00:32:45 +01:00
protected [ diplomacy ] def finishInstantiate ( ) = {
bundlesSafeNow = false
}
2016-10-04 00:17:36 +02:00
// connects the outward part of a node with the inward part of this node
2017-10-25 20:17:17 +02:00
protected [ diplomacy ] def bind ( h : OutwardNode [ DI , UI , BI ] , binding : NodeBinding ) ( implicit p : Parameters , sourceInfo : SourceInfo ) {
2016-10-04 00:17:36 +02:00
val x = this // x := y
2017-10-25 20:17:17 +02:00
val y = h
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
2017-12-02 03:28:37 +01:00
case BIND_FLEX => BIND_FLEX
2017-01-29 06:20:34 +01:00
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
// meta-data for printing the node graph
2017-10-27 00:08:06 +02:00
def inputs = ( iPorts zip edgesIn ) map { case ( ( _ , n , p , _ ) , e ) =>
2017-09-26 22:23:54 +02:00
val re = inner . render ( e )
( n , re . copy ( flipped = re . flipped != p ( RenderFlipped ) ) )
}
2017-10-27 00:08:06 +02:00
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 ] ) (
2017-09-12 08:33:44 +02:00
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedNode ( inner , outer )
2017-05-20 02:29:22 +02:00
{
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 ] ) (
2017-09-12 08:33:44 +02:00
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedCustomNode ( imp , imp )
2017-05-20 02:29:22 +02:00
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 ,
2017-11-30 23:43:43 +01:00
uFn : UO => UI ) (
2017-09-12 08:33:44 +02:00
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedNode ( inner , outer )
2017-01-29 22:55:53 +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 ( 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 )
2017-11-30 23:43:43 +01:00
} else if ( iStars > 0 ) {
2017-05-19 21:52:01 +02:00
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-11-30 23:43:43 +01:00
} else {
require ( oKnown == iKnown , s" ${ name } (an adapter) has ${ oKnown } outputs and ${ iKnown } inputs; these do not match " )
( 0 , 0 )
2017-05-19 21:52:01 +02:00
}
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 ,
2017-11-30 23:43:43 +01:00
uFn : U => U ) (
2017-09-14 03:06:03 +02:00
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedAdapterNode [ D , U , EI , B , D , U , EO , B ] ( imp , imp ) ( dFn , uFn )
2017-09-14 03:06:03 +02:00
// 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 ,
2017-11-30 23:43:43 +01:00
// no inputs and no outputs is always allowed
inputRequiresOutput : Boolean = true ,
outputRequiresInput : Boolean = true ) (
2017-09-12 08:33:44 +02:00
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedNode ( inner , outer )
2017-01-29 22:55:53 +01:00
{
2017-05-19 21:52:01 +02:00
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int ) = {
2017-11-30 23:43:43 +01:00
// a nexus treats :=* as a weak pointer
require ( ! outputRequiresInput || oKnown == 0 || iStars + iKnown != 0 , s" ${ name } (a nexus) has ${ oKnown } required outputs and no possible inputs " )
require ( ! inputRequiresOutput || iKnown == 0 || oStars + oKnown != 0 , s" ${ name } (a nexus) has ${ iKnown } required inputs and no possible outputs " )
if ( iKnown == 0 && oKnown == 0 ) ( 0 , 0 ) else ( 1 , 1 )
2017-01-29 22:55:53 +01:00
}
2017-11-30 23:43:43 +01:00
protected [ diplomacy ] def mapParamsD ( n : Int , p : Seq [ DI ] ) : Seq [ DO ] = { if ( n > 0 ) { val a = dFn ( p ) ; Seq . fill ( n ) ( a ) } else Nil }
protected [ diplomacy ] def mapParamsU ( n : Int , p : Seq [ UO ] ) : Seq [ UI ] = { if ( n > 0 ) { val a = uFn ( p ) ; Seq . fill ( n ) ( a ) } else Nil }
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 ,
2017-11-30 23:43:43 +01:00
inputRequiresOutput : Boolean = true ,
outputRequiresInput : Boolean = true ) (
2017-09-12 08:33:44 +02:00
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedNexusNode [ D , U , EI , B , D , U , EO , B ] ( imp , imp ) ( dFn , uFn , inputRequiresOutput , outputRequiresInput )
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-11-30 23:43:43 +01:00
extends MixedNode ( imp , imp )
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 } " )
2017-11-30 23:43:43 +01:00
require ( po . size == oKnown || oStars == 1 , s" ${ name } (a source) has only ${ oKnown } outputs connected out of ${ po . size } " )
2017-05-19 21:52:01 +02:00
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-11-30 23:43:43 +01:00
extends MixedNode ( imp , imp )
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 } " )
2017-11-30 23:43:43 +01:00
require ( pi . size == iKnown || iStars == 1 , s" ${ name } (a sink) has only ${ iKnown } inputs connected out of ${ pi . size } " )
2017-05-19 21:52:01 +02:00
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
}
2017-11-07 22:08:30 +01:00
class MixedTestNode [ DI , UI , EI , BI <: Data , DO , UO , EO , BO <: Data ] protected [ diplomacy ] (
node : NodeHandle [ DI , UI , EI , BI , DO , UO , EO , BO ] , clone : CloneLazyModule ) (
implicit valName : ValName )
2017-11-30 23:43:43 +01:00
extends MixedNode ( node . inner , node . outer )
2017-11-07 22:08:30 +01:00
{
// The devices connected to this test node must recreate these parameters:
def iParams : Seq [ DI ] = node . inward . diParams
def oParams : Seq [ UO ] = node . outward . uoParams
protected [ diplomacy ] def resolveStar ( iKnown : Int , oKnown : Int , iStars : Int , oStars : Int ) : ( Int , Int ) = {
require ( oStars <= 1 , s" ${ name } (a test node) appears right of a :=* ${ oStars } times; at most once is allowed ${ lazyModule . line } " )
require ( iStars <= 1 , s" ${ name } (a test node) appears left of a :*= ${ iStars } times; at most once is allowed ${ lazyModule . line } " )
2017-11-30 23:43:43 +01:00
require ( node . inward . uiParams . size == iKnown || iStars == 1 , s" ${ name } (a test node) has only ${ iKnown } inputs connected out of ${ node . inward . uiParams . size } " )
require ( node . outward . doParams . size == oKnown || oStars == 1 , s" ${ name } (a test node) has only ${ oKnown } outputs connected out of ${ node . outward . doParams . size } " )
2017-11-07 22:08:30 +01:00
( node . inward . uiParams . size - iKnown , node . outward . doParams . size - oKnown )
}
protected [ diplomacy ] def mapParamsU ( n : Int , p : Seq [ UO ] ) : Seq [ UI ] = node . inward . uiParams
protected [ diplomacy ] def mapParamsD ( n : Int , p : Seq [ DI ] ) : Seq [ DO ] = node . outward . doParams
override protected [ diplomacy ] def instantiate ( ) = {
val dangles = super . instantiate ( )
val orig_module = clone . base . module
val clone_auto = clone . io ( "auto" ) . asInstanceOf [ AutoBundle ]
danglesOut . zipWithIndex . foreach { case ( d , i ) =>
val orig = orig_module . dangles . find ( _ . source == HalfEdge ( node . outward . serial , i ) )
require ( orig . isDefined , s" Cloned node ${ node . outward . name } must be connected externally out ${ orig_module . name } " )
val io_name = orig_module . auto . elements . find ( _ . _2 eq orig . get . data ) . get . _1
d . data <> clone_auto . elements ( io_name )
}
danglesIn . zipWithIndex . foreach { case ( d , i ) =>
val orig = orig_module . dangles . find ( _ . sink == HalfEdge ( node . inward . serial , i ) )
require ( orig . isDefined , s" Cloned node ${ node . inward . name } must be connected externally in ${ orig_module . name } " )
val io_name = orig_module . auto . elements . find ( _ . _2 eq orig . get . data ) . get . _1
clone_auto . elements ( io_name ) <> d . data
}
dangles
}
}