Skip to content

Commit e8b65cd

Browse files
authored
Merge pull request #297 from DFiantHDL/opsrefactor
almost at v0.16.0
2 parents 95f53de + a0d62c0 commit e8b65cd

File tree

215 files changed

+8320
-5937
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

215 files changed

+8320
-5937
lines changed

.scalafmt.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = 3.9.9
1+
version = 3.9.10
22
runner.dialect = scala3
33

44
maxColumn = 100

build.sbt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ commands += DFHDLCommands.docExamplesRefUpdate
55

66
// format: off
77
val projectName = "dfhdl"
8-
val compilerVersion = "3.7.2"
8+
val compilerVersion = "3.7.4-RC1"
99

1010
inThisBuild(
1111
List(
@@ -135,11 +135,11 @@ lazy val platforms = project
135135
lazy val dependencies =
136136
new {
137137
private val scodecV = "1.2.4"
138-
private val munitV = "1.1.1"
139-
private val airframelogV = "2025.1.16"
140-
private val oslibV = "0.9.2"
138+
private val munitV = "1.2.0"
139+
private val airframelogV = "2025.1.19"
140+
private val oslibV = "0.11.5"
141141
private val scallopV = "5.2.0"
142-
private val upickleV = "4.2.1"
142+
private val upickleV = "4.3.2"
143143

144144
val scodec = "org.scodec" %% "scodec-bits" % scodecV
145145
val munit = "org.scalameta" %% "munit" % munitV % Test
@@ -153,7 +153,8 @@ lazy val commonDependencies = Seq(
153153
dependencies.scodec,
154154
dependencies.munit,
155155
dependencies.airframelog,
156-
dependencies.scallop
156+
dependencies.scallop,
157+
dependencies.oslib
157158
)
158159

159160
// SETTINGS

compiler/ir/src/main/scala/dfhdl/compiler/analysis/DFValAnalysis.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,7 @@ extension (members: List[DFMember])
462462
case _ => Nil
463463
}
464464
members.view.filter(_.isPublicMember).flatMap {
465-
case p: DFVal.DesignParam => getPublicMembersDeps(p).reverse
466-
case m => Some(m)
465+
case m => getPublicMembersDeps(m).reverse
467466
}.toList.distinct
468467
end extension
469468

compiler/ir/src/main/scala/dfhdl/compiler/analysis/StateAnalysis.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ object StateAnalysis:
1616
val currentBlock = summon[DFBlock]
1717
val access = immutable.BitSet.empty ++ (relBitLow until relBitLow + relWidth)
1818
value match
19-
case DFVal.Alias.AsIs(dfType = toType, relValRef = relValRef) =>
19+
case dfVal: DFVal.Alias if dfVal.relValRef.get.dfType.isUnbounded => currentSet
20+
case DFVal.Alias.AsIs(dfType = toType, relValRef = relValRef) =>
2021
val relVal = relValRef.get
2122
if (toType.width == relVal.width)
2223
// casting maintains relative bit consumption

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ object ConfigN:
3737
def flatMap[R](f: T => ConfigN[R]): ConfigN[R] = x match
3838
case None => None
3939
case value: T @unchecked => f(value)
40+
def toOption: Option[T] = x match
41+
case None => None
42+
case value: T @unchecked => Some(value)
4043
def toList: List[T] = x match
4144
case None => Nil
4245
case value: T @unchecked => List(value)
46+
def nonEmpty: Boolean = x != None
47+
def isEmpty: Boolean = x == None
4348
end extension
4449
extension [T <: DFRefAny](x: ConfigN[T])
4550
def =~(that: ConfigN[T])(using MemberGetSet): Boolean = (x, that) match

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

Lines changed: 152 additions & 53 deletions
Large diffs are not rendered by default.

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

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import upickle.default.*
55
import scala.annotation.tailrec
66
import scala.collection.immutable.ListMap
77
import scala.reflect.{ClassTag, classTag}
8+
import dfhdl.compiler.ir.PhysicalNumber.Ops.MHz
89

910
sealed trait DFMember extends Product, Serializable, HasRefCompare[DFMember] derives CanEqual:
1011
val ownerRef: DFOwner.Ref
@@ -19,7 +20,7 @@ sealed trait DFMember extends Product, Serializable, HasRefCompare[DFMember] der
1920
final def getOwner(using MemberGetSet): DFOwner = ownerRef.get match
2021
case o: DFOwner => o
2122
case _: DFMember.Empty =>
22-
throw new IllegalArgumentException(s"No owner found for member $this.")
23+
throw new Exception(s"No owner found for member $this.")
2324
final def getOwnerNamed(using MemberGetSet): DFOwnerNamed = getOwner match
2425
case b: DFOwnerNamed => b
2526
case o => o.getOwnerNamed
@@ -133,6 +134,16 @@ object DFMember:
133134
case _ => None
134135
})
135136
def toJson(using Writer[DFMember]): String = write(member)
137+
def getConstraints: List[constraints.Constraint] =
138+
val allAnnotations = member match
139+
case design: DFDesignBlock =>
140+
design.dclMeta.annotations.view ++ design.meta.annotations
141+
case interface: DFInterfaceOwner =>
142+
interface.dclMeta.annotations.view ++ interface.meta.annotations
143+
case _ => member.meta.annotations.view
144+
allAnnotations.collect {
145+
case c: constraints.Constraint => c
146+
}.toList
136147
end extension
137148

138149
sealed trait Empty extends DFMember:
@@ -217,7 +228,9 @@ sealed trait DFVal extends DFMember.Named:
217228
if (cachedConstDataReady) cachedConstData
218229
else
219230
cachedConstData = protGetConstData
220-
cachedConstDataReady = true
231+
// disable None constant data caching during mutation, since some data like CLK_FREQ
232+
// cannot be attained during mutation and returns None
233+
if (!(getSet.isMutable && cachedConstData == None)) cachedConstDataReady = true
221234
cachedConstData
222235
def updateDFType(dfType: DFType): this.type
223236
end DFVal
@@ -226,13 +239,12 @@ object DFVal:
226239
type Ref = DFRef.TwoWay[DFVal, DFMember]
227240
given ReadWriter[DFVal] = ReadWriter.merge(
228241
summon[ReadWriter[DFVal.Dcl]],
229-
summon[ReadWriter[DFVal.OPEN]],
242+
summon[ReadWriter[DFVal.Special]],
230243
summon[ReadWriter[DFVal.Alias]],
231244
summon[ReadWriter[DFVal.Const]],
232245
summon[ReadWriter[DFVal.DesignParam]],
233246
summon[ReadWriter[DFVal.Func]],
234-
summon[ReadWriter[DFVal.PortByNameSelect]],
235-
summon[ReadWriter[DFVal.NOTHING]]
247+
summon[ReadWriter[DFVal.PortByNameSelect]]
236248
)
237249
final case class Modifier(dir: Modifier.Dir, special: Modifier.Special)
238250
derives CanEqual,
@@ -278,18 +290,18 @@ object DFVal:
278290
case _ => false
279291
case _ => false
280292
def isOpen: Boolean = dfVal match
281-
case _: DFVal.OPEN => true
282-
case _ => false
293+
case DFVal.Special(kind = DFVal.Special.OPEN) => true
294+
case _ => false
283295
def isDesignParam: Boolean = dfVal match
284296
case _: DFVal.DesignParam => true
285297
case _ => false
286298
def isReg: Boolean = dfVal match
287299
case dcl: DFVal.Dcl => dcl.modifier.isReg
288300
case _ => false
289-
@tailrec def dealias(using MemberGetSet): Option[DFVal.Dcl | DFVal.OPEN] = dfVal match
301+
@tailrec def dealias(using MemberGetSet): Option[DFVal.Dcl | DFVal.Special] = dfVal match
290302
case dcl: DFVal.Dcl => Some(dcl)
291303
case portByNameSelect: DFVal.PortByNameSelect => Some(portByNameSelect.getPortDcl)
292-
case open: DFVal.OPEN => Some(open)
304+
case open: DFVal.Special if open.isOpen => Some(open)
293305
case alias: DFVal.Alias => alias.relValRef.get.dealias
294306
case _ => None
295307
@tailrec private def departial(range: Range)(using MemberGetSet): (DFVal, Range) =
@@ -455,38 +467,28 @@ object DFVal:
455467
type Ref = DFRef.TwoWay[DFVal, DesignParam]
456468
type DefaultRef = DFRef.TwoWay[DFVal | DFMember.Empty, DesignParam]
457469

458-
final case class OPEN(
459-
dfType: DFType,
460-
ownerRef: DFOwner.Ref
461-
) extends DFVal derives ReadWriter:
462-
val meta: Meta = Meta(None, Position.unknown, None, Nil)
463-
val tags: DFTags = DFTags.empty
464-
protected def protIsFullyAnonymous(using MemberGetSet): Boolean = true
465-
protected def protGetConstData(using MemberGetSet): Option[Any] = None
466-
protected def `prot_=~`(that: DFMember)(using MemberGetSet): Boolean = that match
467-
case _: OPEN => true
468-
case _ => false
469-
protected def setMeta(meta: Meta): this.type = this
470-
protected def setTags(tags: DFTags): this.type = this
471-
lazy val getRefs: List[DFRef.TwoWayAny] = dfType.getRefs ++ meta.getRefs
472-
def updateDFType(dfType: DFType): this.type = copy(dfType = dfType).asInstanceOf[this.type]
473-
def copyWithNewRefs(using RefGen): this.type = copy(
474-
dfType = dfType.copyWithNewRefs,
475-
ownerRef = ownerRef.copyAsNewRef
476-
).asInstanceOf[this.type]
477-
end OPEN
478-
479-
final case class NOTHING(
470+
final case class Special(
480471
dfType: DFType,
472+
kind: Special.Kind,
481473
ownerRef: DFOwner.Ref,
482474
meta: Meta,
483475
tags: DFTags
484476
) extends CanBeExpr derives ReadWriter:
485477
protected def protIsFullyAnonymous(using MemberGetSet): Boolean = true
486-
protected def protGetConstData(using MemberGetSet): Option[Any] = None
478+
protected def protGetConstData(using MemberGetSet): Option[Any] = kind match
479+
case Special.CLK_FREQ =>
480+
if (getSet.isMutable) None // disable during elaboration
481+
else
482+
Some(getSet.designDB.explicitRTDomainCfgMap(
483+
this.getOwnerDomain
484+
).clkCfg.toOption.map(_.rate.to_freq).getOrElse(0.MHz))
485+
case _ => None
487486
protected def `prot_=~`(that: DFMember)(using MemberGetSet): Boolean = that match
488-
case _: NOTHING => true
489-
case _ => false
487+
case that: Special =>
488+
this.dfType =~ that.dfType && this.kind == that.kind &&
489+
this.meta =~ that.meta && this.tags =~ that.tags
490+
491+
case _ => false
490492
protected[ir] def protIsSimilarTo(that: CanBeExpr)(using MemberGetSet): Boolean =
491493
this == that
492494
protected def setMeta(meta: Meta): this.type = copy(meta = meta).asInstanceOf[this.type]
@@ -498,7 +500,11 @@ object DFVal:
498500
dfType = dfType.copyWithNewRefs,
499501
ownerRef = ownerRef.copyAsNewRef
500502
).asInstanceOf[this.type]
501-
end NOTHING
503+
end Special
504+
object Special:
505+
enum Kind extends StableEnum derives CanEqual, ReadWriter:
506+
case NOTHING, OPEN, CLK_FREQ
507+
export Kind.{NOTHING, OPEN, CLK_FREQ}
502508

503509
final case class Dcl(
504510
dfType: DFType,
@@ -1013,7 +1019,7 @@ object DFNet:
10131019
MemberGetSet
10141020
): Option[
10151021
(
1016-
toVal: DFVal.Dcl | DFVal.OPEN | DFInterfaceOwner,
1022+
toVal: DFVal.Dcl | DFVal.Special | DFInterfaceOwner,
10171023
fromVal: DFVal | DFInterfaceOwner,
10181024
swapped: Boolean
10191025
)
@@ -1098,19 +1104,21 @@ object DFOwner:
10981104

10991105
final case class DFInterfaceOwner(
11001106
domainType: DomainType,
1107+
dclMeta: Meta,
11011108
ownerRef: DFOwner.Ref,
11021109
meta: Meta,
11031110
tags: DFTags
11041111
) extends DFDomainOwner derives ReadWriter:
11051112
protected def `prot_=~`(that: DFMember)(using MemberGetSet): Boolean = that match
11061113
case that: DFInterfaceOwner =>
11071114
this.domainType =~ that.domainType &&
1108-
this.meta =~ that.meta && this.tags =~ that.tags
1115+
this.dclMeta =~ that.dclMeta && this.meta =~ that.meta && this.tags =~ that.tags
11091116
case _ => false
11101117
protected def setMeta(meta: Meta): this.type = copy(meta = meta).asInstanceOf[this.type]
11111118
protected def setTags(tags: DFTags): this.type = copy(tags = tags).asInstanceOf[this.type]
11121119
lazy val getRefs: List[DFRef.TwoWayAny] = domainType.getRefs ++ meta.getRefs
11131120
def copyWithNewRefs(using RefGen): this.type = copy(
1121+
dclMeta = dclMeta.copyWithNewRefs,
11141122
meta = meta.copyWithNewRefs,
11151123
domainType = domainType.copyWithNewRefs,
11161124
ownerRef = ownerRef.copyAsNewRef
@@ -1447,15 +1455,26 @@ final case class DFDesignBlock(
14471455
protected def `prot_=~`(that: DFMember)(using MemberGetSet): Boolean = that match
14481456
case that: DFDesignBlock =>
14491457
this.domainType =~ that.domainType &&
1450-
this.dclMeta == that.dclMeta &&
1458+
this.dclMeta =~ that.dclMeta &&
14511459
this.instMode == that.instMode &&
14521460
this.meta =~ that.meta && this.tags =~ that.tags
14531461
case _ => false
14541462
protected def setMeta(meta: Meta): this.type = copy(meta = meta).asInstanceOf[this.type]
14551463
protected def setTags(tags: DFTags): this.type = copy(tags = tags).asInstanceOf[this.type]
1456-
lazy val getRefs: List[DFRef.TwoWayAny] = domainType.getRefs
1464+
lazy val getRefs: List[DFRef.TwoWayAny] = domainType.getRefs ++ dclMeta.getRefs
1465+
1466+
/** Whether this design is considered to be a device's top-level design. THIS MAY NOT BE THE TOP
1467+
* DESIGN, for example if the design is in a simulation. A design is considered to be a device
1468+
* top-level design if it has a device ID constraint (usually as a result of a device resource
1469+
* instantiated within).
1470+
*/
1471+
lazy val isDeviceTop: Boolean = this.getConstraints.exists {
1472+
case _: constraints.DeviceID => true
1473+
case _ => false
1474+
}
14571475
def copyWithNewRefs(using RefGen): this.type = copy(
14581476
meta = meta.copyWithNewRefs,
1477+
dclMeta = dclMeta.copyWithNewRefs,
14591478
domainType = domainType.copyWithNewRefs,
14601479
ownerRef = ownerRef.copyAsNewRef
14611480
).asInstanceOf[this.type]
@@ -1465,17 +1484,21 @@ object DFDesignBlock:
14651484
import InstMode.BlackBox.Source
14661485
enum InstMode extends StableEnum derives CanEqual, ReadWriter:
14671486
case Normal, Def, Simulation
1468-
case BlackBox(verilogSrc: Source, vhdlSrc: Source)
1487+
case BlackBox(source: Source)
14691488
object InstMode:
14701489
object BlackBox:
14711490
enum Source extends StableEnum derives CanEqual, ReadWriter:
14721491
case NA
1473-
case File(path: String)
1492+
case Files(path: List[String])
14741493
case Library(libName: String, nameSpace: String)
1494+
case Qsys(typeName: String)
14751495

14761496
extension (dsn: DFDesignBlock)
14771497
def isDuplicate: Boolean = dsn.hasTagOf[DuplicateTag]
14781498
def isBlackBox: Boolean = dsn.instMode.isInstanceOf[InstMode.BlackBox]
1499+
def isQsysIPBlackbox: Boolean = dsn.instMode match
1500+
case InstMode.BlackBox(_: InstMode.BlackBox.Source.Qsys) => true
1501+
case _ => false
14791502
def inSimulation: Boolean = dsn.instMode == InstMode.Simulation
14801503
def getCommonDesignWith(dsn2: DFDesignBlock)(using MemberGetSet): DFDesignBlock =
14811504
def getOwnerDesignChain(dsn: DFDesignBlock): List[DFDesignBlock] =

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ object DFType:
6969
dt.cellType.decompose(pf)
7070
case _ => Nil
7171
ListSet.from(deps.collect(pf) ++ List(dfType).collect(pf))
72-
72+
def isUnbounded: Boolean = dfType match
73+
case _: DFUnbounded => true
74+
case _ => false
75+
end extension
7376
end DFType
7477

7578
sealed trait ComposedDFType extends DFType
@@ -527,7 +530,7 @@ case object DFDouble extends DFType.Companion[DFDouble, Option[Double]] with DFD
527530
/////////////////////////////////////////////////////////////////////////////
528531

529532
sealed trait DFUnbounded extends DFType:
530-
def noTypeErr = throw new IllegalArgumentException(
533+
def noTypeErr = throw new Exception(
531534
s"Unexpected access to $this data type"
532535
)
533536
def width(using MemberGetSet): Int = noTypeErr

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ object Data:
2424
case Some(stringValue: String) => writeJs(("string", stringValue))
2525
case time: TimeNumber => writeJs(("time", (time.value, time.unit)))
2626
case freq: FreqNumber => writeJs(("freq", (freq.value, freq.unit)))
27+
case number: LiteralNumber => writeJs(("number", number.value))
2728
case vectorData: Vector[Data] =>
2829
given ReadWriter[Vector[Data]] = vectorDataWriter
2930
writeJs(("vector", vectorData))
@@ -50,6 +51,8 @@ object Data:
5051
case ujson.Arr(ArrayBuffer(ujson.Str("freq"), freqValue)) =>
5152
val (value, unit) = read[(BigDecimal, FreqNumber.Unit)](freqValue)
5253
FreqNumber(value, unit)
54+
case ujson.Arr(ArrayBuffer(ujson.Str("number"), numberValue)) =>
55+
LiteralNumber(read[BigDecimal](numberValue))
5356
case ujson.Arr(ArrayBuffer(ujson.Str("vector"), vectorData)) =>
5457
given ReadWriter[Vector[Data]] = vectorDataWriter
5558
read[Vector[Data]](vectorData)

0 commit comments

Comments
 (0)