Skip to content

Commit 8d09c3b

Browse files
authored
Merge pull request #330 from DFiantHDL/scala3p8
v0.17.0
2 parents 3883742 + 0eaa4a0 commit 8d09c3b

File tree

159 files changed

+2936
-1326
lines changed

Some content is hidden

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

159 files changed

+2936
-1326
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.10.1
1+
version = 3.10.5
22
runner.dialect = scala3
33

44
maxColumn = 100

build.sbt

Lines changed: 21 additions & 7 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.4"
8+
val compilerVersion = "3.8.1"
99

1010
inThisBuild(
1111
List(
@@ -33,6 +33,7 @@ name := projectName
3333
ThisBuild / organization := "io.github.dfianthdl"
3434
ThisBuild / scalaVersion := compilerVersion
3535
ThisBuild / versionScheme := Some("semver-spec")
36+
ThisBuild / resolvers += Resolver.scalaNightlyRepository
3637
//ThisBuild / version := "0.3.0-SNAPSHOT"
3738

3839
// PROJECTS
@@ -55,6 +56,7 @@ lazy val internals = project
5556
.settings(
5657
name := s"$projectName-internals",
5758
settings,
59+
implicitConversionSettings,
5860
libraryDependencies ++= commonDependencies
5961
)
6062

@@ -71,13 +73,15 @@ lazy val compiler_ir = (project in file("compiler/ir"))
7173
.settings(
7274
name := s"$projectName-compiler-ir",
7375
settings,
76+
implicitConversionSettings,
7477
libraryDependencies += dependencies.upickle
7578
).dependsOn(internals)
7679

7780
lazy val core = project
7881
.settings(
7982
name := s"$projectName-core",
8083
settings,
84+
implicitConversionSettings,
8185
pluginTestUseSettings,
8286
libraryDependencies ++= commonDependencies,
8387
Compile / resourceGenerators += Def.task {
@@ -123,6 +127,10 @@ lazy val platforms = project
123127
.settings(
124128
name := s"$projectName-platforms",
125129
settings,
130+
// Override global license: platforms module is published under Apache 2.0
131+
licenses := List(
132+
"Apache-2.0" -> url("https://www.apache.org/licenses/LICENSE-2.0.txt")
133+
),
126134
pluginUseSettings,
127135
libraryDependencies ++= commonDependencies
128136
)
@@ -136,11 +144,11 @@ lazy val platforms = project
136144
lazy val dependencies =
137145
new {
138146
private val scodecV = "1.2.4"
139-
private val munitV = "1.2.1"
140-
private val airframelogV = "2025.1.21"
141-
private val oslibV = "0.11.6"
142-
private val scallopV = "5.2.0"
143-
private val upickleV = "4.4.1"
147+
private val munitV = "1.2.2"
148+
private val airframelogV = "2025.1.27"
149+
private val oslibV = "0.11.7"
150+
private val scallopV = "5.3.0"
151+
private val upickleV = "4.4.2"
144152

145153
val scodec = "org.scodec" %% "scodec-bits" % scodecV
146154
val munit = "org.scalameta" %% "munit" % munitV % Test
@@ -177,8 +185,8 @@ def compilerOptionsVersionDependent(scalaVersion: String) = {
177185
lazy val compilerOptions = Seq(
178186
"-unchecked",
179187
"-feature",
188+
"-preview",
180189
"-language:strictEquality",
181-
"-language:implicitConversions",
182190
"-deprecation",
183191
//TODO: remove when fixed scalac issues:
184192
//https://github.com/lampepfl/dotty/issues/19299
@@ -216,3 +224,9 @@ lazy val commonSettings = Seq(
216224
compilerOptions ++ compilerOptionsVersionDependent(scalaVersion.value)
217225
}
218226
)
227+
228+
lazy val implicitConversionSettings = Seq(
229+
Compile / scalacOptions ++= Seq(
230+
"-language:implicitConversions"
231+
)
232+
)

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package analysis
33
import dfhdl.internals.*
44
import ir.*
55
import scala.annotation.tailrec
6+
import scala.collection.mutable
67
extension (owner: DFOwner)
78
def members(memberView: MemberView)(using MemberGetSet): List[DFMember] =
89
getSet.designDB.getMembersOf(owner, memberView)
@@ -29,3 +30,29 @@ extension (domainOwner: DFDomainOwner)
2930
if (dependency == thatDomainOwner) true
3031
else dependency.isDependentOn(thatDomainOwner)
3132
case None => false
33+
34+
extension (design: DFDesignBlock)
35+
// collect all local parameters that are used in IOs
36+
def getIOLocalParams(using getSet: MemberGetSet): List[DFVal.CanBeExpr] =
37+
val ioLocalParams = mutable.LinkedHashSet.empty[DFVal.CanBeExpr]
38+
def collectIOLocalParams(ref: DFRefAny): Unit = ref.get match
39+
// skip existing design parameters
40+
case _: DFVal.DesignParam => // do nothing
41+
// skip global parameters
42+
case gp: DFVal.CanBeGlobal if gp.isGlobal => // do nothing
43+
// check this value and its dependencies
44+
case dfVal: DFVal.CanBeExpr =>
45+
// already collected
46+
if (!ioLocalParams.contains(dfVal))
47+
// collect dependencies
48+
dfVal.getRefs.foreach(collectIOLocalParams)
49+
// if the value is named collect this value too
50+
if (!dfVal.isAnonymous)
51+
ioLocalParams.add(dfVal)
52+
case _ => // do nothing
53+
design.members(MemberView.Folded).foreach {
54+
case port @ DclPort() => port.getRefs.foreach(collectIOLocalParams)
55+
case _ => // do nothing
56+
}
57+
ioLocalParams.toList
58+
end extension

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,13 @@ extension (dfVal: DFVal)
281281
val maxValue = relVal.dfType match
282282
case vector: DFVector => vector.length - 1
283283
case bits: DFBits => bits.width - 1
284+
case xInt: DFDecimal => xInt.width - 1
284285
case _ => ???
285286
s"_${i.toPaddedString(maxValue)}"
286287
case _ => "_sel"
287288
case applyRange: DFVal.Alias.ApplyRange =>
288-
(applyRange.dfType: @unchecked) match
289-
case DFBits(_) =>
289+
applyRange.dfType.runtimeChecked match
290+
case DFBits(_) | DFUInt(_) | DFSInt(_) =>
290291
val idxHigh = applyRange.idxHighRef.getInt.toPaddedString(applyRange.width - 1)
291292
val idxLow = applyRange.idxLowRef.getInt.toPaddedString(applyRange.width - 1)
292293
s"_${idxHigh}_${idxLow}"

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package dfhdl.compiler.ir
22
import upickle.default.*
3-
opaque type ConfigN[T] = T | None.type
3+
into opaque type ConfigN[T] = T | None.type
44
object ConfigN:
55
given [T]: Conversion[None.type, ConfigN[T]] with
66
def apply(x: None.type): ConfigN[T] = x
77
given [T]: Conversion[T, ConfigN[T]] with
88
def apply(x: T): ConfigN[T] = x
9+
given [F, T](using conv: Conversion[F, T]): Conversion[F, ConfigN[T]] with
10+
def apply(x: F): ConfigN[T] = conv(x)
911
given [T1, T2](using CanEqual[T1, T2]): CanEqual[ConfigN[T1], ConfigN[T2]] = CanEqual.derived
1012
given [T]: CanEqual[ConfigN[T], None.type] = CanEqual.derived
1113
given [T]: CanEqual[None.type, ConfigN[T]] = CanEqual.derived
@@ -14,9 +16,9 @@ object ConfigN:
1416
given [L, R]: CanEqual[ConfigN[L], ConfigN[R]] = CanEqual.derived
1517
given [T](using ReadWriter[T]): ReadWriter[ConfigN[T]] = readwriter[ujson.Value].bimap(
1618
value =>
17-
(value: @unchecked) match
18-
case None => ujson.Null
19-
case value: T => writeJs(value)
19+
value.runtimeChecked match
20+
case None => ujson.Null
21+
case value: T @unchecked => writeJs(value)
2022
,
2123
json =>
2224
json match

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,17 +203,17 @@ final case class DB(
203203
case MemberView.Folded =>
204204
ownerMemberTable(owner)
205205
case MemberView.Flattened =>
206-
def recur(owner: DFOwner, includeOwner: Boolean = true): List[DFMember] =
206+
def recur(owner: DFOwner): List[DFMember] =
207207
val members = ownerMemberTable(owner)
208208
members.flatMap {
209209
case d: DFDesignBlock => Some(d)
210-
case o: DFOwner => if (includeOwner) o :: recur(o) else recur(o)
210+
case o: DFOwner => o :: recur(o)
211211
case m => Some(m)
212212
}
213213
end recur
214214
owner match
215215
case d: DFDesignBlock => designMemberTable(d)
216-
case _ => recur(owner, includeOwner = false)
216+
case _ => recur(owner)
217217

218218
// holds a hash table that lists members of each owner. The member list order is maintained.
219219
lazy val ownerMemberTable: Map[DFOwner, List[DFMember]] =
@@ -652,7 +652,7 @@ final case class DB(
652652
!magnetConnectionTable.contains(p) && !p.hasNonBubbleInit =>
653653
val ownerDesign = p.getOwnerDesign
654654
s"""|DFiant HDL connectivity error!
655-
|Position: ${ownerDesign.meta.position}
655+
|Position: ${p.meta.position}
656656
|Hierarchy: ${ownerDesign.getFullName}
657657
|Message: Found a dangling (unconnected/unassigned and uninitialized) output port `${p.getName}`.""".stripMargin
658658
}

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

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,26 @@ sealed trait DFVal extends DFMember.Named:
217217
case DFVal.DesignParam(dfValRef = DFRef(dfVal)) =>
218218
stripAsIsAndDesignParam(dfVal)
219219
case _ => dfVal
220+
// TODO: maybe we need a better way to check equivalent expressions, with symbolic algebra comparison?
221+
// with such comparison, it is possible to simplify expressions at least in the common cases.
220222
(stripAsIsAndDesignParam(this), stripAsIsAndDesignParam(that)) match
221-
case (lhs: DFVal.CanBeExpr, rhs: DFVal.CanBeExpr) => lhs.protIsSimilarTo(rhs)
222-
case (lhs, rhs) => lhs == rhs
223+
// literal constants are considered to be similar to expressions if they are
224+
// at a higher level of hierarchy than the expression
225+
case (lhs: DFVal.Const, rhs: DFVal.CanBeExpr)
226+
if !lhs.isGlobal && !rhs.isGlobal &&
227+
lhs.getOwnerDesign.isOutsideOwner(rhs.getOwnerDesign) ||
228+
lhs.isGlobal && lhs.isAnonymous =>
229+
lhs.dfType.isSimilarTo(rhs.dfType) && lhs.getConstData.equals(rhs.getConstData)
230+
case (lhs: DFVal.CanBeExpr, rhs: DFVal.Const)
231+
if !lhs.isGlobal && !rhs.isGlobal &&
232+
rhs.getOwnerDesign.isOutsideOwner(lhs.getOwnerDesign) ||
233+
rhs.isGlobal && rhs.isAnonymous =>
234+
rhs.dfType.isSimilarTo(lhs.dfType) && rhs.getConstData.equals(lhs.getConstData)
235+
case (lhs: DFVal.CanBeExpr, rhs: DFVal.CanBeExpr) =>
236+
lhs.protIsSimilarTo(rhs)
237+
case (lhs, rhs) => lhs == rhs
238+
end match
239+
end isSimilarTo
223240
protected def protGetConstData(using MemberGetSet): Option[Any]
224241
private var cachedConstDataReady: Boolean = false
225242
private var cachedConstData: Option[Any] = None
@@ -599,7 +616,7 @@ object DFVal:
599616
case >>, <<, **, ror, rol, reverse, repeat
600617
case unary_-, unary_~, unary_!
601618
case rising, falling
602-
case clog2, max, min, sel
619+
case clog2, max, min, abs, sel
603620
// special-case of initFile construct for vectors of bits
604621
case InitFile(format: InitFileFormat, path: String)
605622
object Op:
@@ -763,9 +780,9 @@ object DFVal:
763780
meta: Meta,
764781
tags: DFTags
765782
) extends Partial derives ReadWriter:
766-
def elementWidth(using MemberGetSet): Int = (dfType: @unchecked) match
767-
case DFBits(_) => 1
768-
case DFVector(cellType = cellType) => cellType.width
783+
def elementWidth(using MemberGetSet): Int = dfType.runtimeChecked match
784+
case DFBits(_) | DFUInt(_) | DFSInt(_) => 1
785+
case DFVector(cellType = cellType) => cellType.width
769786
protected def protIsFullyAnonymous(using MemberGetSet): Boolean =
770787
relValRef.get.isFullyAnonymous
771788
protected def protGetConstData(using MemberGetSet): Option[Any] =
@@ -789,9 +806,8 @@ object DFVal:
789806
case that: ApplyRange =>
790807
this.dfType.isSimilarTo(that.dfType) &&
791808
this.relValRef.get.isSimilarTo(that.relValRef.get) &&
792-
this.idxHighRef.isSimilarTo(that.idxHighRef) && this.idxLowRef.isSimilarTo(
793-
that.idxLowRef
794-
)
809+
this.idxHighRef.isSimilarTo(that.idxHighRef) &&
810+
this.idxLowRef.isSimilarTo(that.idxLowRef)
795811
case _ => false
796812
protected def setMeta(meta: Meta): this.type = copy(meta = meta).asInstanceOf[this.type]
797813
protected def setTags(tags: DFTags): this.type = copy(tags = tags).asInstanceOf[this.type]
@@ -834,12 +850,15 @@ object DFVal:
834850
val data = relValData.asInstanceOf[(BitVector, BitVector)]
835851
if (data._2.bit(idxInt)) None
836852
else Some(data._1.bit(idxInt))
853+
case DFUInt(_) | DFSInt(_) =>
854+
relValData.asInstanceOf[Option[BigInt]].map(_.testBit(idxInt))
837855
case DFVector(_, _) =>
838856
relValData.asInstanceOf[Vector[?]](idxInt)
839857
case _ => ???
840858
Some(outData)
841859
case Some(_: None.type) => Some(None)
842860
case _ => None
861+
end match
843862
)
844863
end protGetConstData
845864
protected def `prot_=~`(that: DFMember)(using MemberGetSet): Boolean = that match
@@ -1486,19 +1505,20 @@ object DFDesignBlock:
14861505
case Normal, Def, Simulation
14871506
case BlackBox(source: Source)
14881507
object InstMode:
1508+
import constraints.DeviceID.Vendor
14891509
object BlackBox:
14901510
enum Source derives CanEqual, ReadWriter:
14911511
case NA
14921512
case Files(path: List[String])
14931513
case Library(libName: String, nameSpace: String)
1494-
case Qsys(typeName: String)
1514+
case VendorIP(vendor: Vendor, typeName: String)
14951515

14961516
extension (dsn: DFDesignBlock)
14971517
def isDuplicate: Boolean = dsn.hasTagOf[DuplicateTag]
14981518
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
1519+
def isVendorIPBlackbox: Boolean = dsn.instMode match
1520+
case InstMode.BlackBox(_: InstMode.BlackBox.Source.VendorIP) => true
1521+
case _ => false
15021522
def inSimulation: Boolean = dsn.instMode == InstMode.Simulation
15031523
def getCommonDesignWith(dsn2: DFDesignBlock)(using MemberGetSet): DFDesignBlock =
15041524
def getOwnerDesignChain(dsn: DFDesignBlock): List[DFDesignBlock] =

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ object IntParamRef:
9090
def isInt: Boolean = intParamRef match
9191
case int: Int => true
9292
case _ => false
93-
def getInt(using MemberGetSet): Int = (intParamRef: @unchecked) match
93+
def getInt(using MemberGetSet): Int = intParamRef.runtimeChecked match
9494
case Int(int) => int
9595
def isRef: Boolean = intParamRef match
9696
case ref: DFRef.TypeRef => true
@@ -135,7 +135,7 @@ end IntParamRef
135135

136136
extension (intCompanion: Int.type)
137137
def unapply(intParamRef: IntParamRef)(using MemberGetSet): Option[Int] =
138-
(intParamRef: @unchecked) match
138+
intParamRef.runtimeChecked match
139139
case int: Int => Some(int)
140140
case DFRef(dfVal: DFVal) =>
141141
dfVal.getConstData.asInstanceOf[Option[Option[BigInt]]].flatten.map(_.toInt)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dfhdl.compiler.ir
22
import dfhdl.internals.BitVector
33
import upickle.default.*
44
import scala.collection.mutable.ArrayBuffer
5-
opaque type Data = Any
5+
into opaque type Data = Any
66
object Data:
77
given Conversion[Any, Data] = identity
88
given ReadWriter[BitVector] = readwriter[String].bimap(

0 commit comments

Comments
 (0)