Skip to content

Commit 3e87b41

Browse files
authored
Sub-board infrastructure with export-tap (#486)
Adds a SubblockBoard and WrapperSubblockBoard Block subclasses which have their internal implementation (links and blocks) in a separate board (or in the Wrapper case, discarded - the internal implementation is for electronics modeling only). Blocks marked as external can be used for, for example, connectors that sit on the carrier board. Implementation-wise, this adds an export-tap construct, an export (or export-array) construct that does not propagate parameters but can be hooked onto exterior ports that have other exports (including export-taps). A compiler check pass checks that inner ports do not have defined parameters (are empty) and (in the array case) elements are equal. Refactors A4988 and VL53L0x connectors to use this new infrastructure instead of the older WrapperFootprintBlock. which is removed. Infrastructure towards #367, #389 Future PRs will: - Implement multi-netlist generation - Implement connector pairs with some examples - Refactor microcontrollers to use this infrastructure
1 parent 06e423a commit 3e87b41

28 files changed

Lines changed: 1100 additions & 733 deletions

compiler/src/main/scala/edg/ElemBuilder.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,27 @@ object ElemBuilder {
4444
def Exported(
4545
external: ref.LocalPath,
4646
internal: ref.LocalPath,
47-
expanded: Seq[expr.ValueExpr] = Seq()
47+
expanded: Seq[expr.ValueExpr] = Seq(),
48+
tap: Boolean = false
4849
): expr.ValueExpr = expr.ValueExpr(
4950
expr = expr.ValueExpr.Expr.Exported(expr.ExportedExpr(
5051
exteriorPort = Some(ValueExpr.Ref(external)),
5152
internalBlockPort = Some(ValueExpr.Ref(internal)),
52-
expanded = expanded.map(_.getExported)
53+
expanded = expanded.map(_.getExported),
54+
tap = tap
5355
))
5456
)
5557
def ExportedArray(
5658
external: ref.LocalPath,
5759
internal: ref.LocalPath,
58-
expanded: Seq[expr.ValueExpr] = Seq()
60+
expanded: Seq[expr.ValueExpr] = Seq(),
61+
tap: Boolean = false
5962
): expr.ValueExpr = expr.ValueExpr(
6063
expr = expr.ValueExpr.Expr.ExportedArray(expr.ExportedExpr(
6164
exteriorPort = Some(ValueExpr.Ref(external)),
6265
internalBlockPort = Some(ValueExpr.Ref(internal)),
63-
expanded = expanded.map(_.getExported)
66+
expanded = expanded.map(_.getExported),
67+
tap = tap
6468
))
6569
)
6670
// variation for map_extract

compiler/src/main/scala/edg/compiler/Compiler.scala

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object ElaborateRecord {
3737
// Connection to be elaborated, to set port parameter, IS_CONNECTED, and CONNECTED_LINK equivalences.
3838
// Only elaborates the direct connect, and for bundles, creates sub-Connect tasks since it needs
3939
// connectedLink and linkParams.
40-
case class Connect(toLinkPortPath: DesignPath, toBlockPortPath: DesignPath, root: DesignPath)
40+
case class Connect(toLinkPortPath: DesignPath, toBlockPortPath: DesignPath, root: DesignPath, tap: Boolean = false)
4141
extends ElaborateTask
4242

4343
// Elaborates the contents of a port array, based on the port array's ELEMENTS parameter.
@@ -117,7 +117,7 @@ class AssignNamer() {
117117
}
118118

119119
object Compiler {
120-
final val kExpectedProtoVersion = 11
120+
final val kExpectedProtoVersion = 12
121121
}
122122

123123
/** Compiler for a particular design, with an associated library to elaborate references from.
@@ -279,12 +279,14 @@ class Compiler private (
279279
val toLinkPort = resolvePort(connect.toLinkPortPath).asInstanceOf[wir.HasParams]
280280
val connectedParam = toLinkPort.getParams.keys.map(IndirectStep.Element(_))
281281
for (connectedStep <- connectedParam) { // note: can't happen for top level connect!
282-
constProp.addAssignEqual(
283-
connect.toLinkPortPath.asIndirect + connectedStep,
284-
connect.toBlockPortPath.asIndirect + connectedStep,
285-
connect.root,
286-
"connect"
287-
)
282+
if (!connect.tap) { // tap is non-propagating
283+
constProp.addAssignEqual(
284+
connect.toLinkPortPath.asIndirect + connectedStep,
285+
connect.toBlockPortPath.asIndirect + connectedStep,
286+
connect.root,
287+
"connect"
288+
)
289+
}
288290
}
289291

290292
// Add sub-ports to the elaboration dependency graph, as appropriate
@@ -295,7 +297,8 @@ class Compiler private (
295297
ElaborateRecord.Connect(
296298
connect.toLinkPortPath + portName,
297299
connect.toBlockPortPath + portName,
298-
connect.root
300+
connect.root,
301+
connect.tap
299302
),
300303
Seq()
301304
)
@@ -499,11 +502,12 @@ class Compiler private (
499502
case (ValueExpr.Ref(extPort), ValueExpr.Ref(intPort)) =>
500503
if (!isInLink) {
501504
elaboratePending.addNode(
502-
ElaborateRecord.Connect(blockPath ++ extPort, blockPath ++ intPort, blockPath),
505+
ElaborateRecord.Connect(blockPath ++ extPort, blockPath ++ intPort, blockPath, tap = exported.tap),
503506
Seq(ElaborateRecord.Port(blockPath ++ extPort))
504507
)
505508
constProp.setConnection(blockPath ++ extPort, blockPath ++ intPort)
506509
} else { // for links, the internal port is towards the inner link, so the args are flipped
510+
require(!exported.tap, "tap not allowed in links")
507511
elaboratePending.addNode(
508512
ElaborateRecord.Connect(blockPath ++ intPort, blockPath ++ extPort, blockPath),
509513
Seq(ElaborateRecord.Port(blockPath ++ intPort))
@@ -514,6 +518,7 @@ class Compiler private (
514518
case _ => false // anything with allocates is not processed
515519
}
516520
case expr.ValueExpr.Expr.ExportedTunnel(exported) =>
521+
require(!exported.tap, "tap not allowed in tunnel")
517522
(exported.getExteriorPort, exported.getInternalBlockPort) match {
518523
case (ValueExpr.Ref(extPort), ValueExpr.Ref(intPort)) =>
519524
require(!isInLink)
@@ -845,12 +850,14 @@ class Compiler private (
845850

846851
case expr.ValueExpr.Expr.ExportedArray(exported) => // note internal port is portPostfix
847852
val ValueExpr.Ref(extPostfix) = exported.getExteriorPort
848-
constProp.addAssignEqual(
849-
path.asIndirect ++ extPostfix + IndirectStep.Elements,
850-
path.asIndirect ++ portPostfix + IndirectStep.Elements,
851-
path,
852-
constrName
853-
)
853+
if (!exported.tap) { // elements do not propagate in tap case, but are checked to be equal
854+
constProp.addAssignEqual(
855+
path.asIndirect ++ extPostfix + IndirectStep.Elements,
856+
path.asIndirect ++ portPostfix + IndirectStep.Elements,
857+
path,
858+
constrName
859+
)
860+
}
854861
constProp.addAssignEqual(
855862
path.asIndirect ++ portPostfix + IndirectStep.Allocated,
856863
path.asIndirect ++ extPostfix + IndirectStep.Allocated,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package edg.compiler
2+
3+
import edg.ExprBuilder.ValueExpr
4+
import edg.wir.{DesignPath, IndirectStep}
5+
import edg.wir.ProtoUtil.{ConstraintProtoToSeqMap, ParamProtoToSeqMap}
6+
import edgir.elem.elem
7+
import edgir.expr.expr
8+
import edgir.ref.ref
9+
10+
import scala.collection.SeqMap
11+
import scala.collection.mutable
12+
13+
/** Checks export tap validity, that inner-side parameters are undefined and elements are consistent.
14+
*/
15+
class ExportTapCheck(compiler: Compiler)
16+
extends DesignMap[Unit, Seq[CompilerError], Unit] {
17+
val portParams = mutable.HashMap[DesignPath, Seq[String]]()
18+
19+
def mapExported(
20+
containingPath: DesignPath,
21+
exportName: String,
22+
exported: expr.ExportedExpr
23+
): Seq[CompilerError] = {
24+
val (ValueExpr.Ref(extPort), ValueExpr.Ref(intPort)) = (exported.getExteriorPort, exported.getInternalBlockPort)
25+
portParams(containingPath ++ extPort).flatMap { paramName =>
26+
val paramPath = containingPath.asIndirect ++ intPort + paramName
27+
val exportedErrors = compiler.getValue(paramPath) match {
28+
case Some(_) => Seq(CompilerError.ExprError(
29+
paramPath,
30+
"export tap internal port parameter must be undefined"
31+
))
32+
case None => Seq()
33+
}
34+
exportedErrors ++ exported.expanded.flatMap(expr =>
35+
mapExported(containingPath, exportName, expr)
36+
)
37+
}
38+
}
39+
40+
def mapConstraint(
41+
containingPath: DesignPath,
42+
constrName: String,
43+
constr: expr.ValueExpr
44+
): Seq[CompilerError] = {
45+
constr.expr match {
46+
case expr.ValueExpr.Expr.Exported(exported) if exported.tap =>
47+
mapExported(containingPath, constrName, exported)
48+
case expr.ValueExpr.Expr.ExportedArray(exported) if exported.tap =>
49+
val (ValueExpr.Ref(extPort), ValueExpr.Ref(intPort)) = (exported.getExteriorPort, exported.getInternalBlockPort)
50+
val exportedArrayContainerErrors =
51+
if (
52+
compiler.getValue(containingPath.asIndirect ++ extPort + IndirectStep.Elements) == compiler.getValue(
53+
containingPath.asIndirect ++ intPort + IndirectStep.Elements
54+
)
55+
) {
56+
Seq()
57+
} else {
58+
Seq(CompilerError.ExprError(
59+
containingPath.asIndirect + constrName,
60+
"inconsistent export tap array port elements"
61+
))
62+
}
63+
exportedArrayContainerErrors ++ mapExported(containingPath, constrName, exported)
64+
case _ => Seq() // other constructs ignored
65+
}
66+
}
67+
68+
override def mapPort(path: DesignPath, port: elem.Port, ports: SeqMap[String, Unit]): Unit = {
69+
portParams.put(path, port.params.asPairs.map { case (name, _) => name }.toSeq)
70+
}
71+
override def mapPortArray(path: DesignPath, port: elem.PortArray, ports: SeqMap[String, Unit]): Unit = {
72+
portParams.put(path, Seq())
73+
}
74+
override def mapPortLibrary(path: DesignPath, port: ref.LibraryPath): Unit = {}
75+
76+
override def mapBlock(
77+
path: DesignPath,
78+
block: elem.HierarchyBlock,
79+
ports: SeqMap[String, Unit],
80+
blocks: SeqMap[String, Seq[CompilerError]],
81+
links: SeqMap[String, Unit]
82+
): Seq[CompilerError] = {
83+
block.constraints.asPairs.flatMap {
84+
case (name, constr) => mapConstraint(path, name, constr)
85+
}.toSeq ++ blocks.values.flatten
86+
}
87+
override def mapBlockLibrary(path: DesignPath, block: ref.LibraryPath): Seq[CompilerError] = {
88+
Seq() // block library errors should be checked elsewhere
89+
}
90+
91+
override def mapLink(
92+
path: DesignPath,
93+
link: elem.Link,
94+
ports: SeqMap[String, Unit],
95+
links: SeqMap[String, Unit]
96+
): Unit = {} // export tap not valid in links
97+
98+
override def mapLinkArray(
99+
path: DesignPath,
100+
link: elem.LinkArray,
101+
ports: SeqMap[String, Unit],
102+
links: SeqMap[String, Unit]
103+
): Unit = {} // export tap not valid in links
104+
105+
override def mapLinkLibrary(
106+
path: DesignPath,
107+
link: ref.LibraryPath
108+
): Unit = {} // link library errors should be checked elsewhere
109+
}

compiler/src/main/scala/edg/compiler/ExprToString.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,11 @@ class ExprToString() extends ValueExprMap[String] {
191191
expandedExteriorPort: String,
192192
expandedInterorPort: String
193193
): String = {
194-
s"exported($exteriorPort, $internalBlockPort)"
194+
if (!exported.tap) {
195+
s"exported($exteriorPort, $internalBlockPort)"
196+
} else {
197+
s"exported[tap]($exteriorPort, $internalBlockPort)"
198+
}
195199
}
196200

197201
override def mapExportedTunnel(

0 commit comments

Comments
 (0)