Skip to content

Commit 52b6b65

Browse files
author
Oron Port
committed
Clk/Rst casting and usage refactoring
1 parent 592dd32 commit 52b6b65

File tree

10 files changed

+178
-78
lines changed

10 files changed

+178
-78
lines changed

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dfhdl.compiler.ir
22
import scala.annotation.unchecked.uncheckedVariance
33
import dfhdl.internals.hashString
44
import upickle.default.*
5+
import scala.collection.mutable
56

67
type DFRefAny = DFRef[DFMember]
78
sealed trait DFRef[+M <: DFMember] extends Product, Serializable derives CanEqual:
@@ -139,21 +140,36 @@ extension (intCompanion: Int.type)
139140
case DFRef(dfVal: DFVal) =>
140141
dfVal.getConstData.asInstanceOf[Option[Option[BigInt]]].flatten.map(_.toInt)
141142

142-
class RefGen(private var grpId: (Int, Int), private var lastId: Int):
143+
class RefGen private (
144+
private var magnetID: Int,
145+
private var grpId: (Int, Int),
146+
private var lastId: Int
147+
) extends Serializable:
148+
private def nextMagnetID: Int =
149+
val newId = magnetID + 1
150+
magnetID = newId
151+
newId
143152
private def nextId: Int =
144153
val newId = lastId + 1
145154
lastId = newId
146155
newId
156+
private val magnetIDMap = mutable.Map.empty[Product, Int]
157+
def getMagnetID(t: Product): Int = magnetIDMap.getOrElseUpdate(t, nextMagnetID)
147158
def getGrpId: (Int, Int) = grpId
148159
def setGrpId(newGrpId: (Int, Int)): Unit =
149160
grpId = newGrpId
150161
def genOneWay[M <: DFMember]: DFRef.OneWay[M] = DFRef.OneWay.Gen(grpId, nextId)
151162
def genTwoWay[M <: DFMember, O <: DFMember]: DFRef.TwoWay[M, O] = DFRef.TwoWay.Gen(grpId, nextId)
152163
def genTypeRef: DFRef.TypeRef = DFRef.TypeRef(grpId, nextId)
164+
end RefGen
153165

154166
object RefGen:
167+
def initial: RefGen = RefGen(0, (0, 0), 0)
155168
def fromGetSet(using getSet: MemberGetSet): RefGen =
156169
val rt = getSet.designDB.refTable
157170
val grpId = rt.last._1.grpId
158171
val lastId = rt.keys.map(_.id).max
159-
RefGen(grpId, lastId)
172+
val magnetID = getSet.designDB.members.view.collect {
173+
case DFOpaque.Val(dfType) if dfType.isMagnet => dfType.id
174+
}.maxOption.getOrElse(0)
175+
RefGen(magnetID, grpId, lastId)

compiler/stages/src/test/scala/StagesSpec/AddClkRstSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ class AddClkRstSpec extends StageSpec:
298298
val gen = new RTDomain(genCfg):
299299
val clk = Clk <> OUT
300300
val rst = Rst <> OUT
301-
gen.clk <> src.clk
302-
gen.rst <> src.rst
301+
gen.clk <> src.clk.as(gen.Clk)
302+
gen.rst <> src.rst.as(gen.Rst)
303303
class ID extends RTDesign(cfg):
304304
val x = SInt(16) <> IN
305305
val y = SInt(16) <> OUT
@@ -324,8 +324,8 @@ class AddClkRstSpec extends StageSpec:
324324
| val gen = new RTDomain(genCfg):
325325
| val clk = Clk_genCfg <> OUT
326326
| val rst = Rst_genCfg <> OUT
327-
| gen.clk <> src.clk
328-
| gen.rst <> src.rst
327+
| gen.clk <> src.clk.as(Clk_genCfg)
328+
| gen.rst <> src.rst.as(Rst_genCfg)
329329
|end ClkGen
330330
|
331331
|class ID extends RTDesign(cfg):

compiler/stages/src/test/scala/StagesSpec/ExplicitClkRstCfgSpec.scala

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
4444
RstCfg(inclusionPolicy = RstCfg.InclusionPolicy.AlwaysAtTop)
4545
val eo = summon[options.ElaborationOptions]
4646
// force DFC with these elaboration options modifications (this is required because no @top annotation)
47-
val dfc = DFC.empty(eo)
47+
val dfc = DFC.empty(eo)
4848
def gen(using DFC): dfhdl.core.Design =
4949
class ID extends RTDesign:
5050
val x = SInt(16) <> IN
@@ -117,8 +117,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
117117
y := x
118118

119119
class IDTop extends EDDesign:
120-
val x = SInt(16) <> IN
121-
val y = SInt(16) <> OUT
120+
val x = SInt(16) <> IN
121+
val y = SInt(16) <> OUT
122122
val dmn1 = new RTDomain:
123123
val id = ID()
124124
id.x <> x
@@ -163,8 +163,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
163163
y := x
164164

165165
class IDTop extends EDDesign:
166-
val x = SInt(16) <> IN
167-
val y = SInt(16) <> OUT
166+
val x = SInt(16) <> IN
167+
val y = SInt(16) <> OUT
168168
val dmn1 = new RTDomain:
169169
val id = ID()
170170
id.x <> x
@@ -209,8 +209,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
209209
y := x
210210

211211
class IDTop extends RTDesign:
212-
val x = SInt(16) <> IN
213-
val y = SInt(16) <> OUT
212+
val x = SInt(16) <> IN
213+
val y = SInt(16) <> OUT
214214
val dmn1 = new RTDomain:
215215
val id = ID()
216216
id.x <> x
@@ -255,8 +255,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
255255
y := x
256256

257257
class IDTop extends RTDesign:
258-
val x = SInt(16) <> IN
259-
val y = SInt(16) <> OUT
258+
val x = SInt(16) <> IN
259+
val y = SInt(16) <> OUT
260260
val dmn1 = new RTDomain:
261261
val id = ID()
262262
id.x <> x
@@ -305,8 +305,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
305305
y := x.reg(1, init = 5)
306306

307307
class IDTop extends RTDesign:
308-
val x = SInt(16) <> IN
309-
val y = SInt(16) <> OUT
308+
val x = SInt(16) <> IN
309+
val y = SInt(16) <> OUT
310310
val dmn1 = new RTDomain(cfg):
311311
val id = ID()
312312
id.x <> x
@@ -435,8 +435,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
435435
y := x
436436

437437
class IDTop extends EDDesign:
438-
val x = SInt(16) <> IN
439-
val y = SInt(16) <> OUT
438+
val x = SInt(16) <> IN
439+
val y = SInt(16) <> OUT
440440
val dmn1 = new RTDomain:
441441
val id = ID()
442442
id.x <> x
@@ -486,12 +486,12 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
486486
val gen = new RTDomain(genCfg):
487487
val clk = Clk <> OUT
488488
val rst = Rst <> OUT
489-
gen.clk <> src.clk
490-
gen.rst <> src.rst
489+
gen.clk <> src.clk.as(gen.Clk)
490+
gen.rst <> src.rst.as(gen.Rst)
491491
class ID extends RTDesign(cfg):
492-
val x = SInt(16) <> IN
493-
val y = SInt(16) <> OUT
494-
val clkGen = new ClkGen(cfg, genCfg)
492+
val x = SInt(16) <> IN
493+
val y = SInt(16) <> OUT
494+
val clkGen = new ClkGen(cfg, genCfg)
495495
val internal = new RTDomain(genCfg):
496496
val x = SInt(16) <> IN
497497
val y = SInt(16) <> OUT
@@ -507,8 +507,8 @@ class ExplicitClkRstCfgSpec extends StageSpec(stageCreatesUnrefAnons = true):
507507
| val gen = new RTDomain(genCfg):
508508
| val clk = Clk <> OUT
509509
| val rst = Rst <> OUT
510-
| gen.clk <> src.clk
511-
| gen.rst <> src.rst
510+
| gen.clk <> src.clk.as(Clk)
511+
| gen.rst <> src.rst.as(Rst)
512512
|end ClkGen
513513
|
514514
|class ID extends RTDesign(cfg):

core/src/main/scala/dfhdl/core/Container.scala

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,6 @@ abstract class DomainContainer[D <: DomainType](domainType: D) extends Container
2727
final private[core] lazy val __domainType: ir.DomainType = domainType.asIR
2828

2929
abstract class RTDomainContainer(cfg: RTDomainCfg) extends DomainContainer(DomainType.RT(cfg)):
30-
31-
protected lazy val Clk: DFOpaque[DFOpaque.Clk] =
32-
case class Clk() extends DFOpaque.Clk
33-
cfg match
34-
case ir.RTDomainCfg.Related(ref) =>
35-
import dfc.getSet
36-
throw new IllegalArgumentException(
37-
s"Cannot create an explicit clock in a related domain.\nYou can create the clock in the primary domain `${ref.get.getName}` and reference it here instead."
38-
)
39-
case _ =>
40-
DFOpaque(Clk())
41-
end Clk
42-
43-
protected lazy val Rst: DFOpaque[DFOpaque.Rst] =
44-
case class Rst() extends DFOpaque.Rst
45-
cfg match
46-
case ir.RTDomainCfg.Related(ref) =>
47-
import dfc.getSet
48-
throw new IllegalArgumentException(
49-
s"Cannot create an explicit reset in a related domain.\nYou can create the reset in the primary domain `${ref.get.getName}` and reference it here instead."
50-
)
51-
case _ =>
52-
DFOpaque(Rst())
53-
end Rst
30+
final case class Clk() extends DFOpaque.Clk
31+
final case class Rst() extends DFOpaque.Rst
5432
end RTDomainContainer

core/src/main/scala/dfhdl/core/DFC.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final case class DFC(
1818
docOpt: Option[String],
1919
annotations: List[HWAnnotation] = Nil, // TODO: removing default causes stale symbol crash
2020
mutableDB: MutableDB = new MutableDB(),
21-
refGen: ir.RefGen = new ir.RefGen((0, 0), 0),
21+
refGen: ir.RefGen = ir.RefGen.initial,
2222
tags: ir.DFTags = ir.DFTags.empty,
2323
elaborationOptionsContr: () => ElaborationOptions = () =>
2424
summon[ElaborationOptions.Defaults[Design]]

core/src/main/scala/dfhdl/core/DFOpaque.scala

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,20 @@ object DFOpaque:
4343

4444
def apply[TFE <: Abstract](
4545
t: TFE
46-
)(using DFCG): DFOpaque[TFE] = trydf:
46+
)(using dfc: DFCG): DFOpaque[TFE] = trydf:
4747
val kind = t match
4848
case _: Clk => ir.DFOpaque.Kind.Clk
4949
case _: Rst => ir.DFOpaque.Kind.Rst
5050
case _: Magnet[?] => ir.DFOpaque.Kind.Magnet
5151
case _ => ir.DFOpaque.Kind.General
52-
// Generate a stable ID based on the fully qualified class name
53-
// This ensures different case classes have different IDs even if they have the same simple name
54-
// but are in different packages, and remains stable between runs
55-
val fullyQualifiedClassName = t.getClass.getName
56-
val id = fullyQualifiedClassName.hashCode
52+
val id = t match
53+
case _: Magnet[?] => dfc.refGen.getMagnetID(t)
54+
case _ =>
55+
// Generate a stable ID based on the fully qualified class name
56+
// This ensures different case classes have different IDs even if they have the same simple name
57+
// but are in different packages, and remains stable between runs
58+
val fullyQualifiedClassName = t.getClass.getName
59+
fullyQualifiedClassName.hashCode
5760
ir.DFOpaque(
5861
t.typeName,
5962
kind,
@@ -126,6 +129,40 @@ object DFOpaque:
126129
}(using dfc, CTName("cast as opaque"))
127130
end evOpAsDFOpaqueIterable
128131

132+
given evOpClkAsClkComp[
133+
LTFE <: Clk,
134+
L <: DFValOf[DFOpaque[LTFE]],
135+
Comp <: Object,
136+
TFE <: Clk
137+
](using
138+
cc: CaseClass.Aux[Comp, Clk, TFE]
139+
)(using
140+
ce: ClassEv[TFE]
141+
): ExactOp2Aux["as", DFC, DFValAny, L, Comp, DFValOf[DFOpaque[TFE]]] =
142+
new ExactOp2["as", DFC, DFValAny, L, Comp]:
143+
type Out = DFValOf[DFOpaque[TFE]]
144+
def apply(lhs: L, tfeComp: Comp)(using DFC): Out = trydf {
145+
DFVal.Alias.AsIs(DFOpaque[TFE](ce.value), lhs)
146+
}(using dfc, CTName("cast clk as a different clk"))
147+
end evOpClkAsClkComp
148+
149+
given evOpRstAsRstComp[
150+
LTFE <: Rst,
151+
L <: DFValOf[DFOpaque[LTFE]],
152+
Comp <: Object,
153+
TFE <: Rst
154+
](using
155+
cc: CaseClass.Aux[Comp, Rst, TFE]
156+
)(using
157+
ce: ClassEv[TFE]
158+
): ExactOp2Aux["as", DFC, DFValAny, L, Comp, DFValOf[DFOpaque[TFE]]] =
159+
new ExactOp2["as", DFC, DFValAny, L, Comp]:
160+
type Out = DFValOf[DFOpaque[TFE]]
161+
def apply(lhs: L, tfeComp: Comp)(using DFC): Out = trydf {
162+
DFVal.Alias.AsIs(DFOpaque[TFE](ce.value), lhs)
163+
}(using dfc, CTName("cast rst as a different rst"))
164+
end evOpRstAsRstComp
165+
129166
private def asDFVector[A <: DFTypeAny, P](dfVals: Iterable[DFValTP[A, P]])(using
130167
DFC
131168
): DFValTP[DFVector[A, Tuple1[Int]], P] =

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

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,7 +1177,7 @@ object DFVal extends DFValLP:
11771177
export DFPhysical.Val.Ops.given
11781178
export TDFDouble.Val.Ops.given
11791179
export DFEnum.Val.Ops.given
1180-
export DFOpaque.Val.Ops.evOpAsDFOpaqueIterable
1180+
export DFOpaque.Val.Ops.{evOpAsDFOpaqueIterable, evOpClkAsClkComp, evOpRstAsRstComp}
11811181
export TDFString.Val.Ops.given
11821182
export ConnectOps.given
11831183

@@ -1252,8 +1252,9 @@ object DFVal extends DFValLP:
12521252
// connection in either direction where both implicit directions are available
12531253
inline if (lhsIsDFVal && rhsIsDFVal)
12541254
inline lhs match
1255-
case lhs: DFValAny => inline rhs match
1256-
case rhs: DFValAny => ConnectOps.specialConnect(lhs, rhs)
1255+
case lhs: DFVal[lt, lm] => inline rhs match
1256+
case rhs: DFVal[rt, rm] =>
1257+
ConnectOps.specialConnect[lt, lm, rt, rm](lhs, rhs)
12571258
// if the RHS is a modifier, this is a port/variable constructor,
12581259
// so we invoke the the implicit given operation only in one way
12591260
else if (rhsIsModifier) exactOp2["<>", DFC, Any](lhs, rhs)
@@ -1541,24 +1542,34 @@ object ConnectOps:
15411542
]
15421543
protected type ConnectableModifier[M <: ModifierAny] =
15431544
M <:< Modifier[Any, Modifier.Connectable, Any, Any]
1544-
protected trait TC_Connect[Consumer <: DFValAny, Producer <: DFValAny]:
1545-
def connect(consumer: Consumer, producer: Producer)(using DFC): Unit
1545+
protected trait TC_Connect[
1546+
CT <: DFTypeAny,
1547+
CM <: ModifierAny,
1548+
PT <: DFTypeAny,
1549+
PM <: ModifierAny
1550+
]:
1551+
def connect(consumer: DFVal[CT, CM], producer: DFVal[PT, PM])(using DFC): Unit
15461552
protected object TC_Connect:
15471553
given [
15481554
CT <: DFTypeAny,
15491555
CM <: ModifierAny,
1550-
Consumer <: DFVal[CT, CM],
1551-
Producer <: DFValAny
1556+
PT <: DFTypeAny,
1557+
PM <: ModifierAny
15521558
](using
15531559
ConnectableModifier[CM]
1554-
)(using tc: DFVal.TC[CT, Producer]): TC_Connect[Consumer, Producer] with
1555-
def connect(consumer: Consumer, producer: Producer)(using DFC): Unit =
1560+
)(using tc: DFVal.TC[CT, DFVal[PT, PM]]): TC_Connect[CT, CM, PT, PM] with
1561+
def connect(consumer: DFVal[CT, CM], producer: DFVal[PT, PM])(using DFC): Unit =
15561562
consumer.connect(tc(consumer.dfType, producer))
15571563

1558-
private def specialConnectRuntime[L <: DFValAny, R <: DFValAny](
1559-
lhs: L,
1560-
rhs: R,
1561-
dualSummon: DualSummonTrapError[TC_Connect[L, R], TC_Connect[R, L]]
1564+
private def specialConnectRuntime[
1565+
CT <: DFTypeAny,
1566+
CM <: ModifierAny,
1567+
PT <: DFTypeAny,
1568+
PM <: ModifierAny
1569+
](
1570+
lhs: DFVal[CT, CM],
1571+
rhs: DFVal[PT, PM],
1572+
dualSummon: DualSummonTrapError[TC_Connect[CT, CM, PT, PM], TC_Connect[PT, PM, CT, CM]]
15621573
)(using dfc: DFC): Unit = trydf {
15631574
(dualSummon.valueL, dualSummon.valueR) match
15641575
case (Some(tcL), Some(tcR)) =>
@@ -1573,12 +1584,19 @@ object ConnectOps:
15731584
end match
15741585
}(using dfc, CTName("<>"))
15751586

1576-
private[core] transparent inline def specialConnect[L <: DFValAny, R <: DFValAny](
1577-
inline lhs: L,
1578-
inline rhs: R
1587+
private[core] transparent inline def specialConnect[
1588+
LT <: DFTypeAny,
1589+
LM <: ModifierAny,
1590+
RT <: DFTypeAny,
1591+
RM <: ModifierAny
1592+
](
1593+
inline lhs: DFVal[LT, LM],
1594+
inline rhs: DFVal[RT, RM]
15791595
)(using dfc: DFC): Unit =
1580-
val dualSummon =
1581-
compiletime.summonInline[DualSummonTrapError[TC_Connect[L, R], TC_Connect[R, L]]]
1596+
val dualSummon = compiletime.summonInline[DualSummonTrapError[
1597+
TC_Connect[LT, LM, RT, RM],
1598+
TC_Connect[RT, RM, LT, LM]
1599+
]]
15821600
specialConnectRuntime(lhs, rhs, dualSummon)
15831601
end specialConnect
15841602

0 commit comments

Comments
 (0)