chipsalliance / chipsalliance/rocket-chip

Question about annotation and about flip Data in different functions

Open
#2,806 0 comments 0 reactions 0 assignees View on GitHub
question
Dominant language
Scala
Stars
3.9k
Forks
1.3k
Avg merge
5d 13m
Merged PRs (30d)
1

Description

**Type of issue**: bug report

**Impact**: no functional change | unknown

**Development Phase**: request

**Other information**

First , I notice that the annotation in line 476 in LazyModule.scala is :
```
467 /** [[Dangle]] captures the `IO` information of a [[LazyModule]] and which two [[BaseNode]]s the [[Edges]]/[[Bundle]] connects.
468 *
469 * [[Dangle]]s are generated by [[BaseNode.instantiate]]
470 * using [[MixedNode.danglesOut]] and [[MixedNode.danglesIn]] ,
471 * [[LazyModuleImp.instantiate]] connects those that go to internal or explicit IO connections
472 * in a [[LazyModule]].
473 *
474 * @param source the source [[HalfEdge]] of this [[Dangle]], which captures the source [[BaseNode]] and the port `index` within that [[BaseNode]].
475 * @param sink sink [[HalfEdge]] of this [[Dangle]], which captures the sink [[BaseNode]] and the port `index` within that [[BaseNode]].
476 * @param flipped flip or not in [[AutoBundle.makeElements]]. If true this corresponds to `danglesOut`, if false it corresponds to `danglesIn`.
477 * @param data actual [[Data]] for the hardware connection.
478 */
479 case class Dangle(source: HalfEdge, sink: HalfEdge, flipped: Boolean, name: String, data: Data)
```
while in Nodes.scala , dangleOut's flipped is false ,dangleIn's flipped is true:
```
protected[diplomacy] def danglesOut: Seq[Dangle] = oPorts.zipWithIndex.map { case ((j, n, _, _), i) =>
Dangle(
source = HalfEdge(serial, i),
sink = HalfEdge(n.serial, j),
flipped= false,
name = wirePrefix + "out",
data = bundleOut(i))
}

/** Create the [[Dangle]]s which describe the connections from this node input from other nodes outputs. */
protected[diplomacy] def danglesIn: Seq[Dangle] = iPorts.zipWithIndex.map { case ((j, n, _, _), i) =>
Dangle(
source = HalfEdge(n.serial, j),
sink = HalfEdge(serial, i),
flipped= true,
name = wirePrefix + "in",
data = bundleIn(i))
}
```
And I have a question about flip of data:

In LazyModule.scala , function AutoBundle() flip the Data(bundleIn) in dangleIn with flipped = true to make autoIO, while in Nodes.scala , function makeIOs() in class sourceNode flip the bundleOut to make IOs , why are they different?

AutoBundle() code in LazyModule.scala:
```
/** [[AutoBundle]] will construct the [[Bundle]]s for a [[LazyModule]] in [[LazyModuleImpLike.instantiate]],
*
* @param elts is a sequence of data containing for each IO port a tuple of (name, data, flipped), where
* name: IO name
* data: actual data for connection.
* flipped: flip or not in [[makeElements]]
*/
final class AutoBundle(elts: (String, Data, Boolean)*) extends Record {
// We need to preserve the order of elts, despite grouping by name to disambiguate things.
val elements: ListMap[String, Data] = ListMap() ++ elts.zipWithIndex.map(makeElements).groupBy(_._1).values.flatMap {
// If name is unique, it will return a Seq[index -> (name -> data)].
case Seq((key, element, i)) => Seq(i -> (key -> element))
// If name is not unique, name will append with j, and return `Seq[index -> (s"${name}_${j}" -> data)]`.
case seq => seq.zipWithIndex.map { case ((key, element, i), j) => i -> (key + "_" + j -> element) }
}.toList.sortBy(_._1).map(_._2)
require(elements.size == elts.size)

// Trim final "(_[0-9]+)*$" in the name, flip data with flipped.
private def makeElements(tuple: ((String, Data, Boolean), Int)) = {
val ((key, data, flip), i) = tuple
// Trim trailing _0_1_2 stuff so that when we append _# we don't create collisions.
val regex = new Regex("(_[0-9]+)*$")
val element = if (flip) data.cloneType.flip() else data.cloneType
(regex.replaceAllIn(key, ""), element, i)
}

override def cloneType: this.type = new AutoBundle(elts: _*).asInstanceOf[this.type]
}

```
makeIOs() code in Nodes.scala:
```
/** A node which represents a node in the graph which only has outward edges and no inward edges.
*
* A [[SourceNode]] cannot appear left of a `:=`, `:*=`, `:=*, or `:*=*`
* There are no Mixed [[SourceNode]]s, There are no "Mixed" [[SourceNode]]s because each one only has an outward side.
*/
class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D])(implicit valName: ValName)
extends MixedNode(imp, imp)
{
override def description = "source"
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
def resolveStarInfo: String =
s"""$context
|$bindingInfo
|number of known := bindings to inward nodes: $iKnown
|number of known := bindings to outward nodes: $oKnown
|number of binding queries from inward nodes: $iStars
|number of binding queries from outward nodes: $oStars
|${po.size} outward parameters: [${po.map(_.toString).mkString(",")}]
|""".stripMargin
require(oStars <= 1,
s"""Diplomacy has detected a problem with your graph:
|The following node appears right of a :=* $oStars times; at most once is allowed.
|$resolveStarInfo
|""".stripMargin)
require(iStars == 0,
s"""Diplomacy has detected a problem with your graph:
|The following node cannot appear left of a :*=
|$resolveStarInfo
|""".stripMargin)
require(iKnown == 0,
s"""Diplomacy has detected a problem with your graph:
|The following node cannot appear left of a :=
|$resolveStarInfo
|""".stripMargin)
if (oStars == 0)
require(po.size == oKnown,
s"""Diplomacy has detected a problem with your graph:
|The following node has $oKnown outward bindings connected to it, but ${po.size} sources were specified to the node constructor.
|Either the number of outward := bindings should be exactly equal to the number of sources, or connect this node on the right-hand side of a :=*
|$resolveStarInfo
|""".stripMargin)
else
require(po.size >= oKnown,
s"""Diplomacy has detected a problem with your graph:
|The following node has $oKnown outward bindings connected to it, but ${po.size} sources were specified to the node constructor.
|To resolve :=*, size of outward parameters can not be less than bindings.
|$resolveStarInfo
|""".stripMargin
)
(0, po.size - oKnown)
}
protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = po
protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = Seq()

def makeIOs()(implicit valName: ValName): HeterogeneousBag[B] = {
val bundles = this.out.map(_._1)
val ios = IO(Flipped(new HeterogeneousBag(bundles.map(_.cloneType))))
ios.suggestName(valName.name)
bundles.zip(ios).foreach { case (bundle, io) => bundle <> io }
ios
}
}
```

Contributor guide

Open the contributing guide

Research direction

Read LazyModule.scala around Dangle and AutoBundle.makeElements, then compare it with Nodes.scala around danglesOut, danglesIn, and SourceNode.makeIOs. Trace the meaning of each flipped value through these paths and confirm whether the annotation or implementation is inconsistent. Done means a maintainer-confirmed explanation and, if needed, a narrowly scoped correction with coverage for the affected direction.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.