Skip to content

Commit 70d9eec

Browse files
author
Oron Port
committed
project constraints from resources to connected dfVals
1 parent 0ab42c1 commit 70d9eec

File tree

6 files changed

+87
-28
lines changed

6 files changed

+87
-28
lines changed

compiler/ir/src/main/scala/dfhdl/compiler/ir/annotation.scala

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ object constraints:
6161
import annotation.HWAnnotation
6262
sealed abstract class Constraint extends HWAnnotation derives ReadWriter
6363
sealed abstract class GlobalConstraint extends Constraint derives ReadWriter
64-
sealed abstract class SigConstraint extends Constraint derives ReadWriter:
64+
sealed abstract class SigConstraint extends Constraint, HasTypeName derives ReadWriter:
6565
def merge(that: SigConstraint): Option[SigConstraint] =
6666
if (this == that) Some(this) else None
67+
def updateBitIdx(bitIdx: ConfigN[Int]): SigConstraint
6768
val bitIdx: ConfigN[Int]
6869
final case class Device(name: String, properties: Map[String, String]) extends GlobalConstraint
6970
derives CanEqual, ReadWriter:
@@ -83,6 +84,7 @@ object constraints:
8384
case (t1: T @unchecked, t2: T @unchecked) if t1 equals t2 => t1
8485
case x => throw new IllegalArgumentException("Constraint merge error: " + x)
8586
extension (list: List[SigConstraint])
87+
/** Merge constraints that are of the same type and are mergeable. */
8688
def merge: List[SigConstraint] =
8789
list.foldLeft(List.empty[SigConstraint]) { (acc, cs) =>
8890
var merged = false
@@ -97,6 +99,19 @@ object constraints:
9799
if (merged) newAcc
98100
else cs :: newAcc
99101
}.reverse
102+
103+
/** Consolidate several constraints that are all the same for all the bits into a single
104+
* constraint. This should be applied after merging.
105+
*/
106+
def consolidate(length: Int)(using MemberGetSet): List[SigConstraint] =
107+
list.groupByOrdered(_.typeName).map {
108+
case (typeName, cs) if cs.length == length =>
109+
val consolidated = cs.map(_.updateBitIdx(None))
110+
if (consolidated.forall(_ =~ consolidated.head))
111+
consolidated.head :: Nil
112+
else cs
113+
case (typeName, cs) => cs
114+
}.flatten
100115
end extension
101116

102117
private def csParam[T](name: String, value: ConfigN[T])(using printer: Printer): String =
@@ -134,6 +149,8 @@ object constraints:
134149
)
135150
)
136151
case _ => None
152+
def updateBitIdx(bitIdx: ConfigN[Int]): SigConstraint =
153+
this.copy(bitIdx = bitIdx)
137154
def codeString(using Printer): String =
138155
val params = List(
139156
csParam("bitIdx", bitIdx),
@@ -166,12 +183,15 @@ object constraints:
166183
protected def `prot_=~`(that: HWAnnotation)(using MemberGetSet): Boolean = this == that
167184
lazy val getRefs: List[DFRef.TwoWayAny] = Nil
168185
def copyWithNewRefs(using RefGen): this.type = this
186+
def updateBitIdx(bitIdx: ConfigN[Int]): SigConstraint =
187+
this.copy(bitIdx = bitIdx)
169188
def codeString(using Printer): String =
170189
val params = List(
171190
csParam("bitIdx", bitIdx),
172191
csParam("maxFreqMinPeriod", maxFreqMinPeriod)
173192
).filter(_.nonEmpty).mkString(", ")
174193
s"""@timing.ignore($params)"""
194+
end Ignore
175195

176196
final case class Clock(
177197
rate: RateNumber

core/src/main/scala/dfhdl/core/DFVal.scala

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import DFOpaque.Abstract as DFOpaqueA
1212
import dfhdl.compiler.ir.MemberGetSet
1313
import dfhdl.compiler.printing.{DefaultPrinter, Printer}
1414
import scala.annotation.tailrec
15+
import dfhdl.platforms.resources.Resource
1516

1617
import scala.reflect.ClassTag
1718
final class DFVal[+T <: DFTypeAny, +M <: ModifierAny](val irValue: ir.DFVal | DFError)
@@ -1040,15 +1041,26 @@ object DFVal extends DFValLP:
10401041
export DFTuple.Val.TCConv.given
10411042
export DFVector.Val.TCConv.given
10421043

1043-
trait TC_Or_OPEN[T <: DFTypeAny, R] extends TC[T, R]
1044-
object TC_Or_OPEN:
1045-
type Exact[T <: DFTypeAny] = Exact1[DFTypeAny, T, [t <: DFTypeAny] =>> t, DFC, TC_Or_OPEN]
1046-
given fromOPEN[T <: DFTypeAny]: TC_Or_OPEN[T, OPEN] with
1044+
trait TC_Or_OPEN_Or_Resource[T <: DFTypeAny, R] extends TC[T, R]
1045+
object TC_Or_OPEN_Or_Resource:
1046+
type Exact[T <: DFTypeAny] =
1047+
Exact1[DFTypeAny, T, [t <: DFTypeAny] =>> t, DFC, TC_Or_OPEN_Or_Resource]
1048+
given fromOPEN[T <: DFTypeAny]: TC_Or_OPEN_Or_Resource[T, OPEN] with
10471049
type OutP = NOTCONST
10481050
def conv(dfType: T, from: OPEN)(using DFC): Out = DFVal.OPEN(dfType)
1049-
given fromTC[T <: DFTypeAny, R, TC <: DFVal.TC[T, R]](using tc: TC): TC_Or_OPEN[T, R] with
1051+
given fromTC[
1052+
T <: DFTypeAny,
1053+
R,
1054+
TC <: DFVal.TC[T, R]
1055+
](using tc: TC): TC_Or_OPEN_Or_Resource[T, R] with
10501056
type OutP = tc.OutP
10511057
def conv(dfType: T, from: R)(using DFC): Out = tc(dfType, from)
1058+
given fromResource[T <: DFTypeAny, R <: Resource](using
1059+
Resource.CanConnect[R, DFValOf[T]] // just type checking
1060+
): TC_Or_OPEN_Or_Resource[T, R] with
1061+
type OutP = NOTCONST
1062+
def conv(dfType: T, from: R)(using DFC): Out = ???
1063+
end TC_Or_OPEN_Or_Resource
10521064

10531065
trait Compare[T <: DFTypeAny, V, Op <: FuncOp, C <: Boolean] extends TCCommon[T, V, DFValAny]:
10541066
type OutP
@@ -1225,9 +1237,30 @@ extension [T <: DFTypeAny](dfVar: DFValOf[T])
12251237
DFNet(dfVar.asIR, DFNet.Op.NBAssignment, rhs.asIR)
12261238

12271239
extension [T <: DFTypeAny](lhs: DFValOf[T])
1240+
def connect(resource: Resource)(using dfc: DFC): Unit =
1241+
import dfc.getSet
1242+
lhs.asIR.departialDcl match
1243+
case Some(dcl, range) =>
1244+
val newSigConstraints =
1245+
if (range.length != dcl.width) resource.allSigConstraints.flatMap { cs =>
1246+
for (i <- range) yield cs.updateBitIdx(i)
1247+
}
1248+
else resource.allSigConstraints
1249+
val (existingSigConstraints, otherAnnotations) = dcl.meta.annotations.partition {
1250+
case cs: ir.constraints.SigConstraint => true
1251+
case _ => false
1252+
}.asInstanceOf[(List[ir.constraints.SigConstraint], List[ir.annotation.HWAnnotation])]
1253+
val updatedSigConstraints =
1254+
(existingSigConstraints ++ newSigConstraints).merge.consolidate(dcl.width)
1255+
val updatedAnnotations = updatedSigConstraints ++ otherAnnotations
1256+
dcl.setMeta(m => m.copy(annotations = updatedAnnotations))
1257+
case None =>
1258+
end match
1259+
end connect
12281260
def connect[R <: DFTypeAny](rhs: DFValOf[R])(using DFC): Unit =
12291261
val op = if (dfc.lateConstruction) DFNet.Op.ViaConnection else DFNet.Op.Connection
12301262
DFNet(lhs.asIR, op, rhs.asIR)
1263+
end extension
12311264

12321265
trait VarsTuple[T <: NonEmptyTuple]:
12331266
type Width <: Int
@@ -1418,17 +1451,21 @@ object DFVarOps:
14181451
end DFVarOps
14191452

14201453
object DFPortOps:
1421-
protected type ConnectableOnly[C] = AssertGiven[
1422-
C <:< Modifier.Connectable,
1454+
protected type ConnectableOnly[C, R] = AssertGiven[
1455+
C <:< Modifier.Connectable | R <:< Resource,
14231456
"The LHS of a connection must be a connectable DFHDL value (var/port)."
14241457
]
14251458
extension [T <: DFTypeAny, C](dfPort: DFVal[T, Modifier[Any, C, Any, Any]])
1426-
def <>(rhs: DFVal.TC_Or_OPEN.Exact[T])(using
1459+
def <>(rhs: DFVal.TC_Or_OPEN_Or_Resource.Exact[T])(using
14271460
DFC
14281461
)(using
1429-
connectableOnly: ConnectableOnly[C]
1462+
connectableOnly: ConnectableOnly[C, rhs.ExactFrom]
14301463
): ConnectPlaceholder =
1431-
trydf { dfPort.connect(rhs(dfPort.dfType)) }
1464+
trydf {
1465+
rhs.exactFrom match
1466+
case resource: Resource => dfPort.connect(resource)
1467+
case _ => dfPort.connect(rhs(dfPort.dfType))
1468+
}
14321469
ConnectPlaceholder
14331470
end extension
14341471
end DFPortOps

core/src/main/scala/dfhdl/hdl.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ protected object hdl:
2626
export internals.CommonOps.*
2727
export core.{dfType}
2828
export core.DFPhysical.Val.Ops.*
29+
export platforms.resources.Resource.Ops.*
2930
export core.COMB_LOOP
3031
type Time = core.DFTime
3132
val Time = core.DFTime

core/src/main/scala/dfhdl/platforms/resources/Resource.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dfhdl.platforms.resources
22
import scala.annotation.implicitNotFound
33
import scala.collection.mutable
44
import dfhdl.compiler.ir.constraints.SigConstraint
5+
import dfhdl.core.*
56

67
trait Resource extends ResourceContext:
78
private val connections = mutable.ListBuffer[Resource]()
@@ -34,14 +35,18 @@ private trait ResourceLP:
3435
cc.connect(resource2, resource1)
3536

3637
object Resource extends ResourceLP:
37-
@implicitNotFound("Cannot connect the resources ${T} and ${R}")
38-
trait CanConnect[T <: Resource, R <: Resource]:
38+
@implicitNotFound("Cannot connect the resource ${T} with ${R}")
39+
trait CanConnect[T <: Resource, R]:
3940
def connect(resource1: T, resource2: R): Unit
4041
given [T <: Resource, R <: Resource](using T =:= R): CanConnect[T, R] =
4142
(resource1: T, resource2: R) =>
4243
resource1.connect(resource2)
4344
resource2.connect(resource1)
45+
given [T <: Resource, R <: DFValAny](using DFC): CanConnect[T, R] =
46+
(resource: T, dfVal: R) => dfVal.connect(resource)
4447

45-
extension [T <: Resource](self: T)
46-
def <>[R <: Resource](that: R)(using cc: CanConnect[T, R]): Unit =
47-
cc.connect(self, that)
48+
object Ops:
49+
extension [T <: Resource](self: T)
50+
def <>[R](that: R)(using cc: CanConnect[T, R]): Unit =
51+
cc.connect(self, that)
52+
end Resource

core/src/main/scala/dfhdl/platforms/resources/ResourceOwner.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ trait ResourceOwner extends ResourceContext:
2929
dfc.mutableDB.ResourceOwnershipContext.exit()
3030
dfc.mutableDB.ResourceOwnershipContext.ownerOpt.foreach(_.children += this)
3131
projectGlobalConstraints()
32+
33+
export Resource.Ops.*
3234
end ResourceOwner

internals/src/main/scala/dfhdl/internals/helpers.scala

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -326,18 +326,12 @@ extension (str: String)
326326
end extension
327327
extension [T](seq: Iterable[T])
328328
def groupByOrdered[P](f: T => P): List[(P, List[T])] =
329-
@tailrec
330-
def accumulator(
331-
seq: Iterable[T],
332-
f: T => P,
333-
res: List[(P, Iterable[T])]
334-
): Seq[(P, Iterable[T])] = seq.headOption match
335-
case None => res.reverse
336-
case Some(h) =>
337-
val key = f(h)
338-
val subseq = seq.takeWhile(f(_) equals key)
339-
accumulator(seq.drop(subseq.size), f, (key -> subseq) :: res)
340-
accumulator(seq, f, Nil).view.map(e => (e._1, e._2.toList)).toList
329+
val buf = mutable.LinkedHashMap.empty[P, mutable.ListBuffer[T]]
330+
for (elem <- seq)
331+
val key = f(elem)
332+
buf.getOrElseUpdate(key, mutable.ListBuffer.empty) += elem
333+
buf.iterator.map { case (k, v) => (k, v.toList) }.toList
334+
end extension
341335

342336
lazy val getShellCommand: Option[String] =
343337
import scala.io.Source

0 commit comments

Comments
 (0)