" else m.getOwnerNamed.getFullName
println(
- s"The member ${m.hashString}:\n$m\nIn hierarchy:\n${m.getOwnerNamed.getFullName}\nHas reference $r pointing to a later member ${rm.hashString}:\n${rm}"
+ s"The member ${m.hashString}:\n$m\nIn hierarchy:\n$hierarchy\nHas reference $r pointing to a later member ${rm.hashString}:\n${rm}"
)
hasViolations = true
require(!hasViolations, "Failed member order check!")
@@ -234,7 +266,7 @@ case class SanityCheck(skipAnonRefCheck: Boolean) extends Stage:
end orderCheck
def transform(designDB: DB)(using MemberGetSet, CompilerOptions): DB =
- // refCheck()
+ refCheck()
memberExistenceCheck()
ownershipCheck(designDB.top, designDB.membersNoGlobals.drop(1))
orderCheck()
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/SimplifyRTOps.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/SimplifyRTOps.scala
index 9ed680225..67b9ebdff 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/SimplifyRTOps.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/SimplifyRTOps.scala
@@ -8,19 +8,103 @@ import dfhdl.internals.*
import DFVal.Func.Op as FuncOp
import scala.collection.mutable
//format: off
-/** This stage transforms:
- * - wait statements into while loops with a cycle wait. For example:
- * waitWhile(cond) -> while(cond) 1.cy.wait
- * - rising/falling edge operations into reg alias detection operations. For example:
- * i.rising -> !i.reg(1, init = 1) && i
- * i.falling -> i.reg(1, init = 0) && !i
- * - non-zero/one cycle wait statements to while loops with a counter. For example (under 50Mhz clock):
- * 50000000.cy.wait -> while(waitCnt != 50000000) 1.cy.wait
+/** This stage simplifies RT-domain operations into lower-level constructs that downstream stages
+ * can process. It handles four kinds of transformations: rising/falling edge predicates, boolean
+ * wait statements, cycle-count wait statements, and for loops.
+ *
+ * ==Rule 1: Rising/falling edge simplification==
+ *
+ * `rising` and `falling` predicates on a `Bit` signal are replaced with register-based edge
+ * detection expressions:
+ * {{{
+ * // Before
+ * i.rising
+ * i.falling
+ *
+ * // After
+ * (!i.reg(1, init = 1)) && i
+ * i.reg(1, init = 0) && (!i)
+ * }}}
+ *
+ * ==Rule 2: Boolean wait → while loop==
+ *
+ * `waitWhile(cond)` / `waitUntil(cond)` statements (including those with rising/falling edge
+ * triggers) are replaced with `while` loops. If the wait has a name, the generated while loop
+ * takes that name:
+ * {{{
+ * // Before
+ * waitWhile(i)
+ * val MyWait = waitUntil(i)
+ * waitUntil(i.falling)
+ *
+ * // After
+ * while (i)
+ * end while
+ * val MyWait = while (!i)
+ * end MyWait
+ * while ((!i.reg(1, init = 0)) || i)
+ * end while
+ * }}}
+ *
+ * ==Rule 3: Cycle-count wait → while loop with counter==
+ *
+ * A wait with a cycle count (`N.cy.wait`) is replaced by a `VAR.REG` counter assigned to zero
+ * before the loop and a `while` loop that counts up to `N-1`. A single-cycle wait (`1.cy.wait`)
+ * is left unchanged (no loop needed). If the wait has a name (`val N = X.cy.wait`), the counter
+ * register is prefixed with `N_`:
+ * {{{
+ * // Before
+ * x.din := 1
+ * 50000000.cy.wait
+ * val MyWait = waitParam.cy.wait
+ *
+ * // After
+ * x.din := 1
+ * val waitCnt = UInt(26) <> VAR.REG
+ * waitCnt.din := d"26'0"
+ * while (waitCnt != d"26'49999999")
+ * waitCnt.din := waitCnt + d"26'1"
+ * end while
+ * val MyWait_waitCnt = UInt(26) <> VAR.REG
+ * MyWait_waitCnt.din := d"26'0"
+ * val MyWait = while (MyWait_waitCnt != (waitParam - d"26'1"))
+ * MyWait_waitCnt.din := MyWait_waitCnt + d"26'1"
+ * end MyWait
+ * }}}
+ *
+ * ==Rule 4: For loop → while loop with iterator==
+ *
+ * `for` loops that are inside an RT process are replaced by a `Int <> VAR.REG` iterator assigned
+ * to the range start before the loop, and a `while` loop whose body ends with the iterator
+ * increment. The comparison operator is `<` for `until` (exclusive) and `<=` for `to` (inclusive);
+ * for negative steps the operators are `>` and `>=` respectively. For loops tagged as `COMB_LOOP`,
+ * outside the RT domain, or outside a process block are left unchanged.
+ *
+ * Iterator naming:
+ * - anonymous `for (i <- ...)`: iterator register keeps the original name (`i`)
+ * - named `val Name = for (i <- ...)`: iterator register is named `Name_i`
+ * {{{
+ * // Before
+ * x.din := 1
+ * for (i <- 0 until 4)
+ * x.din := 0
+ * x.din := 1
+ *
+ * // After
+ * x.din := 1
+ * val i = Int <> VAR.REG
+ * i.din := 0
+ * while (i < 4)
+ * x.din := 0
+ * i.din := i + 1
+ * end while
+ * x.din := 1
+ * }}}
*/
//format: on
case object SimplifyRTOps extends Stage:
- def dependencies: List[Stage] = List(DropTimedRTWaits, DFHDLUniqueNames)
- def nullifies: Set[Stage] = Set(DropUnreferencedAnons)
+ def dependencies: List[Stage] = List(DropTimedRTWaits)
+ def nullifies: Set[Stage] = Set(DropUnreferencedAnons, DFHDLUniqueNames, DropLocalDcls)
def transform(designDB: DB)(using MemberGetSet, CompilerOptions): DB =
given RefGen = RefGen.fromGetSet
@@ -29,7 +113,7 @@ case object SimplifyRTOps extends Stage:
case _: Wait => true
case _ => false
}
- val patchList = designDB.members.view.collect {
+ val patchList = designDB.members.view.flatMap {
case trigger @ DFVal.Func(
_,
op @ (FuncOp.rising | FuncOp.falling),
@@ -94,8 +178,11 @@ case object SimplifyRTOps extends Stage:
// the bug originates from a conversion from UInt[1] to the iterType. It could be that the
// methods under core.DFVal.Alias are not working as intended because of meta-programming.
val initZero = dfhdl.core.DFVal.Const(iterType, Some(BigInt(0)))
- val waitCnt =
- iterType.<>(VAR.REG).initForced(List(initZero))(using dfc.setName("waitCnt"))
+ val waitCntName = waitMember.meta.nameOpt match
+ case Some(waitName) => s"${waitName}_waitCnt"
+ case None => "waitCnt"
+ val waitCnt = iterType.<>(VAR.REG)(using dfc.setName(waitCntName))
+ waitCnt.din := initZero
// the upper bound for the while loop count
val upperBound = cyclesVal match
// the upper bound is reduced to a simpler form when the number of cycles is a constant anonymous value
@@ -112,7 +199,65 @@ case object SimplifyRTOps extends Stage:
Some(dsn.patch)
else None
end if
- }.flatten.toList
+
+ // replace RT for loops with while loops + iterator VAR.REG + increment at end of body
+ case forBlock: DFLoop.DFForBlock
+ if forBlock.isInRTDomain && !forBlock.isCombinational && forBlock.isInProcess =>
+ val iteratorDcl = forBlock.iteratorRef.get
+ val range = forBlock.rangeRef.get
+ val startBigInt: BigInt = range.startRef.get match
+ case DFVal.Const(data = Some(v: BigInt)) => v
+ case _ => BigInt(0)
+ val stepBigInt: BigInt = range.stepRef.get match
+ case DFVal.Const(data = Some(v: BigInt)) => v
+ case _ => BigInt(1)
+ val endValIR = range.endRef.get
+ val rangeOp = range.op
+ val iterName = forBlock.meta.nameOpt match
+ case None => iteratorDcl.getName
+ case Some(name) => s"${name}_${iteratorDcl.getName}"
+ val forBodyMembers = forBlock.members(MemberView.Folded)
+ // M1: create iterator VAR.REG + guard + whileBlock, replacing forBlock.
+ // ReplaceWithLast(ChangeRefAndRemove) makes whileBlock (last M1 member) replace forBlock,
+ // redirecting ALL refs to forBlock (including body members' ownerRefs) to whileBlock.
+ val m1 = new MetaDesign(
+ forBlock,
+ Patch.Add.Config.ReplaceWithLast(Patch.Replace.Config.ChangeRefAndRemove),
+ dfhdl.core.DomainType.RT(dfhdl.core.RTDomainCfg.Derived)
+ ):
+ val startConst = dfhdl.core.DFVal.Const(dfhdl.core.DFInt32, Some(startBigInt))
+ val newIterDcl = dfhdl.core.DFInt32.<>(VAR.REG)(using dfc.setName(iterName))
+ newIterDcl.din := startConst
+ val endVal = endValIR.asValOf[dfhdl.core.DFInt32]
+ val guard = (rangeOp, stepBigInt.signum) match
+ case (DFRange.Op.Until, s) if s >= 0 => newIterDcl < endVal
+ case (DFRange.Op.To, s) if s >= 0 => newIterDcl <= endVal
+ case (DFRange.Op.Until, _) => newIterDcl > endVal
+ case (DFRange.Op.To, _) => newIterDcl >= endVal
+ val whileBlock = dfhdl.core.DFWhile.Block(guard)(using dfc.setMeta(forBlock.meta))
+ dfc.enterOwner(whileBlock)
+ dfc.exitOwner()
+ val newIterDclIR = m1.newIterDcl.asIR
+ val iterDclPatch =
+ iteratorDcl -> Patch.Replace(newIterDclIR, Patch.Replace.Config.ChangeRefAndRemove)
+ if forBodyMembers.nonEmpty then
+ // M2: create the increment (newIterDcl.din := newIterDcl + step) after the last body member.
+ // M2's injectedOwner = forBodyMembers.last.getOwner = forBlock (in original DB).
+ // After M1's ref redirect (forBlock → whileBlock), M2's members' ownerRefs are also
+ // redirected to whileBlock, placing the increment correctly as the last while-body statement.
+ val m2 = new MetaDesign(
+ forBodyMembers.last,
+ Patch.Add.Config.After,
+ dfhdl.core.DomainType.RT(dfhdl.core.RTDomainCfg.Derived)
+ ):
+ val stepConst = dfhdl.core.DFVal.Const(dfhdl.core.DFInt32, Some(stepBigInt))
+ m1.newIterDcl.din := m1.newIterDcl + stepConst
+ List(m1.patch, iterDclPatch, m2.patch)
+ else List(m1.patch, iterDclPatch)
+ end if
+
+ case _ => None
+ }.toList
designDB.patch(patchList)
end transform
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/ToED.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/ToED.scala
index 530bb9664..e18df5e26 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/ToED.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/ToED.scala
@@ -11,7 +11,7 @@ import scala.annotation.tailrec
import scala.collection.mutable
case object ToED extends Stage:
def dependencies: List[Stage] =
- List(DropUnreferencedAnons, ToRT, NameRegAliases, ExplicitNamedVars, AddClkRst,
+ List(DropUnreferencedAnons, ToRT, DropRTProcess, NameRegAliases, ExplicitNamedVars, AddClkRst,
SimpleOrderMembers)
def nullifies: Set[Stage] = Set(DropUnreferencedAnons)
def transform(designDB: DB)(using getSet: MemberGetSet, co: CompilerOptions): DB =
@@ -54,12 +54,12 @@ case object ToED extends Stage:
case _ =>
}
def collectFilter(member: DFMember): Boolean = member match
- case IteratorDcl() => true
- case _: DFVal.Dcl => false
- case _: DFVal.DesignParam => false
- case _: DFOwnerNamed => false
- case dfVal: DFVal if dfVal.isReferencedByAnyDcl => false
- case _ => true
+ case IteratorDcl() => true
+ case _: DFVal.Dcl => false
+ case _: DFVal.DesignParam => false
+ case _: DFOwnerNamed => false
+ case dfVal: DFVal if dfVal.isReferencedByAnyDclOrDesign => false
+ case _ => true
def getProcessAllMembers(list: List[DFMember]): List[DFMember] =
val processBlockAllMembersSet: Set[DFMember] = list.view.flatMap {
@@ -160,11 +160,12 @@ case object ToED extends Stage:
}.toList
// create a combinational process if needed
val hasProcessAll =
- !domainIsPureSequential && (dclChangeList.nonEmpty || processBlockAllMembers.exists {
- case net: DFNet => true
- case ch: DFConditional.Header => true
- case _ => false
- })
+ !domainIsPureSequential &&
+ (dclChangeList.nonEmpty || processBlockAllMembers.exists {
+ case net: DFNet => true
+ case ch: DFConditional.Header => true
+ case _ => false
+ })
if (hasProcessAll)
process(all) {
val inVHDL = co.backend.isVHDL
@@ -256,7 +257,9 @@ case object ToED extends Stage:
block
)
val hasSeqProcess =
- clkCfg != None && (dclREGList.nonEmpty || processBlockAllMembers.nonEmpty && domainIsPureSequential)
+ clkCfg != None &&
+ (dclREGList.nonEmpty ||
+ processBlockAllMembers.nonEmpty && domainIsPureSequential)
if (hasSeqProcess)
if (rstCfg != None)
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/ViaConnection.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/ViaConnection.scala
index a2bc18ad0..78f24cc94 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/ViaConnection.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/ViaConnection.scala
@@ -15,7 +15,8 @@ case object ViaConnection extends Stage:
case (ib, members) if !ib.isTop =>
// getting only ports that are not already connected to variables
val (ports, nets): (List[DFVal.Dcl], List[DFNet]) =
- members.foldRight((List.empty[DFVal.Dcl], List.empty[DFNet])) {
+ val ports = designDB.dupPortsByName(ib).values
+ ports.foldRight((List.empty[DFVal.Dcl], List.empty[DFNet])) {
case (p @ DclOut(), (ports, nets)) =>
val conns = p.getConnectionsFrom
conns.headOption match
@@ -43,6 +44,7 @@ case object ViaConnection extends Stage:
case _ => (p :: ports, nets)
case (_, x) => x
}
+ end val
extension (port: DFVal.Dcl)
// set reachable type parameters for the selected ports by setting the MetaDesign context's
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogDataPrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogDataPrinter.scala
index 6f4b5b875..2e27a6ed0 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogDataPrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogDataPrinter.scala
@@ -42,9 +42,11 @@ protected trait VerilogDataPrinter extends AbstractDataPrinter:
def csDFSIntFormatBig(value: BigInt, width: IntParamRef): String =
val csWidth = width.refCodeString.applyBrackets()
if (width.isRef)
- if (value.isValidInt && allowWidthCastSyntax) s"""${csWidth}'($value)"""
+ val actualWidth = value.bitsWidth(true)
+ if (value.isValidInt && allowWidthCastSyntax)
+ if (value >= 0) s"""${csWidth}'($actualWidth'sd$value)"""
+ else s"${csWidth}'(-$actualWidth'sd${-value})"
else
- val actualWidth = value.bitsWidth(true)
if (allowWidthCastSyntax && printer.allowSignedKeywordAndOps)
if (value >= 0) s"""${csWidth}'($actualWidth'sd$value)"""
else s"""${csWidth}'(-$actualWidth'sd${-value})"""
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogOwnerPrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogOwnerPrinter.scala
index 31824d82a..f4bf32d42 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogOwnerPrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogOwnerPrinter.scala
@@ -13,7 +13,12 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
type TPrinter <: VerilogPrinter
val useStdSimLibrary: Boolean = true
def fileSuffix = "v"
- def defsName: String = s"${getSet.topName}_defs"
+ def defsName: String =
+ val name = printerOptions.globalDefsFileName
+ if (name.nonEmpty)
+ val dotIdx = name.lastIndexOf('.')
+ if (dotIdx > 0) name.substring(0, dotIdx) else name
+ else s"${getSet.topName}_defs"
def csLibrary(inSimulation: Boolean, minTimeUnitOpt: Option[TimeNumber.Unit]): String =
val csTimeScale = minTimeUnitOpt.map { unit =>
def unitToStr(unit: TimeNumber.Unit): String =
@@ -24,9 +29,9 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
val precisionUnit = unitToStr(TimeNumber(1e-3, unit).normalize.unit)
s"`timescale 1${scaleUnit}/1${precisionUnit}"
}.getOrElse(s"`timescale 1ns/1ps")
- s"""`default_nettype none
- |$csTimeScale
- |`include "${printer.globalFileName}"""".stripMargin
+ sn"""|`default_nettype none
+ |$csTimeScale
+ |${if (printer.hasGlobalContent) s"""`include "${printer.globalFileName}"""" else ""}"""
def moduleName(design: DFDesignBlock): String = design.dclName
val parameterizedModuleSupport: Boolean =
printer.dialect match
@@ -105,9 +110,9 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
)
val designParamList = designMembers.collect { case param: DesignParam =>
val defaultValue =
- if (design.isTop) s" = ${param.dfValRef.refCodeString}"
+ if (design.isTop) s" = ${param.appliedOrDefaultValRef.refCodeString}"
else
- param.defaultRef.get match
+ param.defaultValRef.get match
case DFMember.Empty =>
// missing default values are supported
if (noDefaultParamSupport) ""
@@ -115,7 +120,7 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
// (different instances may have different constant data, but for default,
// a single module description can have any valid data, just to satisfy the standard)
else s" = ${printer.csConstData(param.dfType, param.getConstData.get)}"
- case _ => s" = ${param.defaultRef.refCodeString}"
+ case _ => s" = ${param.defaultValRef.refCodeString}"
val csType = printer.csDFType(param.dfType).emptyOr(_ + " ")
val csTypeNoLogic = if (printer.supportLogicType) csType else csType.replace("logic ", "")
s"parameter ${csTypeNoLogic}${param.getName}$defaultValue"
@@ -125,7 +130,8 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
else if (designParamList.length == 1) designParamList.mkString("#(", ", ", ")")
else "#(" + designParamList.mkString("\n", ",\n", "\n").hindent(2) + ")"
val includeModuleDefs =
- if (printer.allowTypeDef) "" else s"""`include "${printer.globalFileName}""""
+ if (printer.allowTypeDef || !printer.hasGlobalContent) ""
+ else s"""`include "${printer.globalFileName}""""
// include parameter definitions only when parameters are used in the design
val paramDefines =
if (printer.supportGlobalParameters) ""
@@ -162,9 +168,9 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
|""".stripMargin
def csDFDesignBlockInst(design: DFDesignBlock): String =
val body = csDFDesignLateBody(design)
- val designParamList = design.members(MemberView.Folded).collect { case param: DesignParam =>
- s".${param.getName} (${param.dfValRef.refCodeString})"
- }
+ val designParamList = design.paramMap.view.map { (name, ref) =>
+ s".${name} (${ref.refCodeString})"
+ }.toList
val designParamCS =
if (designParamList.isEmpty || design.isVendorIPBlackbox) ""
else " #(" + designParamList.mkString("\n", ",\n", "\n").hindent(1) + ")"
@@ -189,13 +195,18 @@ protected trait VerilogOwnerPrinter extends AbstractOwnerPrinter:
def csDFCaseKeyword: String = ""
def csDFCaseSeparator: String = ":"
def csDFCaseGuard(guardRef: DFConditional.Block.GuardRef): String = printer.unsupported
- def csDFMatchStatement(csSelector: String, wildcardSupport: Boolean): String =
+ def csDFMatchStatement(csSelector: String, wildcardSupport: Boolean, isUnique: Boolean): String =
val insideSupport = printer.dialect match
case VerilogDialect.v2001 | VerilogDialect.v95 => false
case _ => true
+ val uniqueSupport = printer.dialect match
+ case VerilogDialect.v2001 | VerilogDialect.v95 => false
+ case _ => true
+ val uniquePrefix =
+ if (isUnique && uniqueSupport) "unique " else ""
val keyWord = if (wildcardSupport && !insideSupport) "casez" else "case"
val insideStr = if (wildcardSupport && insideSupport) " inside" else ""
- s"$keyWord ($csSelector)$insideStr"
+ s"$uniquePrefix$keyWord ($csSelector)$insideStr"
def csDFMatchEnd: String = "endcase"
val sensitivityListSep =
printer.dialect match
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogPrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogPrinter.scala
index aa62a32bb..a9caa0a1f 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogPrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogPrinter.scala
@@ -171,32 +171,36 @@ class VerilogPrinter(val dialect: VerilogDialect)(using
case VerilogDialect.v2001 | VerilogDialect.v95 => "vh"
case _ => "svh"
def globalFileName: String =
- s"${printer.defsName}.$verilogFileHeaderSuffix"
+ val name = printerOptions.globalDefsFileName
+ if (name.nonEmpty && name.contains('.')) name
+ else s"${printer.defsName}.$verilogFileHeaderSuffix"
override def csGlobalFileContent: String =
- val defName = printer.defsName.toUpperCase
- // the module defs are alternating between outside of and inside of the module
- // because we will include the module defs twice, once in the top of the file
- // and second time inside the module.
- val globalParams =
- if (printer.supportGlobalParameters) super.csGlobalFileContent else ""
- val globalToLocalParams =
- if (printer.supportGlobalParameters) "" else super.csGlobalFileContent
- val moduleDefs =
- if (printer.allowTypeDef) ""
- else
- sn"""|`ifndef ${defName}_MODULE
- |`define ${defName}_MODULE
- |`else
- |$globalToLocalParams
- |${printer.csGlobalTypeFuncDcls}
- |`undef ${defName}_MODULE
- |`endif"""
- sn"""|`ifndef $defName
- |`define $defName
- |$globalParams
- |`endif
- |$moduleDefs
- |"""
+ if (hasGlobalContent)
+ val defName = printer.defsName.toUpperCase
+ // the module defs are alternating between outside of and inside of the module
+ // because we will include the module defs twice, once in the top of the file
+ // and second time inside the module.
+ val globalParams =
+ if (printer.supportGlobalParameters) super.csGlobalFileContent else ""
+ val globalToLocalParams =
+ if (printer.supportGlobalParameters) "" else super.csGlobalFileContent
+ val moduleDefs =
+ if (printer.allowTypeDef) ""
+ else
+ sn"""|`ifndef ${defName}_MODULE
+ |`define ${defName}_MODULE
+ |`else
+ |$globalToLocalParams
+ |${printer.csGlobalTypeFuncDcls}
+ |`undef ${defName}_MODULE
+ |`endif"""
+ sn"""|`ifndef $defName
+ |`define $defName
+ |$globalParams
+ |`endif
+ |$moduleDefs
+ |"""
+ else ""
end csGlobalFileContent
def dfhdlDefsFileName: String = s"dfhdl_defs.$verilogFileHeaderSuffix"
def dfhdlSourceContents: String =
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogTypePrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogTypePrinter.scala
index 345cc726b..d97221539 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogTypePrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogTypePrinter.scala
@@ -74,11 +74,8 @@ protected trait VerilogTypePrinter extends AbstractTypePrinter:
dfType.entries.view
.map((n, v) => s"${enumName}_$n = $v")
.mkString(",\n")
- // TODO: quartus seems to not accept an explicit size, so we drop it locally where it's not required.
- // Globally, size is required (at least for verilator linter), so we need to drop enumeration altogether
- // in such a case (change to a vector and list of constants) and then remove the special case handling
- // here.
- val explicitWidth = if (global) s" logic [${dfType.width - 1}:0]" else ""
+ // TODO: quartus seems to not accept an explicit size Globally
+ val explicitWidth = s" logic [${dfType.width - 1}:0]"
s"typedef enum$explicitWidth {\n${entries.hindent}\n} ${csDFEnumTypeName(dfType)};"
else
dfType.entries.view
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogValPrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogValPrinter.scala
index 4f0221fb9..ce5a9bc1e 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogValPrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/verilog/VerilogValPrinter.scala
@@ -34,7 +34,7 @@ protected trait VerilogValPrinter extends AbstractValPrinter:
// using the constant data only happens in verilog.v95, since parameters are declared in
// the body and must have defaults.
case param: DesignParam =>
- param.defaultRef.get match
+ param.defaultValRef.get match
case defaultVal: CanBeExpr if !param.getOwnerDesign.isTop => csDFValExpr(defaultVal)
case _ => printer.csConstData(param.dfType, param.getConstData.get)
case _ => csDFValExpr(dfVal)
@@ -85,7 +85,8 @@ protected trait VerilogValPrinter extends AbstractValPrinter:
val cellWidth = dfType.cellType.width
val length = dfType.cellDimParamRefs.head.getInt
val ret = for (i <- 0 until length)
- yield s"${dfVal.getName}[$i] = ${initVal.getName}[${(length - i) * cellWidth - 1}:${(length - i) * cellWidth - cellWidth}];"
+ yield s"${dfVal.getName}[$i] = ${initVal.getName}[${(length - i) * cellWidth -
+ 1}:${(length - i) * cellWidth - cellWidth}];"
ret.mkString("\n")
case Func(op = Func.Op.++, args = args) =>
args.view.zipWithIndex
@@ -148,7 +149,9 @@ protected trait VerilogValPrinter extends AbstractValPrinter:
argL.get.dfType match
case DFSInt(_) => ">>>"
case _ => ">>"
- case _ => commonOpStr
+ case Func.Op.| if argL.get.dfType == DFBool => "||"
+ case Func.Op.& if argL.get.dfType == DFBool => "&&"
+ case _ => commonOpStr
(argL.get.dfType, dfVal.op) match
case (
DFSInt(widthRef),
@@ -319,9 +322,14 @@ protected trait VerilogValPrinter extends AbstractValPrinter:
List.tabulate(vecLength)(i =>
s"$relValStr[${relHighIdx - i * cellWidth}:${relHighIdx - (i + 1) * cellWidth + 1}]"
).csList(literalGroupOpen, ",", "}")
+ case _: DFBoolOrBit =>
+ List.tabulate(vecLength)(i =>
+ s"$relValStr[${relHighIdx - i}]"
+ ).csList(literalGroupOpen, ",", "}")
case x =>
println(x)
printer.unsupported
+ end match
end to_vector_conv
to_vector_conv(toVector, toVector.width - 1)
case (DFBits(Int(tWidth)), fromVector: DFVector) =>
@@ -332,7 +340,8 @@ protected trait VerilogValPrinter extends AbstractValPrinter:
List.tabulate(vecLength)(i => from_vector_conv(cellType, s"[$i]"))
.csList("{", ",", "}")
case cellType: DFBits =>
- val cellWidth = cellType.width
+ List.tabulate(vecLength)(i => s"$relValStr$prevSelect[$i]").csList("{", ",", "}")
+ case _: DFBoolOrBit =>
List.tabulate(vecLength)(i => s"$relValStr$prevSelect[$i]").csList("{", ",", "}")
case x =>
println(x)
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLOwnerPrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLOwnerPrinter.scala
index 0440284c0..18babf197 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLOwnerPrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLOwnerPrinter.scala
@@ -12,14 +12,20 @@ protected trait VHDLOwnerPrinter extends AbstractOwnerPrinter:
type TPrinter <: VHDLPrinter
val useStdSimLibrary: Boolean = true
def fileSuffix = "vhdl"
- def packageName: String = s"${getSet.topName}_pkg"
+ def packageName: String =
+ val name = printerOptions.globalDefsFileName
+ if (name.nonEmpty)
+ val dotIdx = name.lastIndexOf('.')
+ if (dotIdx > 0) name.substring(0, dotIdx) else name
+ else s"${getSet.topName}_pkg"
def csLibrary(inSimulation: Boolean, usesMathReal: Boolean): String =
val default =
- s"""library ieee;
- |use ieee.std_logic_1164.all;
- |use ieee.numeric_std.all;${if (usesMathReal) "\nuse ieee.math_real.all;" else ""}
- |use work.dfhdl_pkg.all;
- |use work.$packageName.all;""".stripMargin
+ sn"""|library ieee;
+ |use ieee.std_logic_1164.all;
+ |use ieee.numeric_std.all;
+ |${if (usesMathReal) "use ieee.math_real.all;" else ""}
+ |use work.dfhdl_pkg.all;
+ |${if (printer.hasGlobalContent) s"use work.$packageName.all;" else ""}"""
if (useStdSimLibrary && inSimulation)
s"""$default
|
@@ -36,11 +42,11 @@ protected trait VHDLOwnerPrinter extends AbstractOwnerPrinter:
.mkString(";\n")
val designParamList = designMembers.collect { case param: DesignParam =>
val defaultValue =
- if (design.isTop) s" := ${param.dfValRef.refCodeString}"
+ if (design.isTop) s" := ${param.appliedOrDefaultValRef.refCodeString}"
else
- param.defaultRef.get match
+ param.defaultValRef.get match
case DFMember.Empty => ""
- case _ => s" := ${param.defaultRef.refCodeString}"
+ case _ => s" := ${param.defaultValRef.refCodeString}"
s"${param.getName} : ${printer.csDFType(param.dfType)}$defaultValue"
}
val genericBlock =
@@ -177,9 +183,9 @@ protected trait VHDLOwnerPrinter extends AbstractOwnerPrinter:
end csDFDesignBlockDcl
def csDFDesignBlockInst(design: DFDesignBlock): String =
val body = csDFDesignLateBody(design)
- val designParamList = design.members(MemberView.Folded).collect { case param: DesignParam =>
- s"${param.getName} => ${param.dfValRef.refCodeString}"
- }
+ val designParamList = design.paramMap.view.map { (name, ref) =>
+ s"${name} => ${ref.refCodeString}"
+ }.toList
val designParamCS =
if (designParamList.isEmpty || design.isVendorIPBlackbox) ""
else " generic map (" + designParamList.mkString("\n", ",\n", "\n").hindent(1) + ")"
@@ -211,7 +217,7 @@ protected trait VHDLOwnerPrinter extends AbstractOwnerPrinter:
def csDFCaseKeyword: String = "when "
def csDFCaseSeparator: String = " =>"
def csDFCaseGuard(guardRef: DFConditional.Block.GuardRef): String = printer.unsupported
- def csDFMatchStatement(csSelector: String, wildcardSupport: Boolean): String =
+ def csDFMatchStatement(csSelector: String, wildcardSupport: Boolean, isUnique: Boolean): String =
s"case $csSelector is"
def csDFMatchEnd: String = "end case;"
def csProcessBlock(pb: ProcessBlock): String =
diff --git a/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLPrinter.scala b/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLPrinter.scala
index 1bd8fcc18..d16fd5388 100644
--- a/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLPrinter.scala
+++ b/compiler/stages/src/main/scala/dfhdl/compiler/stages/vhdl/VHDLPrinter.scala
@@ -154,72 +154,79 @@ class VHDLPrinter(val dialect: VHDLDialect)(using
def csDocString(doc: String): String = doc.linesIterator.mkString("--", "\n--", "")
def csAnnotations(annotations: List[annotation.HWAnnotation]): String = ""
// def csTimer(timer: Timer): String = unsupported
- def globalFileName: String = s"${printer.packageName}.vhd"
+ def globalFileName: String =
+ val name = printerOptions.globalDefsFileName
+ if (name.nonEmpty && name.contains('.')) name
+ else s"${printer.packageName}.vhd"
def designFileName(designName: String): String = s"$designName.vhd"
def dfhdlDefsFileName: String = s"dfhdl_pkg.vhd"
def dfhdlSourceContents: String =
scala.io.Source.fromResource(dfhdlDefsFileName).getLines().mkString("\n")
+ override protected def hasGlobalContentCheck: Boolean =
+ super.hasGlobalContentCheck || printer.globalVectorTypes.nonEmpty
override def csGlobalFileContent: String =
- // In VHDL the vectors need to be named, and put in dependency order of other named types.
- // So first we prepare the vector type declarations in a mutable map and later we remove
- // entries that were already placed in the final type printing.
- val vectorTypeDcls = mutable.Map.from(
- printer.globalVectorTypes.view.map { case (tpName, (vecType, depth)) =>
- tpName -> printer.csDFVectorDclsGlobal(DclScope.Pkg)(tpName, vecType, depth)
- }
- )
- // The body declarations can be in any order, as long as it's consistent between compilations.
- val vectorTypeDclsBody =
- printer.globalVectorTypes.view.map { case (tpName, (vecType, depth)) =>
- printer.csDFVectorDclsGlobal(DclScope.PkgBody)(tpName, vecType, depth)
- }.mkString("\n")
- // collect the global named types, including vectors
- val namedDFTypes = ListSet.from(getSet.designDB.members.view.collect {
- case port @ DclPort() => port.dfType
- case const @ DclConst() if const.isGlobal => const.dfType
- }.flatMap(_.decompose { case dt: (DFVector | NamedDFType) => dt }))
- // declarations of the types and relevant functions
- val namedTypeConvFuncsDcl = namedDFTypes.view
- .flatMap {
- // vector types can have different dimensions, but we only need the declaration once
- case dfType: DFVector =>
- val tpName = printer.getVecDepthAndCellTypeName(dfType)._1
- vectorTypeDcls.get(tpName) match
- case Some(desc) =>
- vectorTypeDcls -= tpName
- Some(desc)
- case None => None
- case dfType: NamedDFType =>
- List(
- printer.csNamedDFTypeDcl(dfType, global = true),
- printer.csNamedDFTypeConvFuncsDcl(dfType)
- )
- }
- .mkString("\n")
- val namedTypeConvFuncsBody =
- getSet.designDB.getGlobalNamedDFTypes.view
- .collect { case dfType: NamedDFType => printer.csNamedDFTypeConvFuncsBody(dfType) }
+ if (hasGlobalContent)
+ // In VHDL the vectors need to be named, and put in dependency order of other named types.
+ // So first we prepare the vector type declarations in a mutable map and later we remove
+ // entries that were already placed in the final type printing.
+ val vectorTypeDcls = mutable.Map.from(
+ printer.globalVectorTypes.view.map { case (tpName, (vecType, depth)) =>
+ tpName -> printer.csDFVectorDclsGlobal(DclScope.Pkg)(tpName, vecType, depth)
+ }
+ )
+ // The body declarations can be in any order, as long as it's consistent between compilations.
+ val vectorTypeDclsBody =
+ printer.globalVectorTypes.view.map { case (tpName, (vecType, depth)) =>
+ printer.csDFVectorDclsGlobal(DclScope.PkgBody)(tpName, vecType, depth)
+ }.mkString("\n")
+ // collect the global named types, including vectors
+ val namedDFTypes = ListSet.from(getSet.designDB.members.view.collect {
+ case port @ DclPort() => port.dfType
+ case const @ DclConst() if const.isGlobal => const.dfType
+ }.flatMap(_.decompose { case dt: (DFVector | NamedDFType) => dt }))
+ // declarations of the types and relevant functions
+ val namedTypeConvFuncsDcl = namedDFTypes.view
+ .flatMap {
+ // vector types can have different dimensions, but we only need the declaration once
+ case dfType: DFVector =>
+ val tpName = printer.getVecDepthAndCellTypeName(dfType)._1
+ vectorTypeDcls.get(tpName) match
+ case Some(desc) =>
+ vectorTypeDcls -= tpName
+ Some(desc)
+ case None => None
+ case dfType: NamedDFType =>
+ List(
+ printer.csNamedDFTypeDcl(dfType, global = true),
+ printer.csNamedDFTypeConvFuncsDcl(dfType)
+ )
+ }
.mkString("\n")
- val usesMathReal = getSet.designDB.membersGlobals.exists {
- _.dfType.decompose { case dt: DFDouble => dt }.nonEmpty
- }
- sn"""|library ieee;
- |use ieee.std_logic_1164.all;
- |use ieee.numeric_std.all;
- |${if (usesMathReal) "use ieee.math_real.all;" else ""}
- |use work.dfhdl_pkg.all;
- |
- |package ${printer.packageName} is
- |${csGlobalConstIntDcls}
- |${namedTypeConvFuncsDcl}
- |${csGlobalConstNonIntDcls}
- |end package ${printer.packageName};
- |
- |package body ${printer.packageName} is
- |${namedTypeConvFuncsBody}
- |${vectorTypeDclsBody}
- |end package body ${printer.packageName};
- |"""
+ val namedTypeConvFuncsBody =
+ getSet.designDB.getGlobalNamedDFTypes.view
+ .collect { case dfType: NamedDFType => printer.csNamedDFTypeConvFuncsBody(dfType) }
+ .mkString("\n")
+ val usesMathReal = getSet.designDB.membersGlobals.exists {
+ _.dfType.decompose { case dt: DFDouble => dt }.nonEmpty
+ }
+ sn"""|library ieee;
+ |use ieee.std_logic_1164.all;
+ |use ieee.numeric_std.all;
+ |${if (usesMathReal) "use ieee.math_real.all;" else ""}
+ |use work.dfhdl_pkg.all;
+ |
+ |package ${printer.packageName} is
+ |${csGlobalConstIntDcls}
+ |${namedTypeConvFuncsDcl}
+ |${csGlobalConstNonIntDcls}
+ |end package ${printer.packageName};
+ |
+ |package body ${printer.packageName} is
+ |${namedTypeConvFuncsBody}
+ |${vectorTypeDclsBody}
+ |end package body ${printer.packageName};
+ |"""
+ else ""
end csGlobalFileContent
def alignCode(cs: String): String =
cs
diff --git a/compiler/stages/src/test/scala/StagesSpec/DropDesignParamDepsSpec.scala b/compiler/stages/src/test/scala/StagesSpec/DropDesignParamDepsSpec.scala
index 91dd8708d..49b4db535 100644
--- a/compiler/stages/src/test/scala/StagesSpec/DropDesignParamDepsSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/DropDesignParamDepsSpec.scala
@@ -124,10 +124,7 @@ class DropDesignParamDepsSpec extends StageSpec:
| val inner_depth: Int <> CONST = baseWidth + 1
| val x = Bits(baseWidth) <> IN
| val y = Bits(baseWidth) <> OUT
- | val inner = Inner(
- | width = baseWidth,
- | depth = inner_depth
- | )
+ | val inner = Inner(width = baseWidth)
| inner.x <> x
| y <> inner.y.resize(baseWidth)
|end Outer
diff --git a/compiler/stages/src/test/scala/StagesSpec/DropRTProcessSpec.scala b/compiler/stages/src/test/scala/StagesSpec/DropRTProcessSpec.scala
index 7f232682c..9a5abf749 100644
--- a/compiler/stages/src/test/scala/StagesSpec/DropRTProcessSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/DropRTProcessSpec.scala
@@ -11,15 +11,15 @@ class DropRTProcessSpec extends StageSpec():
val my_fsm = process:
def S0: Step =
y.din := 0
- if (x) NextStep else S0
+ if (x) S1 else S0
def S1: Step =
def onEntry =
y.din := 1
- if (x) S2 else FirstStep
+ if (x) S2 else S0
def S2: Step =
def onExit =
y.din := 0
- if (x) ThisStep else FirstStep
+ if (x) S2 else S0
end Foo
val top = (new Foo).dropRTProcess
assertCodeString(
@@ -54,6 +54,43 @@ class DropRTProcessSpec extends StageSpec():
|end Foo""".stripMargin
)
}
+ test("onEntry is not fired on self-transition") {
+ class Foo extends RTDesign:
+ val x = Bit <> IN
+ val y = Bit <> OUT.REG init 0
+ process:
+ def S0: Step =
+ if (x) S1 else S0
+ def S1: Step =
+ def onEntry =
+ y.din := 1
+ if (x) S1 else S0
+ end Foo
+ val top = (new Foo).dropRTProcess
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | enum State(val value: UInt[1] <> CONST) extends Encoded.Manual(1):
+ | case S0 extends State(d"1'0")
+ | case S1 extends State(d"1'1")
+ |
+ | val x = Bit <> IN
+ | val y = Bit <> OUT.REG init 0
+ | val state = State <> VAR.REG init State.S0
+ | state match
+ | case State.S0 =>
+ | if (x)
+ | y.din := 1
+ | state.din := State.S1
+ | else state.din := State.S0
+ | end if
+ | case State.S1 =>
+ | if (x) state.din := State.S1
+ | else state.din := State.S0
+ | end match
+ |end Foo""".stripMargin
+ )
+ }
test("unnamed FSM steps") {
class Foo extends RTDesign:
val x = Bit <> IN
@@ -98,20 +135,186 @@ class DropRTProcessSpec extends StageSpec():
|end Foo""".stripMargin
)
}
- test("process with no steps") {
+ test("process with a single step") {
+ class Foo extends RTDesign:
+ val x = Bit <> IN
+ val y = Bit <> OUT.REG init 0
+ process:
+ def S0: Step =
+ y.din := 0
+ S0
+ end S0
+ end Foo
+ val top = (new Foo).dropRTProcess
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | enum State(val value: UInt[1] <> CONST) extends Encoded.Manual(1):
+ | case S0 extends State(d"1'0")
+ |
+ | val x = Bit <> IN
+ | val y = Bit <> OUT.REG init 0
+ | val state = State <> VAR.REG init State.S0
+ | state match
+ | case State.S0 =>
+ | y.din := 0
+ | state.din := State.S0
+ | end match
+ |end Foo""".stripMargin
+ )
+ }
+ test("fall-through steps") {
+ class Foo extends RTDesign:
+ val x = Bit <> IN
+ val y = Bit <> OUT.REG init 0
+ process:
+ def S0: Step =
+ y.din := 0
+ S1
+ def S1: Step =
+ def fallThrough = x
+ def onEntry =
+ y.din := 1
+ S2
+ def S2: Step =
+ def fallThrough = !x
+ def onEntry =
+ y.din := !y
+ S3
+ def S3: Step =
+ def fallThrough = x ^ x.reg(1, init = 0)
+ def onEntry =
+ y.din := y ^ y.reg
+ S4
+ def S4: Step =
+ y.din := 0
+ if (x) S2 else S0
+ end Foo
+ val top = (new Foo).dropRTProcess
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | enum State(val value: UInt[3] <> CONST) extends Encoded.Manual(3):
+ | case S0 extends State(d"3'0")
+ | case S1 extends State(d"3'1")
+ | case S2 extends State(d"3'2")
+ | case S3 extends State(d"3'3")
+ | case S4 extends State(d"3'4")
+ |
+ | val x = Bit <> IN
+ | val y = Bit <> OUT.REG init 0
+ | val state = State <> VAR.REG init State.S0
+ | state match
+ | case State.S0 =>
+ | y.din := 0
+ | y.din := 1
+ | state.din := State.S1
+ | if (x)
+ | y.din := !y
+ | state.din := State.S2
+ | if (!x)
+ | y.din := y ^ y.reg
+ | state.din := State.S3
+ | if (x ^ x.reg(1, init = 0)) state.din := State.S4
+ | end if
+ | end if
+ | case State.S1 =>
+ | y.din := !y
+ | state.din := State.S2
+ | if (!x)
+ | y.din := y ^ y.reg
+ | state.din := State.S3
+ | if (x ^ x.reg(1, init = 0)) state.din := State.S4
+ | end if
+ | case State.S2 =>
+ | y.din := y ^ y.reg
+ | state.din := State.S3
+ | if (x ^ x.reg(1, init = 0)) state.din := State.S4
+ | case State.S3 => state.din := State.S4
+ | case State.S4 =>
+ | y.din := 0
+ | if (x)
+ | y.din := !y
+ | state.din := State.S2
+ | if (!x)
+ | y.din := y ^ y.reg
+ | state.din := State.S3
+ | if (x ^ x.reg(1, init = 0)) state.din := State.S4
+ | end if
+ | else state.din := State.S0
+ | end if
+ | end match
+ |end Foo""".stripMargin
+ )
+ }
+ test("circular fall-through steps") {
class Foo extends RTDesign:
val x = Bit <> IN
val y = Bit <> OUT.REG init 0
process:
- y.din := 0
+ def S0: Step =
+ def fallThrough = x
+ def onEntry =
+ y.din := y
+ S1
+ def S1: Step =
+ def fallThrough = !x
+ def onEntry =
+ y.din := !y
+ S2
+ def S2: Step =
+ def fallThrough = x ^ x.reg(1, init = 0)
+ def onEntry =
+ y.din := y ^ y.reg
+ S0
end Foo
val top = (new Foo).dropRTProcess
assertCodeString(
top,
"""|class Foo extends RTDesign:
+ | enum State(val value: UInt[2] <> CONST) extends Encoded.Manual(2):
+ | case S0 extends State(d"2'0")
+ | case S1 extends State(d"2'1")
+ | case S2 extends State(d"2'2")
+ |
| val x = Bit <> IN
| val y = Bit <> OUT.REG init 0
- | y.din := 0
+ | val state = State <> VAR.REG init State.S0
+ | state match
+ | case State.S0 =>
+ | y.din := !y
+ | state.din := State.S1
+ | if (!x)
+ | y.din := y ^ y.reg
+ | state.din := State.S2
+ | if (x ^ x.reg(1, init = 0))
+ | y.din := y
+ | state.din := State.S0
+ | end if
+ | end if
+ | case State.S1 =>
+ | y.din := y ^ y.reg
+ | state.din := State.S2
+ | if (x ^ x.reg(1, init = 0))
+ | y.din := y
+ | state.din := State.S0
+ | if (x)
+ | y.din := !y
+ | state.din := State.S1
+ | end if
+ | end if
+ | case State.S2 =>
+ | y.din := y
+ | state.din := State.S0
+ | if (x)
+ | y.din := !y
+ | state.din := State.S1
+ | if (!x)
+ | y.din := y ^ y.reg
+ | state.din := State.S2
+ | end if
+ | end if
+ | end match
|end Foo""".stripMargin
)
}
diff --git a/compiler/stages/src/test/scala/StagesSpec/DropRTWaitsSpec.scala b/compiler/stages/src/test/scala/StagesSpec/DropRTWaitsSpec.scala
index b2b5ce929..7a93455c7 100644
--- a/compiler/stages/src/test/scala/StagesSpec/DropRTWaitsSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/DropRTWaitsSpec.scala
@@ -4,13 +4,49 @@ import dfhdl.*
import dfhdl.compiler.stages.dropRTWaits
class DropRTWaitsSpec extends StageSpec():
- test("basic single cycle wait") {
+ test("empty RT process block") {
+ class Foo extends RTDesign:
+ process {}
+ end Foo
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
+ |end Foo""".stripMargin
+ )
+ }
+ test("single statement in process block") {
+ class Foo extends RTDesign:
+ val i = Bit <> IN
+ val x = Bit <> OUT.REG
+ process:
+ x.din := i
+ end Foo
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Bit <> IN
+ | val x = Bit <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
+ | x.din := i
+ |end Foo""".stripMargin
+ )
+ }
+ test("basic single cycle wait before assignment") {
class Foo extends RTDesign:
val i = Bit <> IN
val x = Bit <> OUT.REG
process:
- x.din := 1
1.cy.wait
+ x.din := i
end Foo
val top = (new Foo).dropRTWaits
assertCodeString(
@@ -19,7 +55,32 @@ class DropRTWaitsSpec extends StageSpec():
| val i = Bit <> IN
| val x = Bit <> OUT.REG
| process:
- | x.din := 1
+ | def S_0: Step =
+ | NextStep
+ | end S_0
+ | x.din := i
+ |end Foo""".stripMargin
+ )
+ }
+ test("basic single cycle wait after assignment") {
+ class Foo extends RTDesign:
+ val i = Bit <> IN
+ val x = Bit <> OUT.REG
+ process:
+ x.din := i
+ 1.cy.wait
+ end Foo
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Bit <> IN
+ | val x = Bit <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
+ | x.din := i
| def S_1: Step =
| NextStep
| end S_1
@@ -32,6 +93,7 @@ class DropRTWaitsSpec extends StageSpec():
val x = Bit <> OUT.REG
process:
x.din := 1
+ x.din := i
1.cy.wait
x.din := !x
1.cy.wait
@@ -47,7 +109,11 @@ class DropRTWaitsSpec extends StageSpec():
| val i = Bit <> IN
| val x = Bit <> OUT.REG
| process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
| x.din := 1
+ | x.din := i
| def S_1: Step =
| NextStep
| end S_1
@@ -83,13 +149,12 @@ class DropRTWaitsSpec extends StageSpec():
| val x = Bit <> OUT.REG
| val waitCnt1 = UInt(8) <> VAR.REG init d"8'0"
| process:
- | def S_1: Step =
+ | def S_0: Step =
| if (waitCnt1 != d"8'149")
| waitCnt1.din := waitCnt1 + d"8'1"
| ThisStep
| else NextStep
- | end if
- | end S_1
+ | end S_0
| waitCnt1.din := d"8'0"
| x.din := !x
|end Foo""".stripMargin
@@ -115,22 +180,22 @@ class DropRTWaitsSpec extends StageSpec():
| val x = Bit <> OUT.REG
| val waitCnt1 = UInt(8) <> VAR.REG init d"8'0"
| process:
- | def S_1: Step =
+ | def S_0: Step =
| if (waitCnt1 != d"8'149")
| waitCnt1.din := waitCnt1 + d"8'1"
- | def S_1_1: Step =
+ | def S_0_0: Step =
| NextStep
- | end S_1_1
- | def S_1_2: Step =
+ | end S_0_0
+ | def S_0_1: Step =
| NextStep
- | end S_1_2
- | def S_1_3: Step =
+ | end S_0_1
+ | def S_0_2: Step =
| NextStep
- | end S_1_3
+ | end S_0_2
| ThisStep
| else NextStep
| end if
- | end S_1
+ | end S_0
| waitCnt1.din := d"8'0"
| x.din := !x
|end Foo""".stripMargin
@@ -159,22 +224,66 @@ class DropRTWaitsSpec extends StageSpec():
| val waitCnt1 = UInt(8) <> VAR.REG init d"8'0"
| val waitCnt2 = UInt(8) <> VAR.REG init d"8'0"
| process:
- | def S_1: Step =
+ | def S_0: Step =
| if (waitCnt1 != d"8'149")
| waitCnt1.din := waitCnt1 + d"8'1"
| ThisStep
| else NextStep
- | end if
+ | end S_0
+ | waitCnt1.din := d"8'0"
+ | x.din := !x
+ | def S_1: Step =
+ | if (waitCnt2 != d"8'149")
+ | waitCnt2.din := waitCnt2 + d"8'1"
+ | ThisStep
+ | else NextStep
| end S_1
+ | waitCnt2.din := d"8'0"
+ | x.din := 1
+ |end Foo""".stripMargin
+ )
+ }
+ test("basic multiple while loops with fall-through") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG
+ val waitCnt1 = UInt(8) <> VAR.REG init 0
+ val waitCnt2 = UInt(8) <> VAR.REG init 0
+ process:
+ while (waitCnt1 != 149)
+ FALL_THROUGH
+ waitCnt1.din := waitCnt1 + 1
+ waitCnt1.din := 0
+ x.din := !x
+ while (waitCnt2 != 149)
+ waitCnt2.din := waitCnt2 + 1
+ waitCnt2.din := 0
+ x.din := 1
+ end Foo
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG
+ | val waitCnt1 = UInt(8) <> VAR.REG init d"8'0"
+ | val waitCnt2 = UInt(8) <> VAR.REG init d"8'0"
+ | process:
+ | def S_0: Step =
+ | def fallThrough: Boolean <> VAL =
+ | !(waitCnt1 != d"8'149")
+ | end fallThrough
+ | if (waitCnt1 != d"8'149")
+ | waitCnt1.din := waitCnt1 + d"8'1"
+ | ThisStep
+ | else NextStep
+ | end S_0
| waitCnt1.din := d"8'0"
| x.din := !x
- | def S_2: Step =
+ | def S_1: Step =
| if (waitCnt2 != d"8'149")
| waitCnt2.din := waitCnt2 + d"8'1"
| ThisStep
| else NextStep
- | end if
- | end S_2
+ | end S_1
| waitCnt2.din := d"8'0"
| x.din := 1
|end Foo""".stripMargin
@@ -202,22 +311,21 @@ class DropRTWaitsSpec extends StageSpec():
| val waitCnt1 = UInt(8) <> VAR.REG init d"8'0"
| val waitCnt2 = UInt(8) <> VAR.REG init d"8'0"
| process:
- | def S_1: Step =
+ | def S_0: Step =
| if (waitCnt1 != d"8'149")
- | def S_1_1: Step =
+ | def S_0_0: Step =
| if (waitCnt2 != d"8'149")
| waitCnt2.din := waitCnt2 + d"8'1"
| ThisStep
| else NextStep
- | end if
- | end S_1_1
+ | end S_0_0
| waitCnt2.din := d"8'0"
| x.din := !x
| waitCnt1.din := waitCnt1 + d"8'1"
| ThisStep
| else NextStep
| end if
- | end S_1
+ | end S_0
| waitCnt1.din := d"8'0"
|end Foo""".stripMargin
)
@@ -243,6 +351,9 @@ class DropRTWaitsSpec extends StageSpec():
"""|class Foo extends RTDesign:
| val x = Bit <> OUT.REG init 0
| process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
| if (x)
| x.din := !x
| def S_1: Step =
@@ -292,6 +403,9 @@ class DropRTWaitsSpec extends StageSpec():
| val x = Bit <> OUT.REG init 0
| val waitCnt1 = UInt(8) <> VAR.REG init d"8'0"
| process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
| if (x)
| x.din := !x
| def S_1: Step =
@@ -299,7 +413,6 @@ class DropRTWaitsSpec extends StageSpec():
| waitCnt1.din := waitCnt1 + d"8'1"
| ThisStep
| else NextStep
- | end if
| end S_1
| waitCnt1.din := d"8'0"
| else
@@ -321,4 +434,178 @@ class DropRTWaitsSpec extends StageSpec():
|end Foo""".stripMargin
)
}
+ test("basic named steps") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG init 0
+ process:
+ x.din := 1
+ def MyStep: Step =
+ NextStep
+ end MyStep
+ 1.cy.wait
+ end Foo
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG init 0
+ | process:
+ | def S_0: Step =
+ | NextStep
+ | end S_0
+ | x.din := 1
+ | def MyStep: Step =
+ | NextStep
+ | end MyStep
+ | def S_2: Step =
+ | NextStep
+ | end S_2
+ |end Foo""".stripMargin
+ )
+ }
+ test("basic named steps with nested steps") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG init 0
+ process:
+ def MyStep: Step =
+ 1.cy.wait
+ def Internal: Step =
+ NextStep
+ end Internal
+ 1.cy.wait
+ NextStep
+ end MyStep
+ end Foo
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG init 0
+ | process:
+ | def MyStep: Step =
+ | def MyStep_0: Step =
+ | NextStep
+ | end MyStep_0
+ | def MyStep_Internal: Step =
+ | NextStep
+ | end MyStep_Internal
+ | def MyStep_2: Step =
+ | NextStep
+ | end MyStep_2
+ | NextStep
+ | end MyStep
+ |end Foo""".stripMargin
+ )
+ }
+ test("complex named steps with nested steps, loops, and waits") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG init 0
+ process:
+ def MyStep: Step =
+ 1.cy.wait
+ def Internal: Step =
+ def Deeper: Step =
+ NextStep
+ end Deeper
+ 1.cy.wait
+ NextStep
+ end Internal
+ 1.cy.wait
+ NextStep
+ end MyStep
+ x.din := !x
+ def MyStepB: Step =
+ def MyStepB_Internal: Step =
+ NextStep
+ end MyStepB_Internal
+ 1.cy.wait
+ val MyWait = 1.cy.wait
+ 1.cy.wait
+ NextStep
+ end MyStepB
+ x.din := !x
+ val MyWhile = while (x)
+ x.din := !x
+ def GoGo: Step =
+ NextStep
+ end GoGo
+ 1.cy.wait
+ end MyWhile
+ x.din := !x
+ end Foo
+ // run dropRTWaits twice to test the nested step name handling (nothing should change after the first run)
+ val top = (new Foo).dropRTWaits.dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG init 0
+ | process:
+ | def MyStep: Step =
+ | def MyStep_0: Step =
+ | NextStep
+ | end MyStep_0
+ | def MyStep_Internal: Step =
+ | def MyStep_Internal_Deeper: Step =
+ | NextStep
+ | end MyStep_Internal_Deeper
+ | def MyStep_Internal_1: Step =
+ | NextStep
+ | end MyStep_Internal_1
+ | NextStep
+ | end MyStep_Internal
+ | def MyStep_2: Step =
+ | NextStep
+ | end MyStep_2
+ | NextStep
+ | end MyStep
+ | x.din := !x
+ | def MyStepB: Step =
+ | def MyStepB_Internal: Step =
+ | NextStep
+ | end MyStepB_Internal
+ | def MyStepB_1: Step =
+ | NextStep
+ | end MyStepB_1
+ | def MyStepB_MyWait: Step =
+ | NextStep
+ | end MyStepB_MyWait
+ | def MyStepB_3: Step =
+ | NextStep
+ | end MyStepB_3
+ | NextStep
+ | end MyStepB
+ | x.din := !x
+ | def MyWhile: Step =
+ | if (x)
+ | x.din := !x
+ | def MyWhile_GoGo: Step =
+ | NextStep
+ | end MyWhile_GoGo
+ | def MyWhile_1: Step =
+ | NextStep
+ | end MyWhile_1
+ | ThisStep
+ | else NextStep
+ | end if
+ | end MyWhile
+ | x.din := !x
+ |end Foo""".stripMargin
+ )
+ }
+ test("empty loop") {
+ class Foo extends RTDesign:
+ process:
+ while (true) {}
+ val top = (new Foo).dropRTWaits
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | process:
+ | def S_0: Step =
+ | if (true) ThisStep
+ | else NextStep
+ | end S_0
+ |end Foo""".stripMargin
+ )
+ }
end DropRTWaitsSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/ExplicitCondExprAssignSpec.scala b/compiler/stages/src/test/scala/StagesSpec/ExplicitCondExprAssignSpec.scala
index f72bb7255..66b31d69f 100644
--- a/compiler/stages/src/test/scala/StagesSpec/ExplicitCondExprAssignSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/ExplicitCondExprAssignSpec.scala
@@ -84,7 +84,7 @@ class ExplicitCondExprAssignSpec extends StageSpec(stageCreatesUnrefAnons = true
| case sd"16'1" => sd"4'5"
| case sd"16'2" => sd"4'3"
| end match
- | if (x < sd"16'11") z2 := (zz + sd"4'3").resize(16)
+ | if (x < sd"16'11") z2 := (zz +^ sd"4'3").resize(16)
| else z2 := zz.resize(16)
| case _ => z2 := z + sd"16'12"
| end match
diff --git a/compiler/stages/src/test/scala/StagesSpec/ExplicitNamedVarsSpec.scala b/compiler/stages/src/test/scala/StagesSpec/ExplicitNamedVarsSpec.scala
index 8898a807e..8a2e76d42 100644
--- a/compiler/stages/src/test/scala/StagesSpec/ExplicitNamedVarsSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/ExplicitNamedVarsSpec.scala
@@ -103,7 +103,7 @@ class ExplicitNamedVarsSpec extends StageSpec:
| case sd"16'1" => zz := sd"4'5"
| case sd"16'2" => zz := sd"4'3"
| end match
- | if (x < sd"16'11") z2 := (zz + sd"4'3").resize(16)
+ | if (x < sd"16'11") z2 := (zz +^ sd"4'3").resize(16)
| else z2 := zz.resize(16)
| case _ => z2 := z + sd"16'12"
| end match
@@ -118,10 +118,10 @@ class ExplicitNamedVarsSpec extends StageSpec:
val lhs = Bits(8) <> IN
val shifted = lhs << 1
val o = Bits(8) <> OUT
- o <> ((
+ o <> (
if (lhs(7)) shifted ^ h"1b"
else shifted
- ): Bits[8] <> VAL)
+ )
end xtime
val id = (new xtime).explicitNamedVars
assertCodeString(
@@ -137,4 +137,128 @@ class ExplicitNamedVarsSpec extends StageSpec:
)
}
+ test("Simple named ident") {
+ class ID extends DFDesign:
+ val x = SInt(16) <> IN
+ val y = SInt(16) <> OUT
+ val v = x
+ y := v
+ end ID
+ val id = (new ID).explicitNamedVars
+ assertCodeString(
+ id,
+ """|class ID extends DFDesign:
+ | val x = SInt(16) <> IN
+ | val y = SInt(16) <> OUT
+ | val v = SInt(16) <> VAR
+ | v := x
+ | y := v
+ |end ID
+ |""".stripMargin
+ )
+ }
+
+ test("RT process block named values") {
+ class ID extends RTDesign:
+ val x = SInt(16) <> IN
+ val y = SInt(16) <> OUT.REG init 0
+ process:
+ def S0: Step =
+ val v = x
+ y.din := v
+ NextStep
+ val vr = x
+ def S1: Step =
+ y.din := vr + 1
+ NextStep
+ val vrc = (if (x > 5) x else x + 1)
+ def S2: Step =
+ y.din := vrc
+ NextStep
+ val vm = x
+ y.din := vm
+ def S3: Step =
+ y.din := vm
+ NextStep
+ val vrcm = (if (x > 5) x else x + 1)
+ y.din := vrcm
+ def S4: Step =
+ y.din := vrcm
+ NextStep
+ end ID
+ val id = (new ID).explicitNamedVars
+ assertCodeString(
+ id,
+ """|class ID extends RTDesign:
+ | val x = SInt(16) <> IN
+ | val y = SInt(16) <> OUT.REG init sd"16'0"
+ | process:
+ | def S0: Step =
+ | val v = SInt(16) <> VAR
+ | v := x
+ | y.din := v
+ | NextStep
+ | end S0
+ | val vr = SInt(16) <> VAR.REG
+ | vr.din := x
+ | def S1: Step =
+ | y.din := vr + sd"16'1"
+ | NextStep
+ | end S1
+ | val vrc = SInt(16) <> VAR.REG
+ | if (x > sd"16'5") vrc.din := x
+ | else vrc.din := x + sd"16'1"
+ | def S2: Step =
+ | y.din := vrc
+ | NextStep
+ | end S2
+ | val vm_din = SInt(16) <> VAR
+ | val vm = SInt(16) <> VAR.REG
+ | vm_din := x
+ | vm.din := vm_din
+ | y.din := vm_din
+ | def S3: Step =
+ | y.din := vm
+ | NextStep
+ | end S3
+ | val vrcm_din = SInt(16) <> VAR
+ | val vrcm = SInt(16) <> VAR.REG
+ | if (x > sd"16'5") vrcm_din := x
+ | else vrcm_din := x + sd"16'1"
+ | y.din := vrcm_din
+ | def S4: Step =
+ | y.din := vrcm
+ | NextStep
+ | end S4
+ |end ID""".stripMargin
+ )
+ }
+ test("EDDomain rules") {
+ class ID extends EDDesign:
+ val x = SInt(16) <> IN
+ val y = SInt(16) <> OUT
+ val py = SInt(16) <> OUT
+ val v = x
+ y <> v
+ process:
+ val pv = x
+ py := pv
+ end ID
+ val id = (new ID).explicitNamedVars
+ assertCodeString(
+ id,
+ """|class ID extends EDDesign:
+ | val x = SInt(16) <> IN
+ | val y = SInt(16) <> OUT
+ | val py = SInt(16) <> OUT
+ | val v = SInt(16) <> VAR
+ | v <> x
+ | y <> v
+ | process:
+ | val pv = SInt(16) <> VAR
+ | pv := x
+ | py := pv
+ |end ID""".stripMargin
+ )
+ }
end ExplicitNamedVarsSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/FlattenStepBlocksSpec.scala b/compiler/stages/src/test/scala/StagesSpec/FlattenStepBlocksSpec.scala
new file mode 100644
index 000000000..0e342996c
--- /dev/null
+++ b/compiler/stages/src/test/scala/StagesSpec/FlattenStepBlocksSpec.scala
@@ -0,0 +1,524 @@
+package StagesSpec
+
+import dfhdl.*
+import dfhdl.compiler.stages.flattenStepBlocks
+// scalafmt: { align.tokens = [{code = "<>"}, {code = "="}, {code = "=>"}, {code = ":="}]}
+
+class FlattenStepBlocksSpec extends StageSpec():
+
+ test("single flat step") {
+ class Foo extends RTDesign:
+ process:
+ def S_0: Step =
+ NextStep
+ end S_0
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | process:
+ | def S_0: Step =
+ | S_0
+ | end S_0
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("two flat steps") {
+ class Foo extends RTDesign:
+ val y = Bit <> OUT.REG init 0
+ process:
+ def S0: Step =
+ y.din := 0
+ NextStep
+ end S0
+ def S1: Step =
+ y.din := 1
+ NextStep
+ end S1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val y = Bit <> OUT.REG init 0
+ | process:
+ | def S0: Step =
+ | y.din := 0
+ | S1
+ | end S0
+ | def S1: Step =
+ | y.din := 1
+ | S0
+ | end S1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("two flat steps with inter-step statement") {
+ class Foo extends RTDesign:
+ val i = Bit <> IN
+ val x = Bit <> OUT.REG
+ process:
+ def S_0: Step =
+ NextStep
+ end S_0
+ x.din := i
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Bit <> IN
+ | val x = Bit <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | x.din := i
+ | S_1
+ | end S_0
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("one level of nesting") {
+ class Foo extends RTDesign:
+ process:
+ def MyStep: Step =
+ def MyStep_0: Step =
+ NextStep
+ end MyStep_0
+ NextStep
+ end MyStep
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | process:
+ | def MyStep: Step =
+ | MyStep_0
+ | end MyStep
+ | def MyStep_0: Step =
+ | MyStep
+ | end MyStep_0
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("three flat steps with inter-step statements") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG
+ val y = Bit <> OUT.REG
+ process:
+ def S_0: Step =
+ NextStep
+ end S_0
+ x.din := 0
+ def S_1: Step =
+ NextStep
+ end S_1
+ y.din := 1
+ def S_2: Step =
+ NextStep
+ end S_2
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG
+ | val y = Bit <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | x.din := 0
+ | S_1
+ | end S_0
+ | def S_1: Step =
+ | y.din := 1
+ | S_2
+ | end S_1
+ | def S_2: Step =
+ | S_0
+ | end S_2
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("nested siblings with inter-step statements") {
+ class Foo extends RTDesign:
+ val a = Int <> OUT.REG
+ val b = Int <> OUT.REG
+ process:
+ def S_0: Step =
+ a.din := 1
+ def S_0_0: Step =
+ NextStep
+ end S_0_0
+ b.din := 2
+ def S_0_1: Step =
+ NextStep
+ end S_0_1
+ NextStep
+ end S_0
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val a = Int <> OUT.REG
+ | val b = Int <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | a.din := 1
+ | S_0_0
+ | end S_0
+ | def S_0_0: Step =
+ | b.din := 2
+ | S_0_1
+ | end S_0_0
+ | def S_0_1: Step =
+ | S_1
+ | end S_0_1
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("two levels of nesting with inner-to-outer statement relocation") {
+ class Foo extends RTDesign:
+ val a = Int <> OUT.REG
+ val b = Int <> OUT.REG
+ val c = Int <> OUT.REG
+ process:
+ def S_0: Step =
+ def S_0_0: Step =
+ a.din := 1
+ def S_0_0_0: Step =
+ NextStep
+ end S_0_0_0
+ b.din := 2
+ NextStep
+ end S_0_0
+ c.din := 3
+ NextStep
+ end S_0
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val a = Int <> OUT.REG
+ | val b = Int <> OUT.REG
+ | val c = Int <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | S_0_0
+ | end S_0
+ | def S_0_0: Step =
+ | a.din := 1
+ | S_0_0_0
+ | end S_0_0
+ | def S_0_0_0: Step =
+ | b.din := 2
+ | c.din := 3
+ | S_1
+ | end S_0_0_0
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("ThisStep and FirstStep resolution") {
+ class Foo extends RTDesign:
+ val i = Bit <> IN
+ process:
+ def S_0: Step =
+ if (i)
+ ThisStep
+ else
+ NextStep
+ end if
+ end S_0
+ def S_1: Step =
+ if (i)
+ FirstStep
+ else
+ NextStep
+ end if
+ end S_1
+ def S_2: Step =
+ NextStep
+ end S_2
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Bit <> IN
+ | process:
+ | def S_0: Step =
+ | if (i) S_0
+ | else S_1
+ | end S_0
+ | def S_1: Step =
+ | if (i) S_0
+ | else S_2
+ | end S_1
+ | def S_2: Step =
+ | S_0
+ | end S_2
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("step nested inside conditional branch") {
+ class Foo extends RTDesign:
+ val i = Bit <> IN
+ process:
+ def S_0: Step =
+ if (i)
+ def S_0_0: Step =
+ NextStep
+ end S_0_0
+ ThisStep
+ else
+ NextStep
+ end if
+ end S_0
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Bit <> IN
+ | process:
+ | def S_0: Step =
+ | if (i) S_0_0
+ | else S_1
+ | end S_0
+ | def S_0_0: Step =
+ | S_0
+ | end S_0_0
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("step nested inside conditional branch with inter-step statement") {
+ class Foo extends RTDesign:
+ val i = Bit <> IN
+ val x = Bit <> OUT.REG
+ process:
+ def S_0: Step =
+ if (i)
+ def S_0_0: Step =
+ NextStep
+ end S_0_0
+ x.din := 1
+ ThisStep
+ else
+ NextStep
+ end if
+ end S_0
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Bit <> IN
+ | val x = Bit <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | if (i) S_0_0
+ | else S_1
+ | end S_0
+ | def S_0_0: Step =
+ | x.din := 1
+ | S_0
+ | end S_0_0
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("onEntry and onExit blocks move with their parent step during flattening") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG
+ process:
+ def S_0: Step =
+ def onEntry =
+ x.din := 1
+ end onEntry
+ def S_0_0: Step =
+ def onExit =
+ x.din := 0
+ end onExit
+ NextStep
+ end S_0_0
+ NextStep
+ end S_0
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG
+ | process:
+ | def S_0: Step =
+ | def onEntry: Unit =
+ | x.din := 1
+ | end onEntry
+ | S_0_0
+ | end S_0
+ | def S_0_0: Step =
+ | def onExit: Unit =
+ | x.din := 0
+ | end onExit
+ | S_1
+ | end S_0_0
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test(
+ "multiple inter-step statements from nested and conditional scopes collected before single NextStep"
+ ) {
+ class Foo extends RTDesign:
+ val a = Int <> OUT.REG
+ val b = Int <> OUT.REG
+ val c = Int <> OUT.REG
+ val i = Bit <> IN
+ process:
+ def S_0: Step =
+ def S_0_0: Step =
+ if (i)
+ a.din := 1
+ else
+ a.din := 0
+ end if
+ NextStep
+ end S_0_0
+ b.din := 2
+ NextStep
+ end S_0
+ c.din := 3
+ def S_1: Step =
+ NextStep
+ end S_1
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val a = Int <> OUT.REG
+ | val b = Int <> OUT.REG
+ | val c = Int <> OUT.REG
+ | val i = Bit <> IN
+ | process:
+ | def S_0: Step =
+ | S_0_0
+ | end S_0
+ | def S_0_0: Step =
+ | if (i) a.din := 1
+ | else a.din := 0
+ | b.din := 2
+ | c.din := 3
+ | S_1
+ | end S_0_0
+ | def S_1: Step =
+ | S_0
+ | end S_1
+ |end Foo""".stripMargin
+ )
+ }
+ test("multiple steps nested inside the same conditional branch with inter-step statements") {
+ class Foo extends RTDesign:
+ val i = Int <> VAR.REG
+ process:
+ def S_0: Step =
+ NextStep
+ end S_0
+ i.din := 0
+ def S_1: Step =
+ if (i < 3)
+ println(s"Hello")
+ def S_1_0: Step =
+ NextStep
+ end S_1_0
+ println(s"World")
+ def S_1_1: Step =
+ NextStep
+ end S_1_1
+ println(s"!")
+ i.din := i + 1
+ ThisStep
+ else NextStep
+ end if
+ end S_1
+ finish()
+ end Foo
+ val top = (new Foo).flattenStepBlocks
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val i = Int <> VAR.REG
+ | process:
+ | def S_0: Step =
+ | i.din := 0
+ | S_1
+ | end S_0
+ | def S_1: Step =
+ | if (i < 3)
+ | println(s"Hello")
+ | S_1_0
+ | else
+ | finish()
+ | S_0
+ | end S_1
+ | def S_1_0: Step =
+ | println(s"World")
+ | S_1_1
+ | end S_1_0
+ | def S_1_1: Step =
+ | println(s"!")
+ | i.din := i + 1
+ | S_1
+ | end S_1_1
+ |end Foo""".stripMargin
+ )
+ }
+
+end FlattenStepBlocksSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/GlobalizePortVectorParamsSpec.scala b/compiler/stages/src/test/scala/StagesSpec/GlobalizePortVectorParamsSpec.scala
index 7dc350a90..a38402cdf 100644
--- a/compiler/stages/src/test/scala/StagesSpec/GlobalizePortVectorParamsSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/GlobalizePortVectorParamsSpec.scala
@@ -4,7 +4,7 @@ import dfhdl.*
import dfhdl.compiler.stages.globalizePortVectorParams
// scalafmt: { align.tokens = [{code = "<>"}, {code = "="}, {code = "=>"}, {code = ":="}]}
-class GlobalizePortVectorParams extends StageSpec(stageCreatesUnrefAnons = true):
+class GlobalizePortVectorParamsSpec extends StageSpec(stageCreatesUnrefAnons = true):
given options.CompilerOptions.Backend = backends.vhdl.v93
test("Various vector params are kept"):
val width: Int <> CONST = 8
@@ -46,9 +46,13 @@ class GlobalizePortVectorParams extends StageSpec(stageCreatesUnrefAnons = true)
)
test("Various vector params are globalized, only ports are affected"):
class Foo(
- val width: Int <> CONST = 8,
- val length: Int <> CONST = 10
+ val keepThisParam: Int <> CONST = 4,
+ val width: Int <> CONST = 8,
+ val length: Int <> CONST = 10
) extends RTDesign:
+ val x0 = Bits(keepThisParam) <> IN
+ val y0 = Bits(keepThisParam) <> OUT
+ y0 <> x0
val x1 = Bits(width) X length <> IN
val y1 = Bits(width) X length <> OUT
val v1 = Bits(width) X length <> VAR
@@ -76,7 +80,10 @@ class GlobalizePortVectorParams extends StageSpec(stageCreatesUnrefAnons = true)
"""|val Foo_length: Int <> CONST = 10
|val Foo_width: Int <> CONST = 8
|
- |class Foo extends RTDesign:
+ |class Foo(val keepThisParam: Int <> CONST = 4) extends RTDesign:
+ | val x0 = Bits(keepThisParam) <> IN
+ | val y0 = Bits(keepThisParam) <> OUT
+ | y0 <> x0
| val x1 = Bits(Foo_width) X Foo_length <> IN
| val y1 = Bits(Foo_width) X Foo_length <> OUT
| val v1 = Bits(Foo_width) X Foo_length <> VAR
@@ -312,4 +319,52 @@ class GlobalizePortVectorParams extends StageSpec(stageCreatesUnrefAnons = true)
| y3 <> id3.y
|end IDTop""".stripMargin
)
-end GlobalizePortVectorParams
+
+ test("Duplicate designs with nested design instances"):
+ class ID extends EDDesign:
+ val x = Bits(8) <> IN
+ val y = Bits(8) <> OUT
+ y <> x
+ end ID
+
+ class Internal(val param: Bits[8] <> CONST) extends EDDesign:
+ val x = Bits(8) <> IN
+ val y = Bits(8) <> OUT
+ val id = ID()
+ id.x <> x
+ y <> id.y
+ end Internal
+
+ class Foo extends EDDesign:
+ val state = Bits(8) <> IN
+ val o00 = Internal(param = h"02")
+ val o01 = Internal(param = h"01")
+ o00.x <> state
+ o01.x <> state
+ val top = (new Foo).globalizePortVectorParams
+ assertCodeString(
+ top,
+ """|class ID extends EDDesign:
+ | val x = Bits(8) <> IN
+ | val y = Bits(8) <> OUT
+ | y <> x
+ |end ID
+ |
+ |class Internal(val param: Bits[8] <> CONST) extends EDDesign:
+ | val x = Bits(8) <> IN
+ | val y = Bits(8) <> OUT
+ | val id = ID()
+ | id.x <> x
+ | y <> id.y
+ |end Internal
+ |
+ |class Foo extends EDDesign:
+ | val state = Bits(8) <> IN
+ | val o00 = Internal(param = h"02")
+ | val o01 = Internal(param = h"01")
+ | o00.x <> state
+ | o01.x <> state
+ |end Foo
+ |""".stripMargin
+ )
+end GlobalizePortVectorParamsSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/LocalToDesignParamsSpec.scala b/compiler/stages/src/test/scala/StagesSpec/LocalToDesignParamsSpec.scala
index cff228795..8f9657e2f 100644
--- a/compiler/stages/src/test/scala/StagesSpec/LocalToDesignParamsSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/LocalToDesignParamsSpec.scala
@@ -205,10 +205,7 @@ class LocalToDesignParamsSpec extends StageSpec:
|class PrimeDiv5 extends RTDesign:
| val primeDiv5_DIVIDEND_WIDTH: Int <> CONST = 5 + 1
| val dividend = UInt(6) <> VAR.REG init d"6'0"
- | val primeDiv5 = PrimeDiv(
- | primeDivisor = 5,
- | DIVIDEND_WIDTH = primeDiv5_DIVIDEND_WIDTH
- | )
+ | val primeDiv5 = PrimeDiv(primeDivisor = 5)
| primeDiv5.dividend <> dividend
|end PrimeDiv5""".stripMargin
)
diff --git a/compiler/stages/src/test/scala/StagesSpec/PrintCodeStringSpec.scala b/compiler/stages/src/test/scala/StagesSpec/PrintCodeStringSpec.scala
index c7230c505..beeebd8dd 100644
--- a/compiler/stages/src/test/scala/StagesSpec/PrintCodeStringSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/PrintCodeStringSpec.scala
@@ -201,6 +201,7 @@ class PrintCodeStringSpec extends StageSpec:
test("RTDesign with class extension and parameters") {
val gp: Bit <> CONST = 1
+ val gp2 = gp
val i: SInt[16] <> CONST = 0
val i2 = i + 5
class ID(dp: Bit <> CONST) extends RTDesign:
@@ -210,19 +211,20 @@ class PrintCodeStringSpec extends StageSpec:
val flag = Bit <> IN init dp || gp
y := x.reg.reg(2, init = c - i) - x
end ID
- class IDExt(dpNew: Bit <> CONST) extends ID(gp && dpNew):
+ class IDExt(dpNew: Bit <> CONST) extends ID(gp2 && dpNew):
val z = Bit <> OUT
z := dpNew
val id = (new IDExt(gp)).getCodeString
assertNoDiff(
id,
- """|val gp: Bit <> CONST = 1
- |val i: SInt[16] <> CONST = sd"16'0"
+ """|val i: SInt[16] <> CONST = sd"16'0"
|val i2: SInt[16] <> CONST = i + sd"16'5"
+ |val gp: Bit <> CONST = 1
+ |val gp2: Bit <> CONST = gp
|
|class IDExt(
- | val dp: Bit <> CONST = gp && gp,
+ | val dp: Bit <> CONST = gp2 && gp,
| val dpNew: Bit <> CONST = gp
|) extends RTDesign:
| val c: SInt[16] <> CONST = sd"16'3"
@@ -992,7 +994,8 @@ class PrintCodeStringSpec extends StageSpec:
10.ms.wait
if (i) S_2 else S_1
def S_2: Step =
- def onEntry =
+ def fallThrough = !i
+ def onEntry =
x := 0
def onExit =
x := 1
@@ -1015,6 +1018,9 @@ class PrintCodeStringSpec extends StageSpec:
| else S_1
| end S_1
| def S_2: Step =
+ | def fallThrough: Bit <> VAL =
+ | !i
+ | end fallThrough
| def onEntry: Unit =
| x := 0
| end onEntry
@@ -1171,6 +1177,57 @@ class PrintCodeStringSpec extends StageSpec:
|end Foo""".stripMargin
)
}
+ test("for/while loop printing with FALL_THROUGH") {
+ class Foo extends RTDesign:
+ val matrix = Bits(10) X 8 X 8 <> OUT.REG
+ process:
+ for (
+ i <- 0 until 8;
+ if i % 2 == 0;
+ j <- 0 until 8;
+ if j % 2 == 0;
+ k <- 0 until 10
+ if k % 2 == 0
+ )
+ FALL_THROUGH
+ matrix(i)(j)(k).din := 1
+ val ii = UInt.until(8) <> VAR init 0
+ while (ii != 7)
+ FALL_THROUGH
+ matrix(ii)(0)(0).din := 0
+ ii := ii + 1
+ 10.sec.wait
+ end Foo
+ val top = (new Foo).getCodeString
+ assertNoDiff(
+ top,
+ """|class Foo extends RTDesign:
+ | val matrix = Bits(10) X 8 X 8 <> OUT.REG
+ | process:
+ | for (i <- 0 until 8)
+ | FALL_THROUGH
+ | if ((i % 2) == 0)
+ | for (j <- 0 until 8)
+ | FALL_THROUGH
+ | if ((j % 2) == 0)
+ | for (k <- 0 until 10)
+ | FALL_THROUGH
+ | if ((k % 2) == 0) matrix(i)(j)(k).din := 1
+ | end for
+ | end if
+ | end for
+ | end if
+ | end for
+ | val ii = UInt(3) <> VAR init d"3'0"
+ | while (ii != d"3'7")
+ | FALL_THROUGH
+ | matrix(ii.toInt)(0)(0).din := 0
+ | ii := ii + d"3'1"
+ | end while
+ | 10.sec.wait
+ |end Foo""".stripMargin
+ )
+ }
test("while loop printing") {
class Foo extends EDDesign:
val x = Bit <> OUT
@@ -1606,4 +1663,74 @@ class PrintCodeStringSpec extends StageSpec:
|end Foo""".stripMargin
)
}
+
+ test("named rt-process loops") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG init 0
+ process:
+ val MyWhile = while (x)
+ def GoGo: Step =
+ NextStep
+ end GoGo
+ x.din := !x
+ end MyWhile
+ val MyFor = for (i <- 0 until 10)
+ def GoGo: Step =
+ NextStep
+ end GoGo
+ x.din := !x
+ end MyFor
+ end Foo
+ val top = (new Foo).getCodeString
+ assertNoDiff(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG init 0
+ | process:
+ | val MyWhile = while (x)
+ | def GoGo: Step =
+ | NextStep
+ | end GoGo
+ | x.din := !x
+ | end MyWhile
+ | val MyFor = for (i <- 0 until 10)
+ | def GoGo: Step =
+ | NextStep
+ | end GoGo
+ | x.din := !x
+ | end MyFor
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("parameterized selection") {
+ class Foo extends DFDesign:
+ val LEN: Int <> CONST = 8
+ val v = Bits(LEN) <> VAR
+ val o = v(LEN - 2, 0)
+ val top = (new Foo).getCodeString
+ assertNoDiff(
+ top,
+ """|class Foo extends DFDesign:
+ | val LEN: Int <> CONST = 8
+ | val v = Bits(LEN) <> VAR
+ | val o = v(LEN - 2, 0)
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("cascade aliasing regression") {
+ class Foo() extends DFDesign:
+ val x = UInt(3) <> IN
+ val y = x.resize(16).bits.sint
+ end Foo
+ val top = (new Foo).getCodeString
+ assertNoDiff(
+ top,
+ """|class Foo extends DFDesign:
+ | val x = UInt(3) <> IN
+ | val y = x.resize(16).bits.sint
+ |end Foo""".stripMargin
+ )
+ }
end PrintCodeStringSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala b/compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala
index ac5ca6080..89e21aec3 100644
--- a/compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala
@@ -39,7 +39,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.ID_pkg.all;
|
|entity ID is
|port (
@@ -64,7 +63,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.IDTop_pkg.all;
|
|entity ID is
|port (
@@ -82,7 +80,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.IDTop_pkg.all;
|
|entity IDTop is
|port (
@@ -133,7 +130,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.IDTop_pkg.all;
|
|entity ID is
|generic (
@@ -154,7 +150,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.IDTop_pkg.all;
|
|entity IDTop is
|generic (
@@ -223,7 +218,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Top_pkg.all;
|
|entity Top is
|port (
@@ -290,7 +284,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.numeric_std.all;
|use ieee.math_real.all;
|use work.dfhdl_pkg.all;
- |use work.Top_pkg.all;
|
|entity Top is
|end Top;
@@ -360,7 +353,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Blinker_pkg.all;
|
|entity Blinker is
|generic (
@@ -414,7 +406,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Example_pkg.all;
|
|entity Example is
|port (
@@ -611,7 +602,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.IDTop_pkg.all;
|
|entity IDTop is
|port (
@@ -657,7 +647,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.SelOp_pkg.all;
|
|entity SelOp is
|port (
@@ -694,7 +683,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Empty_pkg.all;
|
|entity Empty is
|end Empty;
@@ -719,7 +707,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.HighZ_pkg.all;
|
|entity HighZ is
|port (
@@ -756,7 +743,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -795,7 +781,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -907,7 +892,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -960,7 +944,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -1077,7 +1060,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -1122,7 +1104,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -1188,7 +1169,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|generic (
@@ -1231,7 +1211,7 @@ class PrintVHDLCodeSpec extends StageSpec:
| println("These are the values: " & to_string(param3) & ", " & to_string(param4) & ", " & to_string(param5) & ", " & to_string(param6) & ", " & to_string(param7) & ", " & to_string(param8) & ", " & to_string(param9) & ", " & t_enum_MyEnum'image(param10) & "");
| report
| "Debug at Foo" & LF &
- | "compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala:1177:9" & LF &
+ | "compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala:1158:9" & LF &
| "param3 = " & to_string(param3) & LF &
| "param4 = " & to_string(param4) & LF &
| "param5 = " & to_string(param5) & LF &
@@ -1250,7 +1230,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|generic (
@@ -1293,7 +1272,7 @@ class PrintVHDLCodeSpec extends StageSpec:
| println("These are the values: " & to_string(param3) & ", " & to_string(param4) & ", " & to_string(param5) & ", " & to_string(param6) & ", " & to_string(param7) & ", " & to_string(param8) & ", " & to_string(param9) & ", " & t_enum_MyEnum'image(param10) & "");
| report
| "Debug at Foo" & LF &
- | "compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala:1177:9" & LF &
+ | "compiler/stages/src/test/scala/StagesSpec/PrintVHDLCodeSpec.scala:1158:9" & LF &
| "param3 = " & to_string(param3) & LF &
| "param4 = " & to_string(param4) & LF &
| "param5 = " & to_string(param5) & LF &
@@ -1325,7 +1304,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|generic (
@@ -1374,7 +1352,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -1475,7 +1452,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -1517,7 +1493,6 @@ class PrintVHDLCodeSpec extends StageSpec:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.Foo_pkg.all;
|
|entity Foo is
|port (
@@ -1532,4 +1507,74 @@ class PrintVHDLCodeSpec extends StageSpec:
|end Foo_arch;""".stripMargin
)
}
+ test("globalDefsFileName override") {
+ given options.PrinterOptions.GlobalDefsFileName = "otherGlobal"
+ enum MyEnum extends Encoded:
+ case A, B
+ class Foo extends RTDesign:
+ val x = MyEnum <> IN
+ val y = MyEnum <> OUT
+ y := x
+ val top = (new Foo).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|type t_enum_MyEnum is (
+ | MyEnum_A, MyEnum_B
+ |);
+ |
+ |library ieee;
+ |use ieee.std_logic_1164.all;
+ |use ieee.numeric_std.all;
+ |use work.dfhdl_pkg.all;
+ |use work.otherGlobal.all;
+ |
+ |entity Foo is
+ |port (
+ | x : in t_enum_MyEnum;
+ | y : out t_enum_MyEnum
+ |);
+ |end Foo;
+ |
+ |architecture Foo_arch of Foo is
+ |begin
+ | y <= x;
+ |end Foo_arch;
+ |""".stripMargin
+ )
+ }
+ test("globalDefsFileName override with suffix") {
+ given options.PrinterOptions.GlobalDefsFileName = "otherGlobal.vhd"
+ enum MyEnum extends Encoded:
+ case A, B
+ class Foo extends RTDesign:
+ val x = MyEnum <> IN
+ val y = MyEnum <> OUT
+ y := x
+ val top = (new Foo).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|type t_enum_MyEnum is (
+ | MyEnum_A, MyEnum_B
+ |);
+ |
+ |library ieee;
+ |use ieee.std_logic_1164.all;
+ |use ieee.numeric_std.all;
+ |use work.dfhdl_pkg.all;
+ |use work.otherGlobal.all;
+ |
+ |entity Foo is
+ |port (
+ | x : in t_enum_MyEnum;
+ | y : out t_enum_MyEnum
+ |);
+ |end Foo;
+ |
+ |architecture Foo_arch of Foo is
+ |begin
+ | y <= x;
+ |end Foo_arch;
+ |""".stripMargin
+ )
+ }
end PrintVHDLCodeSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/PrintVerilogCodeSpec.scala b/compiler/stages/src/test/scala/StagesSpec/PrintVerilogCodeSpec.scala
index 7b3efa223..4cf1700c3 100644
--- a/compiler/stages/src/test/scala/StagesSpec/PrintVerilogCodeSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/PrintVerilogCodeSpec.scala
@@ -41,7 +41,6 @@ class PrintVerilogCodeSpec extends StageSpec:
id,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "ID_defs.svh"
|
|module ID(
| input wire logic signed [15:0] x,
@@ -62,7 +61,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.svh"
|
|module ID(
| input wire logic signed [15:0] x,
@@ -76,7 +74,6 @@ class PrintVerilogCodeSpec extends StageSpec:
|
|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.svh"
|
|module IDTop(
| input wire logic signed [15:0] x,
@@ -124,7 +121,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.svh"
|
|module ID#(parameter int width = 7)(
| input wire logic signed [width - 1:0] x,
@@ -136,7 +132,6 @@ class PrintVerilogCodeSpec extends StageSpec:
|
|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.svh"
|
|module IDTop#(parameter int width = 16)(
| input wire logic signed [width - 1:0] x,
@@ -187,14 +182,12 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.vh"
|
|module ID(
| x,
| y
|);
| `include "dfhdl_defs.vh"
- | `include "IDTop_defs.vh"
| parameter integer width = 7;
| input wire [width - 1:0] x;
| output wire [width - 1:0] y;
@@ -203,14 +196,12 @@ class PrintVerilogCodeSpec extends StageSpec:
|
|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.vh"
|
|module IDTop(
| x,
| y
|);
| `include "dfhdl_defs.vh"
- | `include "IDTop_defs.vh"
| parameter integer width = 16;
| input wire [width - 1:0] x;
| output wire [width - 1:0] y;
@@ -265,6 +256,34 @@ class PrintVerilogCodeSpec extends StageSpec:
)
}
+ test("Boolean logical operators") {
+ class BoolLogic extends RTDesign:
+ val a = Boolean <> IN
+ val b = Boolean <> IN
+ val y1 = Boolean <> OUT
+ val y2 = Boolean <> OUT
+ y1 := a || b
+ y2 := a && b
+ val top = (new BoolLogic).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|`default_nettype none
+ |`timescale 1ns/1ps
+ |
+ |module BoolLogic(
+ | input wire logic a,
+ | input wire logic b,
+ | output logic y1,
+ | output logic y2
+ |);
+ | `include "dfhdl_defs.svh"
+ | assign y1 = a || b;
+ | assign y2 = a && b;
+ |endmodule
+ |""".stripMargin
+ )
+ }
+
test("process block") {
given options.PrinterOptions.Align = true
class Top extends EDDesign:
@@ -295,7 +314,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Top_defs.svh"
|
|module Top(
| input wire logic clk,
@@ -353,7 +371,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Top_defs.svh"
|
|module Top;
| `include "dfhdl_defs.svh"
@@ -415,7 +432,6 @@ class PrintVerilogCodeSpec extends StageSpec:
"""|/* HasDocs has docs */
|`default_nettype none
|`timescale 1ns/1ps
- |`include "HasDocs_defs.svh"
|
|module HasDocs(
| /* My in */
@@ -444,7 +460,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Counter_defs.svh"
|
|module Counter#(parameter int width = 8)(
| input wire logic clk,
@@ -482,7 +497,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Test_defs.svh"
|
|module Test#(parameter int width = 10)(
| output logic [width - 1:0] x,
@@ -515,7 +529,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Counter_defs.svh"
|
|module Counter#(parameter int width = 8)(
| input wire logic clk,
@@ -557,7 +570,6 @@ class PrintVerilogCodeSpec extends StageSpec:
"""|/* This is a led blinker */
|`default_nettype none
|`timescale 1ns/1ps
- |`include "Blinker_defs.svh"
|
|module Blinker#(
| parameter int CLK_FREQ_KHz = 50000,
@@ -600,7 +612,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "IDTop_defs.svh"
|
|module IDTop(
| input wire logic clk,
@@ -637,7 +648,6 @@ class PrintVerilogCodeSpec extends StageSpec:
id,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "SelOp_defs.svh"
|
|module SelOp(
| input wire logic c,
@@ -668,7 +678,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Empty_defs.svh"
|
|module Empty;
| `include "dfhdl_defs.svh"
@@ -688,7 +697,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "HighZ_defs.svh"
|
|module HighZ(
| input wire logic [7:0] x,
@@ -718,7 +726,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| input wire logic [15:0] x,
@@ -751,19 +758,17 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.vh"
|
|module Foo(
| x,
| y
|);
| `include "dfhdl_defs.vh"
- | `include "Foo_defs.vh"
| input wire [15:0] x;
| output reg [15:0] y;
| always @(x)
| begin
- | if ((x[15:8] == 8'h12) | (x[15:4] == 12'h345)) y = 16'h22??;
+ | if ((x[15:8] == 8'h12) || (x[15:4] == 12'h345)) y = 16'h22??;
| else y = 16'hffff;
| end
|endmodule
@@ -864,7 +869,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| output logic x,
@@ -915,7 +919,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| output logic [9:0] matrix [0:7] [0:7]
@@ -979,13 +982,11 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.vh"
|
|module Foo(
| output reg [639:0] matrix
|);
| `include "dfhdl_defs.vh"
- | `include "Foo_defs.vh"
|
| always
| begin
@@ -1036,7 +1037,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| output logic x,
@@ -1096,12 +1096,11 @@ class PrintVerilogCodeSpec extends StageSpec:
sv2005.csTop,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo#(parameter string param = "Hello\n..\"World\"!");
| `include "dfhdl_defs.svh"
| localparam int param3 = 42;
- | typedef enum {
+ | typedef enum logic [1:0] {
| MyEnum_A = 0,
| MyEnum_B = 1,
| MyEnum_C = 2
@@ -1152,11 +1151,9 @@ class PrintVerilogCodeSpec extends StageSpec:
v95.csTop,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.vh"
|
|module Foo;
| `include "dfhdl_defs.vh"
- | `include "Foo_defs.vh"
| parameter param = "Hello\n..\"World\"!";
| parameter integer param3 = 42;
| `define MyEnum_A 0
@@ -1237,7 +1234,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo#(parameter int PORT_WIDTH = 5)(
| input wire logic clk,
@@ -1277,11 +1273,9 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.vh"
|
|module Foo;
| `include "dfhdl_defs.vh"
- | `include "Foo_defs.vh"
| parameter integer PORT_WIDTH = 8;
| parameter integer PORT_DEPTH = 4;
| parameter [(PORT_WIDTH * PORT_DEPTH) - 1:0] initArg = {8'h01, 8'h02, 8'h03, 8'h04};
@@ -1427,7 +1421,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| input wire logic x,
@@ -1455,7 +1448,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| input wire logic clk,
@@ -1484,7 +1476,6 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.svh"
|
|module Foo(
| input wire logic signed [7:0] x,
@@ -1508,18 +1499,121 @@ class PrintVerilogCodeSpec extends StageSpec:
top,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "Foo_defs.vh"
|
|module Foo(
| x,
| y
|);
| `include "dfhdl_defs.vh"
- | `include "Foo_defs.vh"
| input wire [7:0] x;
| output wire [7:0] y;
| assign y = `ABS(x);
|endmodule""".stripMargin
)
}
+ test("globalDefsFileName override") {
+ given options.PrinterOptions.GlobalDefsFileName = "otherGlobal"
+ enum MyEnum extends Encoded:
+ case A, B
+ class Foo extends RTDesign:
+ val x = MyEnum <> IN
+ val y = MyEnum <> OUT
+ y := x
+ val top = (new Foo).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|typedef enum logic [0:0] {
+ | MyEnum_A = 0,
+ | MyEnum_B = 1
+ |} t_enum_MyEnum;
+ |
+ |`default_nettype none
+ |`timescale 1ns/1ps
+ |`include "otherGlobal.svh"
+ |
+ |module Foo(
+ | input wire t_enum_MyEnum x,
+ | output t_enum_MyEnum y
+ |);
+ | `include "dfhdl_defs.svh"
+ | assign y = x;
+ |endmodule
+ |""".stripMargin
+ )
+ }
+ test("globalDefsFileName override with suffix") {
+ given options.PrinterOptions.GlobalDefsFileName = "otherGlobal.svh"
+ enum MyEnum extends Encoded:
+ case A, B
+ class Foo extends RTDesign:
+ val x = MyEnum <> IN
+ val y = MyEnum <> OUT
+ y := x
+ val top = (new Foo).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|typedef enum logic [0:0] {
+ | MyEnum_A = 0,
+ | MyEnum_B = 1
+ |} t_enum_MyEnum;
+ |
+ |`default_nettype none
+ |`timescale 1ns/1ps
+ |`include "otherGlobal.svh"
+ |
+ |module Foo(
+ | input wire t_enum_MyEnum x,
+ | output t_enum_MyEnum y
+ |);
+ | `include "dfhdl_defs.svh"
+ | assign y = x;
+ |endmodule
+ |""".stripMargin
+ )
+ }
+ test("vector to bits conversion") {
+ class Foo extends EDDesign:
+ val i1 = Bit X 8 <> IN
+ val o1 = Bits(8) <> OUT
+ val i2 = Bits(8) <> IN
+ val o2 = Bit X 8 <> OUT
+ o1 <> i1.bits
+ o2 <> i2.as(Bit X 8)
+ end Foo
+ val top = (new Foo).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|`default_nettype none
+ |`timescale 1ns/1ps
+ |
+ |module Foo(
+ | input wire logic i1 [0:7],
+ | output logic [7:0] o1,
+ | input wire logic [7:0] i2,
+ | output logic o2 [0:7]
+ |);
+ | `include "dfhdl_defs.svh"
+ | assign o1 = {i1[0], i1[1], i1[2], i1[3], i1[4], i1[5], i1[6], i1[7]};
+ | assign o2 = '{i2[7], i2[6], i2[5], i2[4], i2[3], i2[2], i2[1], i2[0]};
+ |endmodule""".stripMargin
+ )
+ }
+ test("signed literal with parametric width") {
+ class Foo(
+ val WIDTH: Int <> CONST = 8
+ ) extends EDDesign:
+ val arg = sd"${WIDTH}'2"
+ end Foo
+ val top = (new Foo).getCompiledCodeString
+ assertNoDiff(
+ top,
+ """|`default_nettype none
+ |`timescale 1ns/1ps
+ |
+ |module Foo#(parameter int WIDTH = 8);
+ | `include "dfhdl_defs.svh"
+ | localparam logic signed [WIDTH - 1:0] arg = WIDTH'(3'sd2);
+ |endmodule""".stripMargin
+ )
+ }
end PrintVerilogCodeSpec
diff --git a/compiler/stages/src/test/scala/StagesSpec/SimplifyRTOpsSpec.scala b/compiler/stages/src/test/scala/StagesSpec/SimplifyRTOpsSpec.scala
index 32107d209..323a601e9 100644
--- a/compiler/stages/src/test/scala/StagesSpec/SimplifyRTOpsSpec.scala
+++ b/compiler/stages/src/test/scala/StagesSpec/SimplifyRTOpsSpec.scala
@@ -62,10 +62,8 @@ class SimplifyRTOpsSpec extends StageSpec(stageCreatesUnrefAnons = true):
x.din := i.rising
x.din := i.falling
waitUntil(i)
- waitUntil(i.falling)
+ val MyWait = waitUntil(i.falling)
waitUntil(i.rising)
- val temp = i.rising
- waitUntil(temp)
x.din := 0
end Foo
val top = (new Foo).simplifyRTOps
@@ -80,13 +78,10 @@ class SimplifyRTOpsSpec extends StageSpec(stageCreatesUnrefAnons = true):
| x.din := i.reg(1, init = 0) && (!i)
| while (!i)
| end while
- | while ((!i.reg(1, init = 0)) || i)
- | end while
+ | val MyWait = while ((!i.reg(1, init = 0)) || i)
+ | end MyWait
| while (i.reg(1, init = 1) || (!i))
| end while
- | val temp = (!i.reg(1, init = 1)) && i
- | while (!temp)
- | end while
| x.din := 0
|end Foo""".stripMargin
)
@@ -101,7 +96,7 @@ class SimplifyRTOpsSpec extends StageSpec(stageCreatesUnrefAnons = true):
x.din := 1
waitWhile(i)
x.din := 0
- waitWhile(j)
+ val MyWait = waitWhile(j)
x.din := 1
end Foo
val top = (new Foo).simplifyRTOps
@@ -116,8 +111,8 @@ class SimplifyRTOpsSpec extends StageSpec(stageCreatesUnrefAnons = true):
| while (i)
| end while
| x.din := 0
- | while (j)
- | end while
+ | val MyWait = while (j)
+ | end MyWait
| x.din := 1
|end Foo""".stripMargin
)
@@ -131,7 +126,7 @@ class SimplifyRTOpsSpec extends StageSpec(stageCreatesUnrefAnons = true):
x.din := 1
50000000.cy.wait
x.din := 0
- waitParam.cy.wait
+ val MyWait = waitParam.cy.wait
1.cy.wait
end Foo
val top = (new Foo).simplifyRTOps
@@ -142,17 +137,154 @@ class SimplifyRTOpsSpec extends StageSpec(stageCreatesUnrefAnons = true):
| val waitParam: UInt[26] <> CONST = d"26'50000000"
| process:
| x.din := 1
- | val waitCnt = UInt(26) <> VAR.REG init d"26'0"
+ | val waitCnt = UInt(26) <> VAR.REG
+ | waitCnt.din := d"26'0"
| while (waitCnt != d"26'49999999")
| waitCnt.din := waitCnt + d"26'1"
| end while
| x.din := 0
- | val waitCnt = UInt(26) <> VAR.REG init d"26'0"
- | while (waitCnt != (waitParam - d"26'1"))
- | waitCnt.din := waitCnt + d"26'1"
- | end while
+ | val MyWait_waitCnt = UInt(26) <> VAR.REG
+ | MyWait_waitCnt.din := d"26'0"
+ | val MyWait = while (MyWait_waitCnt != (waitParam - d"26'1"))
+ | MyWait_waitCnt.din := MyWait_waitCnt + d"26'1"
+ | end MyWait
| 1.cy.wait
|end Foo""".stripMargin
)
}
+ test("RT for loop with until is converted to while loop") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG
+ process:
+ x.din := 1
+ for (i <- 0 until 4)
+ x.din := 0
+ x.din := 1
+ end Foo
+ val top = (new Foo).simplifyRTOps
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG
+ | process:
+ | x.din := 1
+ | val i = Int <> VAR.REG
+ | i.din := 0
+ | while (i < 4)
+ | x.din := 0
+ | i.din := i + 1
+ | end while
+ | x.din := 1
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("RT for loop with to is converted to while loop with <= guard") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG
+ process:
+ val MyFor = for (i <- 0 to 3)
+ x.din := 0
+ end Foo
+ val top = (new Foo).simplifyRTOps
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG
+ | process:
+ | val MyFor_i = Int <> VAR.REG
+ | MyFor_i.din := 0
+ | val MyFor = while (MyFor_i <= 3)
+ | x.din := 0
+ | MyFor_i.din := MyFor_i + 1
+ | end MyFor
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("RT for loop with explicit step is converted to while loop with step increment") {
+ class Foo extends RTDesign:
+ val x = Bit <> OUT.REG
+ process:
+ for (i <- 0 until 8 by 2)
+ x.din := 0
+ end Foo
+ val top = (new Foo).simplifyRTOps
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bit <> OUT.REG
+ | process:
+ | val i = Int <> VAR.REG
+ | i.din := 0
+ | while (i < 8)
+ | x.din := 0
+ | i.din := i + 2
+ | end while
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("RT combinational for loop is untouched") {
+ class Foo extends RTDesign:
+ val x = Bits(4) <> OUT.REG
+ process:
+ x.din := all(0)
+ for (i <- 0 until 4)
+ COMB_LOOP
+ x(i).din := 1
+ end Foo
+ val top = (new Foo).simplifyRTOps
+ assertCodeString(
+ top,
+ """|class Foo extends RTDesign:
+ | val x = Bits(4) <> OUT.REG
+ | process:
+ | x.din := h"0"
+ | for (i <- 0 until 4)
+ | COMB_LOOP
+ | x(i).din := 1
+ | end for
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("RT for loop outside a process is untouched") {
+ class Foo(val WIDTH: Int <> CONST = 4) extends RTDesign:
+ val r = Bits(WIDTH) <> OUT.REG init all(0)
+ for (i <- 0 until WIDTH)
+ r(i).din := 1
+ end Foo
+ val top = (new Foo).simplifyRTOps
+ assertCodeString(
+ top,
+ """|class Foo(val WIDTH: Int <> CONST = 4) extends RTDesign:
+ | val r = Bits(WIDTH) <> OUT.REG init b"0".repeat(WIDTH)
+ | for (i <- 0 until WIDTH)
+ | r(i).din := 1
+ | end for
+ |end Foo""".stripMargin
+ )
+ }
+
+ test("ED domain for loop is untouched") {
+ class Foo extends EDDesign:
+ val x = Bit <> OUT
+ process:
+ for (i <- 0 until 4)
+ x :== 0
+ end Foo
+ val top = (new Foo).simplifyRTOps
+ assertCodeString(
+ top,
+ """|class Foo extends EDDesign:
+ | val x = Bit <> OUT
+ | process:
+ | for (i <- 0 until 4)
+ | x :== 0
+ | end for
+ |end Foo""".stripMargin
+ )
+ }
+
end SimplifyRTOpsSpec
diff --git a/core/src/main/scala/dfhdl/compiler/patching/MetaDesign.scala b/core/src/main/scala/dfhdl/compiler/patching/MetaDesign.scala
index 94ea24d27..d17e5a91d 100644
--- a/core/src/main/scala/dfhdl/compiler/patching/MetaDesign.scala
+++ b/core/src/main/scala/dfhdl/compiler/patching/MetaDesign.scala
@@ -6,6 +6,32 @@ import scala.annotation.unchecked.uncheckedVariance
import dfhdl.compiler.ir.DFDesignBlock
type MetaDesignAny = MetaDesign[DomainType]
+
+/** A base class for synthesising new IR members inside a compiler stage and injecting them into the
+ * DB at a precise position relative to an anchor member.
+ *
+ * Extend this class anonymously inside a stage's `transform` method to write ordinary DFHDL DSL
+ * code (ports, vars, assignments, etc.). The members created in the body are extracted and
+ * inserted into the DB when `dsn.patch` is applied; the MetaDesign block itself is discarded.
+ *
+ * ===Constructing raw IR members inside the body===
+ *
+ * To build an IR member directly (e.g. `ir.Goto`) rather than through the DSL, add
+ * `import dfhdl.core.*` at the top of the anonymous body. This brings `refTW` and `addMember` into
+ * scope. Use `dfc.ownerOrEmptyRef` to obtain the owner ref — do not use `dfc.owner.ref` as that
+ * extension method may conflict with other imports:
+ * {{{
+ * val dsn = new MetaDesign(anchor, Patch.Add.Config.Before):
+ * import dfhdl.core.*
+ * ir.Goto(existingStep.refTW[ir.Goto], dfc.ownerOrEmptyRef, dfc.getMeta, dfc.tags).addMember
+ * }}}
+ *
+ * ===Ownership===
+ *
+ * For `Before` / `After` / `ReplaceWith*` configs, newly created members are placed as siblings of
+ * the anchor (same owner). For `InsideFirst` / `InsideLast`, members are placed as direct children
+ * of the anchor (which must be a `DFOwner`).
+ */
abstract class MetaDesign[+D <: DomainType](
positionMember: ir.DFMember,
addCfg: AddCfg,
@@ -32,7 +58,9 @@ abstract class MetaDesign[+D <: DomainType](
final override private[dfhdl] def initOwner: Design.Block =
dfc.mutableDB.addMember(injectedOwner)
injectedOwner.getThisOrOwnerDesign.asFE
- final override protected def __dfc: DFC = DFC.emptyNoEO.copy(refGen = refGen)
+ // default context position is set according to the positionMember
+ final override protected def __dfc: DFC =
+ DFC.emptyNoEO.copy(refGen = refGen, position = positionMember.meta.position)
injectedOwner match
case design: ir.DFDesignBlock => // do nothing
@@ -47,10 +75,7 @@ abstract class MetaDesign[+D <: DomainType](
final lazy val __domainType: ir.DomainType = ir.DomainType.DF
final def plantMember[T <: ir.DFMember](member: T): T =
- if (globalInjection)
- dfc.mutableDB.plantMember(ir.DFMember.Empty, member)
- else
- dfc.mutableDB.plantMember(dfc.owner.asIR, member)
+ dfc.mutableDB.plantMember(dfc.owner.asIR, member)
final def plantMembers(baseOwner: ir.DFOwner, members: Iterable[ir.DFMember]): Unit =
members.foreach { m =>
val owner = m.getOwner
@@ -62,7 +87,10 @@ abstract class MetaDesign[+D <: DomainType](
else owner
dfc.mutableDB.plantMember(updatedOwner, m, _ => cond)
}
- final def plantClonedMembers(baseOwner: ir.DFOwner, members: List[ir.DFMember]): Unit =
+ final def plantClonedMembers(
+ baseOwner: ir.DFOwner,
+ members: List[ir.DFMember]
+ ): Map[ir.DFMember, ir.DFMember] =
val clonedMemberMap = members.map { m => m -> m.copyWithNewRefs }.toMap
members.foreach { m =>
val cloned = clonedMemberMap(m)
@@ -74,6 +102,8 @@ abstract class MetaDesign[+D <: DomainType](
dfc.mutableDB.newRefFor(clonedRef, clonedMemberMap.getOrElse(refMember, refMember))
}
}
+ clonedMemberMap
+ end plantClonedMembers
final def applyBlock(owner: ir.DFOwner)(block: => Unit): Unit =
dfc.mutableDB.OwnershipContext.enter(owner)
block
diff --git a/core/src/main/scala/dfhdl/compiler/patching/Patch.scala b/core/src/main/scala/dfhdl/compiler/patching/Patch.scala
index 272cb4917..48deb1c06 100644
--- a/core/src/main/scala/dfhdl/compiler/patching/Patch.scala
+++ b/core/src/main/scala/dfhdl/compiler/patching/Patch.scala
@@ -41,7 +41,7 @@ object Patch:
def apply(refs: Set[DFRefAny])(using MemberGetSet): Set[DFRefAny] =
refs -- rf(refs)
// All references are replaced
- object All extends RefFilter:
+ case object All extends RefFilter:
def apply(refs: Set[DFRefAny])(using MemberGetSet): Set[DFRefAny] = refs
// Only references from outside the given owner are replaced
final case class Outside(block: DFOwner) extends RefFilter:
@@ -51,6 +51,10 @@ object Patch:
final case class Inside(block: DFOwner) extends RefFilter:
def apply(refs: Set[DFRefAny])(using MemberGetSet): Set[DFRefAny] =
refs.collect { case r: DFRef.TwoWayAny if r.originMember.isInsideOwner(block) => r }
+ // Only references to the given members are replaced
+ final case class OfMembers(members: Set[DFMember]) extends RefFilter:
+ def apply(refs: Set[DFRefAny])(using MemberGetSet): Set[DFRefAny] =
+ refs.collect { case r: DFRef.TwoWayAny if members.contains(r.originMember) => r }
end RefFilter
end Replace
final case class Add private[patching] (db: DB, config: Add.Config) extends Patch:
@@ -101,8 +105,36 @@ object Patch:
case object Via extends Config
end Config
end Add
- // movedMembers: members to move
- // origOwner: the original owner of the top members
+
+ /** Moves `movedMembers` to a new position in the flat member list relative to the anchor member.
+ *
+ * `origOwner` is the original direct owner of the top-level moved members. During ownership
+ * resolution, only members in `movedMembers` whose current owner equals `origOwner` have their
+ * `ownerRef` updated to the new owner (determined by the anchor and config). Members owned by
+ * nested sub-blocks are not re-owned — their `ownerRef` is assumed to already point to the
+ * correct intermediate owner.
+ *
+ * '''Descendants are NOT moved automatically.''' Only the explicitly listed `movedMembers` are
+ * repositioned in the flat list. Moving a `DFOwner` (e.g. a `StepBlock`) without its children
+ * breaks the pre-order DFS ownership invariant. Always include all descendants:
+ * {{{
+ * val all = block :: block.members(MemberView.Flattened)
+ * anchor -> Patch.Move(all, block.getOwner, Patch.Move.Config.After)
+ * }}}
+ *
+ * '''`DFOwner` anchor + `After`/`InsideLast` redirect.''' When the anchor is a `DFOwner`,
+ * physical placement is redirected to `anchor.getVeryLastMember` (deepest recursive last
+ * descendant). Ownership resolution still uses the original anchor, so `newOwner =
+ * anchor.getOwnerBlock`.
+ *
+ * '''Concatenation.''' Multiple `Move` patches targeting the same anchor and config are merged
+ * in patchList order into a single Move before being applied to the member list.
+ *
+ * '''Conflict detection.''' This patch internally generates `Patch.Remove` for every member in
+ * `movedMembers`. If any of those members also appear in a separate patch in the same patchList
+ * (e.g. as the anchor of another `Move.Before`), an `IllegalArgumentException` is thrown.
+ * Resolve by splitting conflicting patches into sequential `db.patch()` calls.
+ */
final case class Move(movedMembers: List[DFMember], origOwner: DFOwner, config: Move.Config)
extends Patch:
override def toString(): String =
@@ -119,14 +151,21 @@ object Patch:
sealed trait Config extends Product with Serializable derives CanEqual:
def ==(addConfig: Add.Config): Boolean = addConfig == this
object Config:
- // moves members before the patched member
+ // Moves members before the anchor member. The anchor must not be a DFOwner when
+ // members to be moved using Before are also referenced by other patches (e.g., as movedMembers
+ // in another Move), as the internal Remove generated here would conflict.
case object Before extends Config
- // moves members after the patched member
+ // Moves members after the anchor member.
+ // When the anchor is a DFOwner, placement is redirected to anchor.getVeryLastMember.
+ // Ownership update: newOwner = anchor.getOwnerBlock (NOT anchor itself).
case object After extends Config
- // moves members inside the given block, at the beginning
+ // Moves members inside the given block, at the beginning (after the block header).
+ // The anchor must be a DFOwner; members become direct children of the anchor.
case object InsideFirst extends Config
- // moves members inside the given block, at the end
+ // Moves members inside the given block, at the end.
+ // The anchor must be a DFOwner; redirects to anchor.getVeryLastMember for placement.
case object InsideLast extends Config
+ end Config
end Move
final case class ChangeRef(
@@ -172,6 +211,16 @@ extension (db: DB)
.foldLeft(ReplacementContext.fromRefTable(refTable)) {
case (rc, (origMember, Patch.Replace(repMember, config, refFilter)))
if (origMember != repMember) =>
+ // TODO: consider using this code in the future
+ // Include refs from any Add for this member so refs shared with added members (e.g. when
+ // the added block reuses the same member) are not purged and lost from the ref table.
+ // val addRefsForSameMember =
+ // patchList.collect {
+ // case (m, Patch.Add(db, _)) if m == origMember => db.members.flatMap(_.getRefs)
+ // }.flatten.toList
+ // val keepRefs = (repMember.getRefs ++ addRefsForSameMember).distinct
+ // val ret =
+ // rc.replaceMember(origMember, repMember, config, refFilter, keepRefs)
val ret =
rc.replaceMember(origMember, repMember, config, refFilter, repMember.getRefs)
// patchDebug {
@@ -182,16 +231,21 @@ extension (db: DB)
case (rc, (origMember, Patch.Add(db, config))) =>
// if the original member is a global value, the all references pointing to the top design in the patch
// db should point to an empty member for global placement
- val fixedGlobalRefTable = origMember match
- case dfVal: DFVal.CanBeGlobal if dfVal.isGlobal =>
+ val globalPlacement =
+ (origMember, config) match
+ case (dfVal: DFVal.CanBeGlobal, _) if dfVal.isGlobal => true
+ case (design: DFDesignBlock, Patch.Add.Config.Before) if design.isTop => true
+ case _ => false
+ val fixedGlobalRefTable =
+ if (globalPlacement)
db.refTable.map { case (ref, member) =>
if (member == db.top) (ref, DFMember.Empty)
else (ref, member)
}
- case _ => db.refTable
+ else db.refTable
// updating the patched DB reference table members with the newest members kept by the replacement context
val updatedPatchRefTable = rc.getUpdatedRefTable(fixedGlobalRefTable)
- val keepRefList = db.members.flatMap(_.getRefs)
+ lazy val keepRefList = db.members.flatMap(_.getRefs)
val repRT = config match
case Patch.Add.Config.ReplaceWithMemberN(n, repConfig, refFilter) =>
val repMember = db.members(n + 1) // At index 0 we have the Top. We don't want that.
@@ -209,23 +263,19 @@ extension (db: DB)
Patch.Replace.RefFilter.All, keepRefList
)
case _ => rc
- // patchDebug {
- // println("repRT.refTable:")
- // println(repRT.refTable.mkString("\n"))
- // }
- // patchDebug {
- // println("dbPatched.refTable:")
- // println(dbPatched.refTable.mkString("\n"))
- // }
- // patchDebug {
- // println("updatedPatchRefTable:")
- // println(updatedPatchRefTable.mkString("\n"))
- // }
+ // patchDebug {
+ // println("repRT.refTable:")
+ // println(repRT.refTable.mkString("\n"))
+ // }
+ // patchDebug {
+ // println("updatedPatchRefTable:")
+ // println(updatedPatchRefTable.mkString("\n"))
+ // }
val ret = repRT.copy(refTable = repRT.refTable ++ updatedPatchRefTable)
- // patchDebug {
- // println("rc.refTable:")
- // println(ret.refTable.mkString("\n"))
- // }
+ // patchDebug {
+ // println("rc.refTable:")
+ // println(ret.refTable.mkString("\n"))
+ // }
ret
// skip over empty move
case (rc, (origMember, Patch.Move(Nil, _, config))) => rc
@@ -338,6 +388,32 @@ extension (db: DB)
Patch.Add(db2, Patch.Add.Config.After)
) =>
tbl + (m -> Patch.Add(db1 concat db2, config1))
+ // concatenating additions with Before and After configurations, respectively
+ case (
+ Patch.Add(db1, Patch.Add.Config.Before),
+ Patch.Add(db2, Patch.Add.Config.After)
+ ) =>
+ val combinedDB = (db1 concat db2).copy(members =
+ db1.members ++ (m :: db2.members.drop(1))
+ )
+ val config = Patch.Add.Config.ReplaceWithMemberN(
+ db1.members.length - 1,
+ Patch.Replace.Config.FullReplacement
+ )
+ tbl + (m -> Patch.Add(combinedDB, config))
+ // concatenating additions with After and Before configurations, respectively
+ case (
+ Patch.Add(db1, Patch.Add.Config.After),
+ Patch.Add(db2, Patch.Add.Config.Before)
+ ) =>
+ val combinedDB = (db1 concat db2).copy(members =
+ (db1.members.head :: db2.members.drop(1)) ++ (m :: db1.members.drop(1))
+ )
+ val config = Patch.Add.Config.ReplaceWithMemberN(
+ db2.members.length - 1,
+ Patch.Replace.Config.FullReplacement
+ )
+ tbl + (m -> Patch.Add(combinedDB, config))
// concatenating moves with the same configuration
// (the patch table does not care about original owner, so we ignore it.
// only the patchList that has all the move patches uses the original owners
@@ -360,16 +436,20 @@ extension (db: DB)
tbl + (m -> Patch.Add(add.db, Patch.Add.Config.ReplaceWithFirst()))
// add followed by a replacement is allowed via a tandem patch execution
case (add: Patch.Add, replace: Patch.Replace) if add.config == Patch.Add.Config.After =>
- tbl + (m -> Patch.Add(
- add.db.copy(add.db.members.head :: replace.updatedMember :: add.db.members.drop(1)),
- Patch.Add.Config.ReplaceWithFirst()
- ))
+ tbl +
+ (m -> Patch.Add(
+ add.db.copy(add.db.members.head :: replace.updatedMember ::
+ add.db.members.drop(1)),
+ Patch.Add.Config.ReplaceWithFirst()
+ ))
// replacement followed by an add via a tandem patch execution
case (replace: Patch.Replace, add: Patch.Add) if add.config == Patch.Add.Config.After =>
- tbl + (m -> Patch.Add(
- add.db.copy(add.db.members.head :: replace.updatedMember :: add.db.members.drop(1)),
- Patch.Add.Config.ReplaceWithFirst()
- ))
+ tbl +
+ (m -> Patch.Add(
+ add.db.copy(add.db.members.head :: replace.updatedMember ::
+ add.db.members.drop(1)),
+ Patch.Add.Config.ReplaceWithFirst()
+ ))
// allow the same member to be removed more than once by getting rid of the redundant removals
case (Patch.Remove(isMovedL), Patch.Remove(isMovedR)) =>
tbl + (m -> Patch.Remove(isMovedL || isMovedR))
diff --git a/core/src/main/scala/dfhdl/compiler/patching/ReplacementContext.scala b/core/src/main/scala/dfhdl/compiler/patching/ReplacementContext.scala
index 0e8c902e4..8c3d6a269 100644
--- a/core/src/main/scala/dfhdl/compiler/patching/ReplacementContext.scala
+++ b/core/src/main/scala/dfhdl/compiler/patching/ReplacementContext.scala
@@ -99,11 +99,14 @@ private final case class ReplacementContext(
def removeMember(origMember: DFMember): ReplacementContext =
// Total references to be removed are:
- // * refs from memberTable - references from other members to this member
+ // * refs from memberTable that still point to origMember in refTable (references from other
+ // members to this member; may have been reassigned by a prior Replace(ChangeRefOnly))
// * refs from origMember - references from this member to other members
// Together these cover both directions of two-way references
+ val refsToOrigThatStillPointHere =
+ memberTable.getOrElse(origMember, Set()).filter(r => refTable.get(r).contains(origMember))
val purgedRefs =
- memberTable.getOrElse(origMember, Set()) ++ origMember.getRefs + origMember.ownerRef
+ refsToOrigThatStillPointHere ++ origMember.getRefs + origMember.ownerRef
val (updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs) =
getUpdatedTypeRefCount(purgedRefs)
val updatedMemberTable = purgedRefsWithoutRepeatedTypeRefs.foldLeft(memberTable) {
diff --git a/core/src/main/scala/dfhdl/core/DFC.scala b/core/src/main/scala/dfhdl/core/DFC.scala
index b2faa467b..baf8f12db 100644
--- a/core/src/main/scala/dfhdl/core/DFC.scala
+++ b/core/src/main/scala/dfhdl/core/DFC.scala
@@ -65,6 +65,10 @@ final case class DFC(
def lateConstruction: Boolean = mutableDB.OwnershipContext.lateConstruction
def ownerOption: Option[DFOwnerAny] =
mutableDB.OwnershipContext.ownerOption.map(_.asFE)
+ // Returns the IR ref for the current owner, or a ref to DFMember.Empty when there is no
+ // owner in the context. Prefer this over `dfc.owner.ref` when constructing raw IR members
+ // (e.g. ir.Goto) inside a MetaDesign body: the `ref` extension method requires
+ // `import dfhdl.core.*` in scope, which can conflict with other `dfhdl.core` imports.
def ownerOrEmptyRef: ir.DFOwner.Ref =
ownerOption.map(_.asIR.ref(using this)).getOrElse(ir.DFMember.Empty.ref(using this))
def setName(name: String): this.type =
diff --git a/core/src/main/scala/dfhdl/core/DFDecimal.scala b/core/src/main/scala/dfhdl/core/DFDecimal.scala
index 9d72011ca..d2a3e33f0 100644
--- a/core/src/main/scala/dfhdl/core/DFDecimal.scala
+++ b/core/src/main/scala/dfhdl/core/DFDecimal.scala
@@ -978,16 +978,38 @@ object DFXInt:
if (dfType.signed != lhsSigned && !lhs.dfType.asIR.isDFInt32)
lhs.asValOf[DFUInt[Int]].signed.asValOf[DFSInt[Int]]
else lhs.asValOf[DFSInt[Int]]
- val nativeTypeChanged = dfType.nativeType != lhs.dfType.nativeType
+ // Auto-promote anonymous +/-/* to carry when target is wide enough
+ import IntParam.+
+ val funcWidth = lhsSignFix.widthIntParam
+ val lhsCarryPromo: DFValOf[DFSInt[Int]] =
+ lhsSignFix.asIR match
+ case func @ ir.DFVal.Func(
+ dfType = dt: ir.DFDecimal,
+ op = op @ (FuncOp.+ | FuncOp.- | FuncOp.*)
+ )
+ if func.isAnonymous && !dt.isDFInt32 && dfType.widthInt > func.width =>
+ val cw: IntParam[Int] = func.op.runtimeChecked match
+ case FuncOp.+ | FuncOp.- => funcWidth + 1
+ case FuncOp.* => funcWidth + funcWidth
+ val newDT = dt.copy(widthParamRef = cw.ref)
+ dfc.mutableDB
+ .setMember(func, _.updateDFType(newDT))
+ .asValOf[DFSInt[Int]]
+ case _ => lhsSignFix
+ val nativeTypeChanged = dfType.nativeType != lhsCarryPromo.dfType.nativeType
if (nativeTypeChanged)
dfType.asIR.nativeType match
case Int32 =>
- lhsSignFix.toInt.asIR
+ lhsCarryPromo.toInt.asIR
case BitAccurate =>
- DFVal.Alias.AsIs(dfType, lhsSignFix).asIR
- else if (!dfType.asIR.widthParamRef.isSimilarTo(lhsSignFix.dfType.asIR.widthParamRef))
- lhsSignFix.resize(dfType.widthIntParam).asIR
- else lhsSignFix.asIR
+ DFVal.Alias.AsIs(dfType, lhsCarryPromo).asIR
+ else if (
+ !dfType.asIR.widthParamRef.isSimilarTo(
+ lhsCarryPromo.dfType.asIR.widthParamRef
+ )
+ )
+ lhsCarryPromo.resize(dfType.widthIntParam).asIR
+ else lhsCarryPromo.asIR
end if
end if
end dfValIR
@@ -1045,7 +1067,8 @@ object DFXInt:
end arithOp
type ArithOp =
- FuncOp.+.type | FuncOp.-.type | FuncOp.*.type | FuncOp./.type | FuncOp.%.type | FuncOp.max.type | FuncOp.min.type
+ FuncOp.+.type | FuncOp.-.type | FuncOp.*.type | FuncOp./.type | FuncOp.%.type |
+ FuncOp.max.type | FuncOp.min.type
given evOpArithIntDFInt32[
Op <: ArithOp,
L <: Int,
diff --git a/core/src/main/scala/dfhdl/core/DFFor.scala b/core/src/main/scala/dfhdl/core/DFFor.scala
index 7effa7c86..7e05834d3 100644
--- a/core/src/main/scala/dfhdl/core/DFFor.scala
+++ b/core/src/main/scala/dfhdl/core/DFFor.scala
@@ -26,7 +26,7 @@ object DFFor:
)(using DFC): Unit =
val iter = DFVal.Dcl.iterator(using dfc.setMeta(iterMeta))
dfc.mutableDB.DesignContext.addLoopIter(iterMeta, iter)
- val block = Block(iter, range)(using dfc.setMetaAnon(forPos))
+ val block = Block(iter, range)(using dfc.setMeta(position = forPos))
dfc.enterOwner(block)
guards.foreach { guard =>
val guardVal = guard()
diff --git a/core/src/main/scala/dfhdl/core/DFVal.scala b/core/src/main/scala/dfhdl/core/DFVal.scala
index a2c30e686..5984877c7 100644
--- a/core/src/main/scala/dfhdl/core/DFVal.scala
+++ b/core/src/main/scala/dfhdl/core/DFVal.scala
@@ -642,20 +642,21 @@ object DFVal extends DFValLP:
end Const
object DesignParam:
+ // Note: in meta-programming, the user needs to manually set the Design's paramMap.
def apply[T <: DFTypeAny](
- dfVal: DFValOf[T],
- default: Option[DFValOf[T]] = None
+ appliedVal: DFValOf[T],
+ defaultVal: Option[DFValOf[T]] = None
)(using DFC): DFConstOf[T] =
val alias: ir.DFVal.DesignParam =
ir.DFVal.DesignParam(
- dfVal.asIR.dfType.dropUnreachableRefs,
- dfVal.asIR.refTW[ir.DFVal.DesignParam](knownReachable = true),
- default.map(_.asIR.refTW[ir.DFVal.DesignParam])
+ appliedVal.asIR.dfType.dropUnreachableRefs,
+ defaultVal.map(_.asIR.refTW[ir.DFVal.DesignParam])
.getOrElse(ir.DFMember.Empty.refTW[ir.DFVal.DesignParam]),
dfc.ownerOrEmptyRef,
dfc.getMeta,
dfc.tags
)
+ if (!dfc.inMetaProgramming) alias.setCachedAppliedVal(appliedVal.asIR)
alias.addMember.asConstOf[T]
end apply
end DesignParam
@@ -774,8 +775,13 @@ object DFVal extends DFValLP:
if (prevLHSArg.isAnonymous) Some(prevLHSArg.setMeta(_ => dfc.getMeta))
else Some(prevLHSArg)
else
- dfc.mutableDB.setMember(prevRHSArg, _.copy(data = Some(newRHSData)))
- Some(dfc.mutableDB.setMember(prevFunc, _.copy(meta = dfc.getMeta)))
+ // Clone prevFunc to avoid destructively modifying shared IR nodes
+ val clonedFunc = prevFunc.cloneAnonValueAndDepsHere
+ .asInstanceOf[ir.DFVal.Func]
+ val clonedRHSArg = clonedFunc.args.last.get
+ .asInstanceOf[ir.DFVal.Const]
+ dfc.mutableDB.setMember(clonedRHSArg, _.copy(data = Some(newRHSData)))
+ Some(dfc.mutableDB.setMember(clonedFunc, _.copy(meta = dfc.getMeta)))
case _ => None
end match
case _ => None
@@ -830,9 +836,12 @@ object DFVal extends DFValLP:
)
).asVal[AT, M]
// remove redundant intermediate casting when the final result needs to be `.bits` anyways
- case asIs: ir.DFVal.Alias.AsIs
+ // as long as the alias is anonymous and has the same width as the related value,
+ // to avoid modifying the semantics of named values that can be referenced in multiple places.
+ case asIs @ ir.DFVal.Alias.AsIs(relValRef = ir.DFRef(relValIR))
if aliasType.asIR.isInstanceOf[ir.DFBits] && asIs.isAnonymous &&
- dfc.isAnonymous && !forceNewAlias && asIs.tags.isEmpty =>
+ dfc.isAnonymous && !forceNewAlias && asIs.tags.isEmpty &&
+ relValIR.width == asIs.width =>
asIs.relValRef.get.asVal[AT, M]
// remove redundant intermediate casting converting from BoolOrBit to Bits/UInt/SInt + resize
case asIs @ ir.DFVal.Alias.AsIs(
@@ -1869,8 +1878,8 @@ extension (dfVal: ir.DFVal)
else
dfVal match
// design parameter, so recurse on the referenced value
- case ir.DFVal.DesignParam(dfValRef = ir.DFRef(of)) =>
- of.cloneUnreachable
+ case dp: ir.DFVal.DesignParam =>
+ dp.appliedOrDefaultVal.cloneUnreachable
// named constant, so clone under a new name within relation to the current design
case _ =>
val newMeta =
diff --git a/core/src/main/scala/dfhdl/core/DFWhile.scala b/core/src/main/scala/dfhdl/core/DFWhile.scala
index e14009bf2..29c251dfd 100644
--- a/core/src/main/scala/dfhdl/core/DFWhile.scala
+++ b/core/src/main/scala/dfhdl/core/DFWhile.scala
@@ -2,6 +2,7 @@ package dfhdl.core
import dfhdl.compiler.ir
import dfhdl.internals.*
import scala.annotation.implicitNotFound
+import scala.reflect.ClassTag
object DFWhile:
object Block:
@@ -21,27 +22,40 @@ object DFWhile:
dfc.exitOwner()
end DFWhile
-//to be used inside an RT loop to indicate that the loop is combinational
-def COMB_LOOP(using
- dfc: DFC,
- @implicitNotFound(
- "`COMB_LOOP` is only allowed under register-transfer (RT) domains."
- ) rt: DomainType.RT
-): Unit =
- import dfc.getSet
- var ownerIR = dfc.owner.asIR
- var stop = false
- var lineEnd = -1
- while (!stop)
- ownerIR match
- case cb: ir.DFConditional.Block => ownerIR = cb.getOwner
- case lb: ir.DFLoop.Block =>
- if (lineEnd == -1)
- lineEnd = lb.meta.position.lineEnd
- else if (lineEnd != lb.meta.position.lineEnd)
- stop = true
- if (!stop)
- ownerIR.setTags(_.tag(ir.CombinationalTag))
- ownerIR = lb.getOwner
- case _ => stop = true
-end COMB_LOOP
+protected[dfhdl] object LoopOps:
+ private def loopTag[CT <: ir.DFTag: ClassTag](tag: CT)(using DFC): Unit =
+ import dfc.getSet
+ var ownerIR = dfc.owner.asIR
+ var stop = false
+ var lineEnd = -1
+ while (!stop)
+ ownerIR match
+ case cb: ir.DFConditional.Block => ownerIR = cb.getOwner
+ case lb: ir.DFLoop.Block =>
+ if (lineEnd == -1)
+ lineEnd = lb.meta.position.lineEnd
+ else if (lineEnd != lb.meta.position.lineEnd)
+ stop = true
+ if (!stop)
+ ownerIR.setTags(_.tag(tag))
+ ownerIR = lb.getOwner
+ case _ => stop = true
+ end loopTag
+
+ // to be used inside an RT loop to indicate that the loop is combinational
+ def COMB_LOOP(using
+ dfc: DFC,
+ @implicitNotFound(
+ "`COMB_LOOP` is only allowed under register-transfer (RT) domains."
+ ) rt: DomainType.RT
+ ): Unit = loopTag(ir.CombinationalTag)
+
+ // to be used inside an RT loop to indicate that the loop should fall through to the
+ // next step if the guard is false without consuming any cycles
+ def FALL_THROUGH(using
+ dfc: DFC,
+ @implicitNotFound(
+ "`FALL_THROUGH` is only allowed under register-transfer (RT) domains."
+ ) rt: DomainType.RT
+ ): Unit = loopTag(ir.FallThroughTag)
+end LoopOps
diff --git a/core/src/main/scala/dfhdl/core/Design.scala b/core/src/main/scala/dfhdl/core/Design.scala
index 2127c2bff..1b167dda4 100644
--- a/core/src/main/scala/dfhdl/core/Design.scala
+++ b/core/src/main/scala/dfhdl/core/Design.scala
@@ -54,6 +54,7 @@ trait Design extends Container, HasClsMetaArgs:
final override def onCreateStartLate: Unit =
hasStartedLate = true
import dfc.getSet
+ Design.Block.updateWithParams(containedOwner.asIR)
if (dfc.owner.asIR.getThisOrOwnerDesign.isDeviceTop)
handleResourceConstraints()
dfc.mutableDB.ResourceOwnershipContext.emptyTopResourceOwners()
@@ -152,12 +153,28 @@ object Design:
type Block = DFOwner[ir.DFDesignBlock]
object Block:
def apply(domain: ir.DomainType, dclMeta: ir.Meta, instMode: InstMode)(using DFC): Block =
- ir.DFDesignBlock(
- domain, dclMeta, instMode, dfc.ownerOrEmptyRef, dfc.getMeta, dfc.tags
+ val paramMap = ListMap.from(
+ dfc.mutableDB.DesignContext.getDesignParamValueMap.view.mapValues(
+ _.asIR.refTW[ir.DFDesignBlock]
+ )
)
- .addMember
- .asFE
+ ir.DFDesignBlock(
+ domain, dclMeta, instMode, paramMap, dfc.ownerOrEmptyRef, dfc.getMeta, dfc.tags
+ ).addMember.asFE
end apply
+ protected[core] def updateWithParams(designBlock: ir.DFDesignBlock)(using dfc: DFC): Unit =
+ import dfc.getSet
+ val paramMap =
+ ListMap.from(
+ dfc.mutableDB.DesignContext.current.getImmutableMemberList.view.collect {
+ case dp: ir.DFVal.DesignParam =>
+ val dfVal = dp.appliedValOpt.get
+ // invalidating the param cache value after design elaboration
+ dp.clearCachedAppliedVal()
+ dp.getName -> dfVal.refTW[ir.DFDesignBlock](knownReachable = true)
+ }.toMap
+ )
+ getSet.replace(designBlock)(designBlock.copy(paramMap = paramMap))
end Block
extension [D <: Design](dsn: D)
def getDB: ir.DB = dsn.dfc.mutableDB.immutable
diff --git a/core/src/main/scala/dfhdl/core/MutableDB.scala b/core/src/main/scala/dfhdl/core/MutableDB.scala
index 4bc6dc3c4..5e95d8bbf 100644
--- a/core/src/main/scala/dfhdl/core/MutableDB.scala
+++ b/core/src/main/scala/dfhdl/core/MutableDB.scala
@@ -28,6 +28,7 @@ import dfhdl.compiler.analysis.filterPublicMembers
import scala.reflect.{ClassTag, classTag}
import collection.mutable
+import collection.immutable.ListMap
private case class MemberEntry(
irValue: DFMember,
@@ -168,6 +169,17 @@ final class MutableDB():
var stack = List.empty[DesignContext]
val designMembers = mutable.Map.empty[DFDesignBlock, List[DFMember]]
val uniqueDesigns = mutable.Map.empty[String, List[List[DFDesignBlock]]]
+
+ // for design parameters we save them via the plugin before the design is elaborated, and then
+ // construct the design block with the parameters referenced in its paramMap.
+ private var designParamValueMap = ListMap.empty[String, DFValAny]
+ def prepareDesignParamValues(paramNames: List[String], paramValues: List[DFValAny]): Unit =
+ designParamValueMap = ListMap.from(paramNames.lazyZip(paramValues))
+ def getDesignParamValueMap: ListMap[String, DFValAny] =
+ val ret = designParamValueMap
+ designParamValueMap = ListMap.empty
+ ret
+
def startDesign(design: DFDesignBlock): Unit =
stack = current :: stack
current = new DesignContext
@@ -178,10 +190,7 @@ final class MutableDB():
var isDuplicate = false
def sameDesignAs(groupDesign: DFDesignBlock): Boolean =
if (design.dclMeta == groupDesign.dclMeta)
- val groupMembers = designMembers(groupDesign)
- if (currentMembers.length == groupMembers.length)
- (currentMembers lazyZip groupMembers).forall { case (l, r) => l =~ r }
- else false
+ currentMembers =~ designMembers(groupDesign)
else false
uniqueDesigns.get(designType) match
// this design type already exists and has at least one group
@@ -201,21 +210,25 @@ final class MutableDB():
// first time encountering this design type, so add the first group
case None => uniqueDesigns += designType -> List(List(design))
end match
- // generally, if this design is a duplicate we want to add only the by-name members and their
- // owner references. however, if current design context is known to be a duplicate (as a result
- // of a `hw.pure` annotation), then we can skip this extra step since the design context is
- // already minimized to the named members.
+ // If this design is a duplicate, we retain only the public members (ports, design
+ // parameters, domain blocks, and their dependencies) during elaboration, because
+ // user code may still reference them (e.g., connecting to a port requires the Dcl
+ // before a PortByNameSelect is created). These public members are later removed
+ // during immutable DB creation (see `immutable`), where ports are resolved
+ // on-demand via DuplicationRef in `DB.dupPortsByName`.
+ // If the current design context is already known to be a duplicate (as a result
+ // of a `hw.pure` annotation), then we can skip this extra step since the design
+ // context is already minimized to the named members.
if (isDuplicate && !current.isDuplicate)
- // public members are ports, design design parameters, and
- // design domains. for design parameters we also get dependencies.
- // all these members are interacted with outside the design,
- // so they are kept as duplicates in the design instances
val publicMembers = currentMembers.filterPublicMembers
designMembers += design -> publicMembers
- val transferredRefs = publicMembers.view.flatMap(m =>
- (m.ownerRef -> currentRefTable(m.ownerRef)) ::
- m.getRefs.map(r => r -> currentRefTable(r))
- )
+ val transferredRefs =
+ // getting the design references to parameters
+ design.getRefs.map(r => r -> currentRefTable(r)) ++
+ publicMembers.view.flatMap(m =>
+ (m.ownerRef -> currentRefTable(m.ownerRef)) ::
+ m.getRefs.map(r => r -> currentRefTable(r))
+ )
stack.head.refTable ++= transferredRefs
else
designMembers += design -> currentMembers
@@ -373,8 +386,9 @@ final class MutableDB():
else resource.allSigConstraints
}
// merge the existing constraints with the new constraints
- val updatedSigConstraints =
- (existingSigConstraints ++ newSigConstraints).merge.consolidate(dcl.width)
+ val updatedSigConstraints = (existingSigConstraints ++ newSigConstraints).merge.consolidate(
+ dcl.width
+ )
// merge all other annotations
val updatedAnnotations = updatedSigConstraints ++ otherAnnotations
dcl -> dcl.copy(meta = dcl.meta.copy(annotations = updatedAnnotations))
@@ -568,6 +582,7 @@ final class MutableDB():
case (ref: DFRef.TypeRef, m) => usedTypeRefs.contains(ref)
case _ => true
}.toMap
+ val duplicateDesignSet = mutable.Set.empty[DFDesignBlock]
val duplicateDesignRepMap = DesignContext.uniqueDesigns.view.flatMap {
case (designType, groupList) =>
groupList.view.reverse.zipWithIndex.flatMap {
@@ -581,7 +596,9 @@ final class MutableDB():
if (first)
first = false
design.tags
- else design.tags.tag(DuplicateTag)
+ else
+ duplicateDesignSet += design
+ design.tags.tag(DuplicateTag)
design -> design.copy(
dclMeta = design.dclMeta.copy(nameOpt = Some(updatedDclName)),
tags = tags
@@ -609,7 +626,24 @@ final class MutableDB():
case dcl: DFVal.Dcl => constrainedDcls.getOrElse(dcl, dcl)
case m => m
}
- (members.map(finalFixFunc), fixedRefTable.view.mapValues(finalFixFunc).toMap)
+ // Remove all remaining public members (ports, domain blocks, and their
+ // dependencies) from duplicate designs. During elaboration these were kept
+ // so user code could reference them, but in the immutable DB they are no
+ // longer needed. Ports for duplicate designs are resolved on-demand via
+ // DuplicationRef in `DB.dupPortsByName`.
+ val redundantRefs = mutable.Set.empty[DFRefAny]
+ val finalMembers = members.flatMap {
+ case m: DFVal if m.isGlobal => Some(finalFixFunc(m))
+ case m: (DomainBlock | DFVal) if duplicateDesignSet.contains(m.getOwnerDesign) =>
+ redundantRefs += m.ownerRef
+ redundantRefs ++= m.getRefs
+ None
+ case m => Some(finalFixFunc(m))
+ }
+ val finalRefTable = fixedRefTable.view.flatMap { case (ref, member) =>
+ if (redundantRefs.contains(ref)) None else Some(ref -> finalFixFunc(member))
+ }.toMap
+ (finalMembers, finalRefTable)
val membersNoGlobalCtx = members.map {
case m: DFVal.CanBeGlobal => m.copyWithoutGlobalCtx
case m => m
diff --git a/core/src/main/scala/dfhdl/core/Step.scala b/core/src/main/scala/dfhdl/core/Step.scala
index 0d0b04842..0844a5c7b 100644
--- a/core/src/main/scala/dfhdl/core/Step.scala
+++ b/core/src/main/scala/dfhdl/core/Step.scala
@@ -56,41 +56,52 @@ object Step extends Step:
scope: DFC.Scope.Process
): Unit =
val step = StepBlock(using dfc.setMeta(stepMeta))
- scope.stepCache += (stepMeta.name -> step.asIR)
+ // a unique step key is generated by combining the step's name with its starting line number.
+ // This handles cases where step names are reused in different internal scopes, such as within loops or nested steps.
+ val stepKey = s"${stepMeta.name}_${stepMeta.position.lineStart}"
+ scope.stepCache += (stepKey -> step.asIR)
// this is called by the compiler plugin and replaces the step's `def`. this will add the
// step to the context, update its reference to point to the proper owner, and finally run
// the step's body with the step as its owner.
- def pluginAddStep(stepName: String)(
+ def pluginAddStep(stepKey: String)(
run: => Unit
)(using dfc: DFC, scope: DFC.Scope.Process): Unit =
- val stepIR = scope.stepCache(stepName)
+ val stepIR = scope.stepCache(stepKey)
stepIR.addMember
dfc.mutableDB.newRefFor(stepIR.ownerRef, dfc.owner.asIR)
dfc.enterOwner(stepIR.asFE)
run
dfc.exitOwner()
- // this is called by the compiler plugin and replaces the step's onEntry/onExit `def` with
- // a step block that has the name "onEntry"/"onExit" which is special-cases and not treated
- // as a normal step, but just a container for the onEntry/onExit code.
- def pluginOnEntryExit(meta: ir.Meta)(
- run: => Unit
+ // this is called by the compiler plugin and replaces the step's onEntry/onExit/fallThrough `def` with
+ // a step block that has the name "onEntry"/"onExit"/"fallThrough" which is special-cases and not treated
+ // as a normal step, but just a container for the onEntry/onExit/fallThrough code.
+ def pluginOnEntryExitFallThrough(meta: ir.Meta)(
+ run: => Any
)(using dfc: DFC): Unit =
- val onEntryExit = ir.StepBlock(
+ import dfc.getSet
+ val onEntryExitFallThrough = ir.StepBlock(
dfc.owner.ref,
meta,
dfc.tags
).addMember
- dfc.enterOwner(onEntryExit.asFE)
- run
+ dfc.enterOwner(onEntryExitFallThrough.asFE)
+ val ret = run
+ if (onEntryExitFallThrough.isFallThrough)
+ Exact.strip(ret) match
+ case v: DFValAny =>
+ // adding ident placement as the last member of the fall-through block
+ DFVal.Alias.AsIs.ident(v)(using dfc.anonymize)
+ case _ => // do nothing
dfc.exitOwner()
+ end pluginOnEntryExitFallThrough
// this is called by the compiler plugin and replaces references (calls) to the step `def`.
// for the process this is considered as a goto statement.
- def pluginGotoStep(nextStepName: String)(using dfc: DFC, scope: DFC.Scope.Process): Unit =
+ def pluginGotoStep(nextStepKey: String)(using dfc: DFC, scope: DFC.Scope.Process): Unit =
import dfc.getSet
- val nextStep = scope.stepCache(nextStepName)
+ val nextStep = scope.stepCache(nextStepKey)
val member: ir.Goto = ir.Goto(
nextStep.refTW[ir.Goto],
dfc.owner.ref,
diff --git a/core/src/main/scala/dfhdl/core/TextOut.scala b/core/src/main/scala/dfhdl/core/TextOut.scala
index 99a09eae3..7f59a6d5e 100644
--- a/core/src/main/scala/dfhdl/core/TextOut.scala
+++ b/core/src/main/scala/dfhdl/core/TextOut.scala
@@ -42,33 +42,35 @@ object TextOut:
transparent inline def print(inline msg: Any): Unit =
compiletime.summonFrom {
case given ScalaPrintsFlag => scala.Predef.print(msg)
- case given DFC.Scope.Local => textOut(Op.Print, Some(msg))
- case _ => scala.Predef.print(msg)
+ case given DFC.Scope.Local =>
+ textOut(Op.Print, Some(msg))(using compiletime.summonInline[DFC])
+ case _ => scala.Predef.print(msg)
}
transparent inline def println(inline msg: Any): Unit =
compiletime.summonFrom {
case given ScalaPrintsFlag => scala.Predef.println(msg)
- case given DFC.Scope.Local => textOut(Op.Println, Some(msg))
- case _ => scala.Predef.println(msg)
+ case given DFC.Scope.Local =>
+ textOut(Op.Println, Some(msg))(using compiletime.summonInline[DFC])
+ case _ => scala.Predef.println(msg)
}
transparent inline def println(): Unit =
compiletime.summonFrom {
case given ScalaPrintsFlag => scala.Predef.println()
- case given DFC.Scope.Local => textOut(Op.Println, None)
+ case given DFC.Scope.Local => textOut(Op.Println, None)(using compiletime.summonInline[DFC])
case _ => scala.Predef.println()
}
inline def report(inline message: Any, severity: Severity = Severity.Info): Unit =
- textOut(Op.Report(severity), Some(message))
+ textOut(Op.Report(severity), Some(message))(using compiletime.summonInline[DFC])
inline def assert(
inline assertion: Any,
inline message: Any,
severity: Severity
)(using dfc: DFC): Unit =
- assertDFHDL(assertion, Some(message), severity)
+ assertDFHDL(assertion, Some(message), severity)(using compiletime.summonInline[DFC])
transparent inline def assert(inline assertion: Any, inline message: => Any): Unit =
compiletime.summonFrom {
@@ -118,11 +120,11 @@ object TextOut:
private inline def textOut(
op: ir.TextOut.Op,
inline msgOption: Option[Any]
- ): Unit = ${ textOutMacro('op, 'msgOption) }
+ )(using dfc: DFC): Unit = ${ textOutMacro('op, 'msgOption)('dfc) }
private def textOutMacro(
op: Expr[ir.TextOut.Op],
msgOption: Expr[Option[Any]]
- )(using
+ )(dfc: Expr[DFC])(using
Quotes
): Expr[Unit] =
import quotes.reflect.*
@@ -133,7 +135,6 @@ object TextOut:
case _ => t
var msgPartsExpr: Expr[List[String]] = '{ List.empty[String] }
var msgArgsExpr: Expr[List[DFValAny]] = '{ List.empty[DFValAny] }
- val dfc = Expr.summon[DFC].get
recurse(msgOption.asTerm).asExpr match
case '{ None } =>
case '{ Some($msg) } =>
diff --git a/core/src/main/scala/dfhdl/core/r__For_Plugin.scala b/core/src/main/scala/dfhdl/core/r__For_Plugin.scala
index d6adfdd9d..87cc92d12 100644
--- a/core/src/main/scala/dfhdl/core/r__For_Plugin.scala
+++ b/core/src/main/scala/dfhdl/core/r__For_Plugin.scala
@@ -104,15 +104,19 @@ object r__For_Plugin:
Pattern.BindSI(op, parts, bindVals.map(_.asIR.refTW[DFConditional.DFCaseBlock]))
@metaContextIgnore
def genDesignParam[V <: DFValAny](
- paramValue: DFValAny,
- default: Option[DFValAny],
+ appliedVal: DFValAny,
+ defaultVal: Option[DFValAny],
paramMeta: ir.Meta
)(using DFC): V =
trydf:
dfc.mutableDB.DesignContext.getReachableNamedValue(
- paramValue.asIR,
- DFVal.DesignParam(paramValue, default)(using dfc.setMeta(paramMeta)).asIR
+ appliedVal.asIR,
+ DFVal.DesignParam(appliedVal, defaultVal)(using dfc.setMeta(paramMeta)).asIR
).asValAny.asInstanceOf[V]
+ def prepareDesignParamValues(paramNames: List[String], paramValues: List[DFValAny])(using
+ DFC
+ ): Unit =
+ dfc.mutableDB.DesignContext.prepareDesignParamValues(paramNames, paramValues)
@metaContextIgnore
def designFromDefGetInput[V <: DFValAny](idx: Int)(using DFC): V =
dfc.mutableDB.DesignContext.getDefInput(idx).asInstanceOf[V]
@@ -135,6 +139,7 @@ object r__For_Plugin:
}
val (isDuplicate, ret): (Boolean, V) =
dfc.mutableDB.DesignContext.runFuncWithInputs(func, inputs)
+ Design.Block.updateWithParams(designBlock.asIR)
def exitAndConnectInputs() =
dfc.exitOwner()
inputs.lazyZip(args).foreach { case (input, (arg, _)) =>
@@ -157,4 +162,6 @@ object r__For_Plugin:
output.asInstanceOf[V]
end if
end designFromDef
+ def identVal[V <: DFValAny](value: V)(using DFC): V =
+ DFVal.Alias.AsIs.ident(value).asInstanceOf[V]
end r__For_Plugin
diff --git a/core/src/main/scala/dfhdl/hdl.scala b/core/src/main/scala/dfhdl/hdl.scala
index f02b2fe13..61ee08459 100644
--- a/core/src/main/scala/dfhdl/hdl.scala
+++ b/core/src/main/scala/dfhdl/hdl.scala
@@ -24,7 +24,7 @@ protected object hdl:
export internals.CommonOps.*
export core.{dfType}
export core.DFPhysical.Val.Ops.*
- export core.COMB_LOOP
+ export core.LoopOps.*
type Time = core.DFTime
val Time = core.DFTime
type Freq = core.DFFreq
diff --git a/core/src/main/scala/dfhdl/options/OnError.scala b/core/src/main/scala/dfhdl/options/OnError.scala
index c022736f5..12e7ef5b0 100644
--- a/core/src/main/scala/dfhdl/options/OnError.scala
+++ b/core/src/main/scala/dfhdl/options/OnError.scala
@@ -1,7 +1,7 @@
package dfhdl.options
-import dfhdl.internals.{sbtShellIsRunning, sbtTestIsRunning}
+import dfhdl.internals.{sbtShellIsRunning, sbtTestIsRunning, sbtnIsRunning}
enum OnError derives CanEqual:
case Exit, Exception
object OnError:
- given OnError = if (sbtShellIsRunning || sbtTestIsRunning) Exception else Exit
+ given OnError = if (sbtShellIsRunning || sbtnIsRunning || sbtTestIsRunning) Exception else Exit
diff --git a/core/src/test/scala/CoreSpec/DFDecimalSpec.scala b/core/src/test/scala/CoreSpec/DFDecimalSpec.scala
index 03266c499..675208ce3 100644
--- a/core/src/test/scala/CoreSpec/DFDecimalSpec.scala
+++ b/core/src/test/scala/CoreSpec/DFDecimalSpec.scala
@@ -598,6 +598,56 @@ class DFDecimalSpec extends DFSpec:
"""u8 % d"9'22""""
)
}
+ test("Arithmetic auto-carry promotion") {
+ val u8 = UInt(8) <> VAR
+ val u5 = UInt(5) <> VAR
+ val s8 = SInt(8) <> VAR
+ val u8b = UInt(8) <> VAR
+ val u9 = UInt(9) <> VAR
+ val u10 = UInt(10) <> VAR
+ val u12 = UInt(12) <> VAR
+ val u16 = UInt(16) <> VAR
+ val s9 = SInt(9) <> VAR
+ assertCodeString {
+ """|u9 := u8 +^ u8
+ |u9 := u8 -^ u8
+ |u16 := u8 *^ u8
+ |u10 := (u8 +^ u8).resize(10)
+ |u8b := u8 + u8
+ |val sum = u8 + u8
+ |u9 := sum.resize(9)
+ |s9 := s8 +^ s8
+ |u9 := (u8 / u8).resize(9)
+ |u9 := u8 +^ u5.resize(8)
+ |u9 := u8 +^ d"8'200"
+ |u12 := (u8 *^ u8).resize(12)
+ |""".stripMargin
+ } {
+ // Basic carry promotion for +
+ u9 := u8 + u8
+ // Basic carry promotion for -
+ u9 := u8 - u8
+ // Basic carry promotion for *
+ u16 := u8 * u8
+ // Target wider than carry width: promote to 9, resize to 10
+ u10 := u8 + u8
+ // Target = func width: no promotion
+ u8b := u8 + u8
+ // Named value: no promotion
+ val sum = u8 + u8
+ u9 := sum
+ // SInt version
+ s9 := s8 + s8
+ // Division: no carry variant, normal resize
+ u9 := u8 / u8
+ // Asymmetric widths: u8 + u5 → func width 8, carry = 9
+ u9 := u8 + u5
+ // Int literal: 200 is 8 bits, carry width = 9
+ u9 := u8 + 200
+ // Partial mul promotion: target (12) > funcWidth (8), promote to 16, resize to 12
+ u12 := u8 * u8
+ }
+ }
test("Int32 arithmetic") {
val param: Int <> CONST = 2
val t1 = 1 + param
diff --git a/core/src/test/scala/CoreSpec/DFVectorSpec.scala b/core/src/test/scala/CoreSpec/DFVectorSpec.scala
index bd3772e26..a368935d3 100644
--- a/core/src/test/scala/CoreSpec/DFVectorSpec.scala
+++ b/core/src/test/scala/CoreSpec/DFVectorSpec.scala
@@ -24,7 +24,8 @@ class DFVectorSpec extends DFSpec:
|val v3 = UInt(8) X 4 X 4 <> VAR
|v3 := all(all(d"8'0"))
|v3(3)(1) := d"8'25"
- |v3 := v3
+ |val t = v3
+ |v3 := t
|val len: Int <> CONST = 3
|val v4 = UInt(8) X len <> VAR init all(d"8'0")
|val v5: UInt[4] X len.type <> CONST = all(d"4'0")
diff --git a/docs/css/user-guide.css b/docs/css/user-guide.css
index 036b10233..313ade59a 100644
--- a/docs/css/user-guide.css
+++ b/docs/css/user-guide.css
@@ -1,3 +1,10 @@
+/* column separator between the two halves of the conversion table */
+div.conversion td:nth-child(4),
+div.conversion th:nth-child(4) {
+ border-left: 2px solid var(--md-typeset-table-color, #0000001f);
+ padding-left: 1em;
+}
+
/* different styles for tabs inside tabs */
html.js-focus-visible.js body div.md-container main.md-main div.md-main__inner.md-grid div.md-content article.md-content__inner.md-typeset div.admonition div.tabbed-set.tabbed-alternate div.tabbed-content div.tabbed-block div.tabbed-set.tabbed-alternate div.tabbed-labels.tabbed-labels--linked label a {
font-size: smaller;
diff --git a/docs/getting-started/hello-world/index.md b/docs/getting-started/hello-world/index.md
index aceae8d67..948e256d1 100644
--- a/docs/getting-started/hello-world/index.md
+++ b/docs/getting-started/hello-world/index.md
@@ -73,6 +73,23 @@ scala run .
For more information, please run `scala run --help` or consult the [online documentation](https://scala-cli.virtuslab.org/docs/commands/run){target="_blank"}.
+/// admonition | Multi-file projects
+ type: tip
+In a scala-cli project with multiple `.scala` files, shared `given` declarations (such as compiler options) must appear in exactly one file. Place them in your `project.scala` file to avoid duplicate definition errors.
+
+```scala title="project.scala"
+//> using scala 3.8.1
+//> using dep io.github.dfianthdl::dfhdl::0.17.0
+//> using plugin io.github.dfianthdl:::dfhdl-plugin:0.17.0
+
+import dfhdl.*
+given options.CompilerOptions.Backend = backends.verilog
+given options.CompilerOptions.PrintBackendCode = true
+```
+
+Individual design files should `import dfhdl.*` but not redeclare the shared `given` options.
+///
+
### sbt Project
The best way to get started with a DFHDL sbt project is to clone our template from GitHub:
diff --git a/docs/getting-started/hello-world/scala-project/.scalafmt.conf b/docs/getting-started/hello-world/scala-project/.scalafmt.conf
index fcc9a13d3..75af615b0 100644
--- a/docs/getting-started/hello-world/scala-project/.scalafmt.conf
+++ b/docs/getting-started/hello-world/scala-project/.scalafmt.conf
@@ -1,4 +1,4 @@
-version = 3.10.5
+version = 3.10.7
runner.dialect = scala3
maxColumn = 100
diff --git a/docs/transitioning/from-verilog/index.md b/docs/transitioning/from-verilog/index.md
index 271e4882e..779cb3749 100644
--- a/docs/transitioning/from-verilog/index.md
+++ b/docs/transitioning/from-verilog/index.md
@@ -1,10 +1,8 @@
# Transitioning from Verilog to DFHDL
-## Using ChatGPT
+This guide helps Verilog/SystemVerilog users translate common patterns into DFHDL. For full type system details, see the [Type System reference][type-system].
-Help me ChatGPT, you're my only hope
-
-## Summary
+## Design Structure
/// admonition | Module Definition
type: verilog
@@ -62,32 +60,41 @@ parameter [7:0] p = 8’b1011;
```scala linenums="0" title="DFHDL"
val p: Bits[8] <> CONST = b"8'1011"
```
+
+
+Inter-dependent parameters and ports example:
+
+
```sv linenums="0" title="Verilog"
-module Concat #(
- parameter int len1;
- parameter int len2;
- localparam int outlen = len1 + len2
-) (
- input [len1-1:0] i1;
- input [len2-1:0] i2;
- output [outlen-1:0] o
+module Concat#(
+ parameter int len1 = 8,
+ parameter int len2 = 8,
+ parameter logic [7:0] midVec = 8'h55
+)(
+ input wire logic [len1 - 1:0] i1,
+ input wire logic [len2 - 1:0] i2,
+ output logic [outlen - 1:0] o
);
- assign o = {i1, i2};
+ localparam int midLen = 8;
+ localparam int outlen = len1 + midLen + len2;
+ assign o = {i1, midVec, i2};
endmodule
```
```scala linenums="0" title="DFHDL"
class Concat(
- val len1: Int <> CONST
- val len2: Int <> CONST
+ val len1: Int <> CONST = 8,
+ val len2: Int <> CONST = 8,
+ val midVec: Bits[Int] <> CONST = h"55"
) extends EDDesign:
- val outlen = len1 + len2
- val i1 = Bits(len1) <> IN
- val i2 = Bits(len2) <> IN
- val o = Bits(outlen) <> OUT
-
- o <> (i1, i2)
+ val midLen = midVec.width
+ val outlen = len1 + midLen + len2
+ val i1 = Bits(len1) <> IN
+ val i2 = Bits(len2) <> IN
+ val o = Bits(outlen) <> OUT
+
+ o <> (i1, midVec, i2)
end Concat
```
@@ -105,9 +112,591 @@ reg [7:0] v = 8’b1011;
```
```scala linenums="0" title="DFHDL"
-val v = Bits(8) <> VAR init b"8'1011"
+val v = Bits(8) <> VAR init b"8’1011"
+```
+
+
+///
+
+## Types and Literals
+
+/// admonition | Numeric Literals
+ type: verilog
+DFHDL uses string interpolators for sized literals. Each type has its own interpolator -- do not mix Verilog base prefixes (`’b`, `’d`, `’h`) inside them.
+
+
+
+```sv linenums="0" title="Verilog"
+8’b1011_0000 // binary
+8’hB0 // hex
+8’d176 // decimal
+5’d27 // 5-bit decimal
+```
+
+```scala linenums="0" title="DFHDL"
+b"8’1011_0000" // binary (b"...")
+h"8’B0" // hex (h"...")
+d"8’176" // unsigned decimal (d"...")
+d"5’27" // 5-bit unsigned decimal
+```
+
+
+
+`b"..."` accepts only binary digits (`0`, `1`, `?`). Writing `b"5’d27"` is an error -- use `d"5’27"` for decimal values.
+///
+
+/// admonition | `$clog2` and Width Computation
+ type: verilog
+Instead of computing widths manually with `$clog2`, use `.until` or `.to` constructors which set the width automatically:
+
+| Verilog | DFHDL | Width |
+|---------|-------|-------|
+| `$clog2(N)` | `UInt.until(N)` / `Bits.until(N)` | `clog2(N)` bits, valid for N >= 2 |
+| `$clog2(N+1)` | `UInt.to(N)` / `Bits.to(N)` | `clog2(N+1)` bits, valid for N >= 1 |
+
+`UInt.until(1)` is **invalid** (would produce 0-bit width). For counters that count 0 to N inclusive (common with `$clog2(N+1)`), use `UInt.to(N)`.
+
+
+
+```sv linenums="0" title="Verilog"
+parameter RATE = 5208;
+localparam WIDTH = $clog2(RATE);
+reg [WIDTH-1:0] counter;
+
+// Counter 0..SCALE inclusive
+reg [$clog2(SCALE+1)-1:0] cnt = 0;
+```
+
+```scala linenums="0" title="DFHDL"
+val RATE: Int <> CONST = 5208
+val counter = UInt.until(RATE) <> VAR
+
+
+// Counter 0..SCALE inclusive
+val cnt = UInt.to(SCALE) <> VAR init 0
+```
+
+
+
+/// admonition | Choosing `.until(N)` vs `.to(N)` for counters
+ type: warning
+If the Verilog counter resets *when it reaches* `N` (i.e., `counter == N`), the variable must be able to hold the value `N`, so use `UInt.to(N)`. If the counter only ever holds values `0..N-1`, use `UInt.until(N)`. For many values of `N`, both produce the same bit width (`clog2(N) == clog2(N+1)`), so the bug is silent until formal verification catches an out-of-range comparison.
+///
+
+See [UInt/SInt constructors][DFDecimal] and [Bits constructors][DFBits] for details. See also the [`clog2` anti-pattern warning][int-param-ops].
+///
+
+## Processes and Sequential Logic
+
+/// admonition | Process Blocks (always)
+ type: verilog
+Verilog `always` blocks map to DFHDL ED domain `process(...)` blocks.
+
+
+
+```sv linenums="0" title="Verilog"
+// Combinational
+always @(*) begin
+ y = a + b;
+end
+
+// Sequential (clocked)
+always @(posedge clk) begin
+ counter <= counter + 1;
+end
+
+// Sequential with async reset
+always @(posedge clk or posedge rst)
+ if (rst)
+ q <= 0;
+ else
+ q <= d;
+```
+
+```scala linenums="0" title="DFHDL"
+// Combinational
+process(all):
+ y := a + b
+
+
+// Sequential (clocked)
+process(clk):
+ if (clk.rising)
+ counter :== counter + 1
+
+// Sequential with async reset
+process(clk, rst):
+ if (rst)
+ q :== 0
+ else if (clk.rising)
+ q :== d
+```
+
+
+
+- `always @(*)` becomes `process(all):`
+- `always @(posedge clk)` becomes `process(clk):` with `if (clk.rising)` inside
+- Verilog blocking `=` becomes DFHDL `:=` (use in combinational processes)
+- Verilog non-blocking `<=` becomes DFHDL `:==` (use in clocked processes)
+///
+
+/// admonition | Variable Initialization (init)
+ type: verilog
+In ED domain, `init` on a `VAR` generates a Verilog `reg` with an initial value. This maps to both `initial begin` blocks and `reg ... = value` declarations.
+
+
+
+```sv linenums="0" title="Verilog"
+reg [7:0] counter = 8’d0;
+// or equivalently:
+// initial counter = 8’d0;
+```
+
+```scala linenums="0" title="DFHDL"
+val counter = UInt(8) <> VAR init 0
+```
+
+
+
+An `output reg` with an initial value maps directly to `OUT init`:
+
+
+
+```sv linenums="0" title="Verilog"
+module Foo(
+ input clk,
+ input din,
+ output reg dout
+);
+ initial dout = 1'b1;
+ always @(posedge clk)
+ dout <= din;
+endmodule
+```
+
+```scala linenums="0" title="DFHDL"
+@top class Foo extends EDDesign:
+ val clk = Bit <> IN
+ val din = Bit <> IN
+ val dout = Bit <> OUT init 1
+ process(clk):
+ if (clk.rising)
+ dout :== din
+```
+
+
+///
+
+/// admonition | FSM State Encoding
+ type: verilog
+Verilog FSMs typically use `parameter` constants and `case`/`if` chains. In DFHDL, the idiomatic translation uses an `enum extends Encoded` and `match`:
+
+
+
+```sv linenums="0" title="Verilog"
+parameter READY = 2'b00,
+ AIM = 2'b01,
+ FIRE = 2'b10;
+reg [1:0] state = READY;
+
+always @(posedge clk)
+ case (state)
+ READY: if (go) state <= AIM;
+ AIM: state <= FIRE;
+ FIRE: state <= READY;
+ default: state <= READY;
+ endcase
+```
+
+```scala linenums="0" title="DFHDL"
+enum State extends Encoded:
+ case Ready, Aim, Fire
+import State.*
+val state = State <> VAR init Ready
+
+process(clk):
+ if (clk.rising)
+ state match
+ case Ready => if (go) state :== Aim
+ case Aim => state :== Fire
+ case Fire => state :== Ready
+ case _ => state :== Ready
+```
+
+
+
+If the encoded Verilog state values follow a standard pattern (incremental, gray, one-hot), use the corresponding `Encoded` variant. For non-standard encodings, use `Encoded.Manual` with a constructor parameter:
+
+```scala
+// Verilog: parameter INIT=3'b000, RUN=3'b011, DONE=3'b101, ERR=3'b110;
+enum Phase(val value: UInt[3] <> CONST) extends Encoded.Manual(3):
+ case Init extends Phase(0)
+ case Run extends Phase(3)
+ case Done extends Phase(5)
+ case Err extends Phase(6)
+```
+
+The constructor parameter `(val value: UInt[N] <> CONST)` is required for `Encoded.Manual` and the bit width `N` must match the argument to `Encoded.Manual(N)`. Omitting it causes a compile error. See [Enumeration][DFEnum] for all encoding options.
+
+When the Verilog FSM uses an explicit reset instead of `initial`, omit the `init` and handle reset inside the clocked process:
+
+
+
+```sv linenums="0" title="Verilog"
+always @(posedge clk)
+ if (rst)
+ state <= READY;
+ else
+ case (state)
+ READY: if (go) state <= AIM;
+ AIM: state <= FIRE;
+ FIRE: state <= READY;
+ default: state <= READY;
+ endcase
+```
+
+```scala linenums="0" title="DFHDL"
+val state = State <> VAR // no init
+
+process(clk):
+ if (clk.rising)
+ if (rst)
+ state :== Ready
+ else
+ state match
+ case Ready => if (go) state :== Aim
+ case Aim => state :== Fire
+ case Fire => state :== Ready
+ case _ => state :== Ready
+```
+
+
+
+Avoid modeling FSM states as `Bits` or `UInt` constants -- it is an anti-pattern. When compiling to SystemVerilog (SV), the SV enums are being utilized as well.
+///
+
+/// admonition | Integer `case` Statements (non-enum)
+ type: verilog
+When the Verilog `case` selector is a plain integer counter (not an FSM), use `match` with integer literal cases directly:
+
+
+
+```sv linenums="0" title="Verilog"
+case (sel)
+ 'd0: out <= 60;
+ 'd1: out <= 110;
+ 'd2 | 'd3: out <= 200;
+ default: out <= 0;
+endcase
+```
+
+```scala linenums="0" title="DFHDL"
+sel match
+ case 0 => out :== 60
+ case 1 => out :== 110
+ case 2 | 3 => out :== 200
+ case _ => out :== 0
+end match
+```
+
+
+
+Integer literal pattern matching works with `UInt` and `SInt` selectors. Guard conditions (`case _ if sel == N`) also work but are less idiomatic. See [Match Expressions][match-expressions] for full details.
+///
+
+## Operations
+
+/// admonition | Shift Operators
+ type: verilog
+Verilog has separate `>>` (logical) and `>>>` (arithmetic) right shift operators. DFHDL uses only `>>`, but the behavior depends on the operand type:
+
+
+
+```sv linenums="0" title="Verilog"
+module RightShifter(
+ input wire logic [7:0] data,
+ output logic [7:0] logical,
+ output logic [7:0] arith
+);
+ assign logical = data >> 1;
+ assign arith = data >>> 1;
+endmodule
+```
+
+```scala linenums="0" title="DFHDL"
+class RightShifter extends EDDesign:
+ val data = Bits(8) <> IN
+ val logical = Bits(8) <> OUT
+ val arith = Bits(8) <> OUT
+
+ logical <> data >> 1
+ arith <> (data.sint >> 1).bits
+end RightShifter
+```
+
+
+
+There is no `>>>` operator in DFHDL. The type of the LHS determines the shift semantics: `>>` on `UInt`/`Bits` zero-fills, `>>` on `SInt` sign-extends. See [Shift Operations][shift-ops] for details.
+///
+
+
+/// admonition | Bit/Boolean Operators: `|`/`&` and `||`/`&&`
+ type: verilog
+In DFHDL, `||`/`&&` and `|`/`&` are interchangeable on `Bit` and `Boolean` types. The generated Verilog operator depends on the LHS type: `Bit` produces bitwise `|`/`&`, `Boolean` produces logical `||`/`&&`.
+
+
+```sv linenums="0" title="Verilog"
+input a, b, c;
+output o1, o2, o3;
+assign o1 = a | b | c;
+assign o2 = a | b | c;
+assign o3 = a || b || c;
+```
+
+```scala linenums="0" title="DFHDL"
+val a, b, c = Bit <> IN
+val o1, o2, o3 = Bit <> OUT
+o1 <> a | b | c
+o2 <> a || b || c
+o3 <> a.bool || b || c
+```
+
+
+
+See [Logical Operations][logical-ops] for the full reference and Verilog/VHDL mapping tables.
+///
+
+/// admonition | Reduction Operators (`&v`, `|v`, `^v`)
+ type: verilog
+Verilog's unary reduction operators have direct DFHDL equivalents using postfix `.&`, `.|`, `.^` on `Bits` values:
+
+
+
+```sv linenums="0" title="Verilog"
+logic [7:0] v;
+logic all_set = &v; // AND reduce
+logic any_set = |v; // OR reduce
+logic parity = ^v; // XOR reduce
+logic not_all = ~&v; // NAND reduce
+logic none_set = ~|v; // NOR reduce
+```
+
+```scala linenums="0" title="DFHDL"
+val v = Bits(8) <> VAR
+val all_set = v.& // Bit: AND reduce
+val any_set = v.| // Bit: OR reduce
+val parity = v.^ // Bit: XOR reduce
+val not_all = !v.& // Bit: NAND reduce
+val none_set = !v.| // Bit: NOR reduce
+```
+
+
+
+See [Bit Reduction Operations][reduction-ops] for full details.
+///
+
+/// admonition | Part-Select Notation (`-:` and `+:`)
+ type: verilog
+Verilog's descending and ascending part-select notation maps to DFHDL's `(hi, lo)` range slice, or use the convenience methods `.msbits(n)` and `.lsbits(n)`:
+
+| Verilog | DFHDL | Notes |
+|---------|-------|-------|
+| `sig[base -: W]` | `sig(base, base - W + 1)` | Descending slice from `base`, `W` bits |
+| `sig[base +: W]` | `sig(base + W - 1, base)` | Ascending slice from `base`, `W` bits |
+| `sig[N-1 -: W]` | `sig.msbits(W)` or `sig(N-1, N-W)` | Top `W` bits |
+| `sig[0 +: W]` | `sig.lsbits(W)` or `sig(W-1, 0)` | Bottom `W` bits |
+| `sig[idx]` | `sig(idx)` | Single bit access |
+
+
+
+```sv linenums="0" title="Verilog"
+logic [15:0] data;
+logic [3:0] top4 = data[15 -: 4];
+logic [3:0] bot4 = data[0 +: 4];
+logic bit5 = data[5];
+```
+
+```scala linenums="0" title="DFHDL"
+val data = Bits(16) <> VAR
+val top4 = data.msbits(4) // top 4 bits
+val bot4 = data.lsbits(4) // bottom 4 bits
+val bit5 = data(5) // single bit
+```
+
+
+///
+
+/// admonition | Arithmetic with Signed Values and Constants
+ type: verilog
+DFHDL arithmetic requires the LHS to be at least as wide as the RHS and to have compatible sign. A plain Scala `Int` literal is unsigned, so it cannot appear on the LHS of arithmetic with `SInt`. The best practice is to use **sized signed literals** (`sd"W'value"`) with the target operation width:
+
+```scala
+// Verilog: y <= 2 * mul_val + y0; (all signed, 16-bit)
+// ERROR: plain 2 is unsigned
+y :== 2 * mul_val + y0
+// CORRECT: use a sized signed literal
+y :== sd"16'2" * mul_val + y0
+
+// Verilog: err <= 2 - (2 * r0); (signed, 18-bit result)
+// ERROR: sd"2" is SInt[3], narrower than RHS
+err :== sd"2" - (r0.resize(CORDW + 2) * 2)
+// CORRECT: match the LHS width to the operation width
+err :== sd"${CORDW + 2}'2" - (r0.resize(CORDW + 2) * 2)
+```
+
+The general rule: the **wider** operand must be on the LHS, and when mixing constants with signed DFHDL values, use `sd"W'value"` with the appropriate width `W`.
+
+See [Arithmetic Operations][arithmetic-ops] and [Carry Arithmetic][carry-ops] for full details.
+///
+
+## Parametric Constants
+
+/// admonition | Parametric-Width Bits Constants
+ type: verilog
+Verilog parameters can be bit-vector constants whose width depends on another parameter. In DFHDL, use `Bits[Int] <> CONST` (unbounded width) for the parameter. The width is inferred from the default literal value, and other local values can derive their widths from it:
+
+
+
+```sv linenums="0" title="Verilog"
+module MyDesign #(
+ parameter WIDTH = 8,
+ parameter [WIDTH-1:0] MASK = 8'hB8
+)(
+ output logic [WIDTH-1:0] data
+);
+ // ...
+endmodule
+```
+
+```scala linenums="0" title="DFHDL"
+class MyDesign(
+ val WIDTH: Int <> CONST = 8,
+ val MASK: Bits[Int] <> CONST = h"B8"
+) extends EDDesign:
+ // MASK.width gives the actual width
+ val data = Bits(MASK.width) <> OUT
+ // ...
+```
+
+
+
+See the [Parameter Declarations](#parameter-declarations) section above for a complete inter-dependent parameters example.
+///
+
+## Common Pitfalls
+
+/// admonition | Scala Reserved Keywords as DFHDL Port or Variable Names
+ type: verilog
+Some Verilog port names (`val`, `type`, `class`, `match`, `case`, `object`, etc.) are reserved in Scala. Use backtick escaping:
+
+
+
+```sv linenums="0" title="Verilog"
+module foo(
+ output reg signed [15:0] val
+);
+ assign val = 16'sd42;
+```
+
+```scala linenums="0" title="DFHDL"
+class foo extends EDDesign:
+ val `val` = SInt(16) <> OUT
+ `val` <> 42
+```
+
+
+
+Alternatively, use a non-keyword name with the Scala `@targetName` annotation to set the actual HDL name:
+
+
+
+```sv linenums="0" title="Verilog"
+module foo(
+ output logic signed [15:0] class
+);
+ assign class = 16'sd42;
+endmodule
+```
+
+```scala linenums="0" title="DFHDL"
+import scala.annotation.targetName
+class foo extends EDDesign:
+ @targetName("class")
+ val class_ = SInt(16) <> OUT
+ class_ <> 42
+```
+
+
+
+
+///
+
+/// admonition | `Bits` Initialization or Assignment
+ type: verilog
+`Bits` values cannot be initialized or assigned with plain integers. Use `all(0)` or a sized literal:
+
+
+
+```sv linenums="0" title="Verilog"
+reg [7:0] flags = 8'd0;
+reg [7:0] mask = 8'hFF;
+```
+
+```scala linenums="0" title="DFHDL"
+val flags = Bits(8) <> VAR init all(0)
+val mask = Bits(8) <> VAR init h"8'FF"
+// NOT: Bits(8) <> VAR init 0 // error
+```
+
+
+
+Note: `UInt` and `SInt` can be initialized or assigned with plain integers.
+///
+
+/// admonition | Inline Conditional Expressions
+ type: verilog
+Verilog's ternary operator `cond ? a : b` has three DFHDL equivalents:
+
+
+
+```sv linenums="0" title="Verilog"
+assign out = cond ? a : b;
+
+always @(*)
+ out = cond ? a : b;
+```
+
+```scala linenums="0" title="DFHDL"
+// 1. Using .sel (closest to ternary)
+out <> cond.sel(a, b)
+
+// 2. Inline if/else (wrap in parentheses)
+out <> (if (cond) a else b)
+
+// 3. Statement form
+if (cond) out := a
+else out := b
```
+
+The `.sel` method compiles directly to Verilog's ternary operator. For complex nested conditions, prefer `if`/`else` or `match` over chaining `.sel` calls. See [Selection (.sel)][sel-ops] for details.
+
+When using inline `if`/`else` as the RHS of `:=` or `:==`, **parentheses are required**. Without them, Scala 3 parses the `if` as a statement, not an expression:
+
+```scala
+// CORRECT: parenthesized inline if with := and <>
+out := (if (cond) a else b)
+out <> (if (cond) a else b)
+
+// PARSE ERROR: bare inline if on RHS of := or <>
+// out := if (cond) a else b // "end of statement expected"
+
+// CORRECT: statement form (no parentheses needed)
+if (cond) out := a
+else out := b
+```
+
+This applies to all assignment operators (`:=`, `:==`, `<>`). Use `.sel` or the parenthesized form for inline conditionals; use the statement form for multi-assignment branches.
///
diff --git a/docs/user-guide/conditionals/index.md b/docs/user-guide/conditionals/index.md
index 86c6f9840..7da6797de 100644
--- a/docs/user-guide/conditionals/index.md
+++ b/docs/user-guide/conditionals/index.md
@@ -184,6 +184,30 @@ else
- Optimizes bit pattern matching into efficient comparisons
- Extracts struct fields into temporary variables when needed
+/// admonition | Use enumerations for state matching
+ type: tip
+For FSM-style `match` over states, define an enumeration with the appropriate [encoding](../type-system/index.md#dfhdl-enumeration-enum--extends-encoded) and match on its members:
+
+```scala
+enum State extends Encoded: // 00, 01, 10
+ case Idle, Start, Data
+
+val state = State <> VAR
+state match
+ case State.Idle => // idle logic
+ case State.Start => // start logic
+ case State.Data => // data logic
+```
+
+For non-sequential state encodings, use `Encoded.Manual`:
+```scala
+enum State(val value: UInt[3] <> CONST) extends Encoded.Manual(3):
+ case Idle extends State(d"3'0")
+ case Start extends State(d"3'3")
+ case Data extends State(d"3'5")
+```
+///
+
### Best Practices
1. **Use Match for Multi-Way Branching**: When dealing with multiple cases, match is often clearer than nested if-else
diff --git a/docs/user-guide/processes/index.md b/docs/user-guide/processes/index.md
index eba028ee2..b1ccf6321 100644
--- a/docs/user-guide/processes/index.md
+++ b/docs/user-guide/processes/index.md
@@ -1 +1,229 @@
-# Processes
\ No newline at end of file
+# Processes
+
+Processes define *when* a block of logic runs. DFHDL supports processes in two domains:
+
+- **RT domain**: A **clock-bound** process used to describe finite-state machines (FSMs). The process runs in lockstep with the domain clock and uses steps, waits, and control flow that the compiler lowers to registers and combinational logic.
+- **ED domain**: **Sensitivity-driven** processes that run when listed signals change (or all read signals with `process(all)`), giving the same level of control as `process` in VHDL or `always` in Verilog.
+
+Processes are not available in the dataflow (DF) domain. Processes cannot be nested inside another process.
+
+## RT domain: clock-bound FSM process
+
+In an [RT design][design-domains], a process is used to describe a finite-state machine that is **clock-bound**: it advances on the domain clock and is compiled to a state register plus combinational next-state and output logic.
+
+### Syntax: `process` / `process.forever`
+
+Use the shorthand `process:` (or `process.forever`) inside an `RTDesign` or `RTDomain`. The block contains either plain combinational logic (assignments, no steps) or step definitions that form an FSM.
+
+### Step-based FSM
+
+Define states as `def Name: Step = ...` and control flow with:
+
+- **`NextStep`** — advance to the next step in definition order.
+- **`ThisStep`** — stay in the current step for another cycle.
+- **`FirstStep`** — go to the first step (e.g. reset to initial state).
+- **Step name** (e.g. `S1`, `S2`) — jump to that step.
+
+You can optionally name the process (e.g. `val my_fsm = process:`) so the compiler uses that name for the generated state enum and state register.
+
+```scala
+class SimpleFSM extends RTDesign:
+ val x = Bit <> IN
+ val y = Bit <> OUT.REG init 0
+
+ process:
+ def S0: Step =
+ y.din := 0
+ if (x) NextStep else S0
+ def S1: Step =
+ y.din := 1
+ if (x) S2 else FirstStep
+ def S2: Step =
+ y.din := 0
+ if (x) ThisStep else FirstStep
+```
+
+The compiler lowers this to a state enum, a state register, and a `match` on the state; see [Design Domains][design-domains] for the compilation flow.
+
+### fallThrough
+
+A step can define **`def fallThrough = cond`** where `cond` is a Boolean/Bit expression. When the condition holds, the step advances to the next step in the same cycle (conditional advancement); when it does not, the FSM stays in the current step.
+
+### onEntry and onExit
+
+Inside a step you can define:
+
+- **`def onEntry = ...`** — run when entering the step (once per transition into this state).
+- **`def onExit = ...`** — run when leaving the step (once per transition out of this state).
+
+```scala
+def S1: Step =
+ def onEntry =
+ y.din := 1
+ if (x) S2 else FirstStep
+def S2: Step =
+ def onExit =
+ y.din := 0
+ if (x) ThisStep else FirstStep
+```
+
+### Waits and loops
+
+RT processes can use **cycle waits** (e.g. `1.cy.wait`, `n.cy.wait`) and **wait conditions** (`waitUntil(cond)`, `waitWhile(cond)`). The compiler converts these into step blocks and counters so that the behavior remains clock-bound and synthesizable.
+
+### Process with no steps
+
+If the process body has no step definitions, it is purely combinational and runs every cycle:
+
+```scala
+process:
+ y.din := x
+```
+
+## ED domain: sensitivity-driven processes
+
+In an [ED design][design-domains], processes are **sensitivity-driven**: they run when an event occurs on one of their sensitivity signals (or on any read signal with `process(all)`).
+
+## ED process forms
+
+### Sensitivity list: `process(sig1, sig2, ...)`
+
+The process runs whenever any of the listed signals change.
+
+```scala
+class CombAndSeq extends EDDesign:
+ val clk = Bit <> IN
+ val rst = Bit <> IN
+ val x = UInt(8) <> IN
+ val y = UInt(8) <> OUT
+
+ // Combinational logic: runs when x changes
+ process(x):
+ y := x + 1
+
+ // Sequential logic: runs on clock (and optionally reset) events
+ val r = UInt(8) <> VAR init 0
+ process(clk):
+ if (clk.rising)
+ r :== x
+```
+
+You can list multiple signals, including edge-qualified signals (see [Edge sensitivity](#edge-sensitivity)).
+
+### Combinational-style: `process(all)`
+
+The process is sensitive to *all* signals that are read in the block. Use this for combinational logic that should react to any input change. The compiler infers the actual sensitivity list from the block body.
+
+```scala
+class CombLogic extends EDDesign:
+ val a = UInt(8) <> IN
+ val b = UInt(8) <> IN
+ val y = UInt(8) <> OUT
+
+ process(all):
+ y := a + b
+```
+
+### Forever process: `process.forever` / `process`
+
+A process with no sensitivity list runs continuously. It is allowed in RT and ED, but **not** in DF. The shorthand `process:` (no arguments) is rewritten by the compiler to `process.forever`.
+
+- **In RT**: `process:` is the [clock-bound FSM process](#rt-domain-clock-bound-fsm-process) described above (steps, waits, etc.).
+- **In ED**: Use it for testbenches or clock generation (e.g. toggling a clock with `wait`).
+
+```scala
+class Testbench extends EDDesign:
+ val clk = Bit <> VAR
+ process.forever:
+ clk := !clk
+ 5.ns.wait
+```
+
+## Edge sensitivity
+
+For sequential (clocked) logic you typically want the process to run only on a specific clock edge. You can either:
+
+1. **List the clock and check the edge inside the block** (VHDL-style):
+
+```scala
+process(clk):
+ if (clk.rising)
+ reg :== nextVal
+```
+
+2. **Put the edge in the sensitivity list** (Verilog-style; compiler may normalize to this):
+
+```scala
+process(clk.rising):
+ reg :== nextVal
+```
+
+Edge options are `.rising` and `.falling` on clock (or bit) signals. When reset is used, list both clock and reset and branch on reset then clock edge:
+
+```scala
+process(clk, rst):
+ if (rst)
+ out :== 0
+ else if (clk.rising)
+ out :== nextVal
+```
+
+## Assignments inside processes
+
+### Blocking assignment `:=`
+
+Takes effect immediately within the process. Use for combinational logic and for intermediate values that are read later in the same process.
+
+```scala
+process(all):
+ val temp = a + b // read a, b
+ y := temp // immediate update of y
+```
+
+### Non-blocking assignment `:==`
+
+Schedules an update at the end of the current evaluation step. Use for registers and outputs that should not create combinational feedback within the same process.
+
+```scala
+process(clk):
+ if (clk.rising)
+ counter :== counter + 1 // register update
+```
+
+/// admonition | Rule of thumb
+ type: tip
+Use `:=` for combinational (e.g. in `process(all)` or combinational branches). Use `:==` for register and sequential outputs in clocked processes.
+///
+
+## Local variables
+
+You can declare local variables inside a process with `VAL` or `VAR`; they are visible only within that process and help structure combinational or sequential logic.
+
+```scala
+process(all):
+ val z = UInt(8) <> VAR
+ if (x > 10)
+ z := x + 1
+ else
+ z := x - 1
+ y := z
+```
+
+## Relation to design domains
+
+| Domain | Processes |
+|--------|-----------|
+| **DF** | No processes. Behavior is expressed with dataflow and `.prev`; the compiler introduces registers and eventually ED processes. |
+| **RT** | **Clock-bound FSM process**: `process:` (or `process.forever`) with optional step definitions (`def Name: Step = ...`), `onEntry`/`onExit`, and waits. Compiled to a state register and match logic. Plain RT register code (no process) is also lowered to ED processes by the compiler. |
+| **ED** | **Sensitivity-driven**: `process(sig1, sig2, ...)`, `process(all)`, and `process.forever` / `process`. Full control over sensitivity and blocking vs non-blocking assignment. |
+
+See [Design Domains][design-domains] for the overall flow from DF → RT → ED and how processes fit into compilation.
+
+## Summary
+
+- **RT**: Use **`process:`** in **RTDesign** / **RTDomain** for a clock-bound FSM with **`def Name: Step = ...`**, **`NextStep`** / **`ThisStep`** / **`FirstStep`**, and optional **`onEntry`** / **`onExit`** and waits.
+- **ED**: Use **`process(sig1, sig2, ...)`** or **`process(all)`** in **EDDesign** / **EDDomain** to define when a block runs; **`process(all)`** for combinational logic; **`process(clk)`** (and optionally **`process(clk, rst)`**) with **`clk.rising`** / **`clk.falling`** for sequential logic.
+- Use **`:=`** for immediate (blocking) updates and **`:==`** for register (non-blocking) updates in ED processes.
+- Processes cannot be nested and are not available in the DF domain.
+
+[design-domains]: ../design-domains/index.md
diff --git a/docs/user-guide/type-system/index.md b/docs/user-guide/type-system/index.md
index 75aac1062..8d766c44b 100755
--- a/docs/user-guide/type-system/index.md
+++ b/docs/user-guide/type-system/index.md
@@ -445,73 +445,6 @@ class Foo extends DFDesign:
///
-## Bit-Accurate Operations and Type Inference
-
-DFHDL provides bit-accurate operations and strong type inference for bit-level manipulations. Here are the key features:
-
-### Bit Selection and Slicing
-```scala
-val b8 = Bits(8) <> VAR
-// Most significant bits selection
-val ms7 = b8(7, 1) // 7 MSBs
-val ms1 = b8(7, 7) // MSB only
-
-// Least significant bits selection
-val ls7 = b8(6, 0) // 7 LSBs
-val ls1 = b8(0, 0) // LSB only
-
-// Single bit access
-val msbit = b8(7) // MSB
-val lsbit = b8(0) // LSB
-```
-
-### Bit Operations
-```scala
-val b8 = Bits(8) <> VAR
-
-// Shift operations
-val shifted_left = b8 << 2 // Logical left shift
-val shifted_right = b8 >> 2 // Logical right shift
-
-// Bit reduction operations
-val or_reduced = b8.| // OR reduction
-val and_reduced = b8.& // AND reduction
-val xor_reduced = b8.^ // XOR reduction
-
-// Bit concatenation
-val concat = (b"100", b"1", b"0", b"11").toBits // Creates 8-bit value
-```
-
-### Multiple Variable Assignment
-```scala
-val b4M, b4L = Bits(4) <> VAR // Declare multiple variables
-val b3M = Bits(3) <> VAR
-val u5L = UInt(5) <> VAR
-
-// Assign to multiple variables using tuple pattern
-(b4M, b4L) := (h"1", 1, 0, b"11") // Values are concatenated and split
-
-// Mix different types in assignment
-(b3M, u5L) := (h"1", 1, 0, b"11") // Values automatically cast to appropriate types
-
-// Assign bit slices to multiple variables
-(b4M, b4L) := (u8.bits(3, 0), u8.bits(7, 4)) // Split byte into nibbles
-
-// Complex multiple assignment
-(b4M, b3M, u5L, b4L) := (u8, b8) // Automatically extracts appropriate bits for each variable
-```
-
-### Width Inference and Resizing
-```scala
-// Automatic width inference
-val b3 = Bits(3) <> VAR
-val b8 = Bits(8) <> VAR
-
-// Explicit resizing required when widths don't match
-b8 := b3.resize(8) // Zero-extend to 8 bits
-b3 := b8.resize(3) // Truncate to 3 bits
-```
-
## Bubble Values {#bubble}
* RT and ED - Don't Care / Unknown
@@ -584,7 +517,111 @@ val x = b8 ++ h"FF" //ok
val y = b8 ++ all(0) //error
```
-## `Bit`/`Boolean` DFHDL Values {#DFBitOrBool}
+## Type Signatures and Parameterization {#type-sigs}
+
+Every DFHDL value has a type of the form `T <> M`, where `T` is the DFHDL type (shape) and `M` is the modifier that determines how the value can be used.
+
+### Modifier Categories
+
+Modifiers fall into two groups:
+
+**Declaration modifiers** — used in `val` declarations with the `<>` operator:
+
+- `VAR`, `VAR.REG`, `VAR.SHARED` — variables
+- `IN`, `OUT`, `OUT.REG`, `INOUT` — ports
+
+**Type signature modifiers** — used in type annotations for parameters, struct fields, and method signatures:
+
+- `CONST` — compile-time or elaboration-time constant parameter
+- `VAL` — read-only value (struct fields, method parameters)
+- `DFRET` / `RTRET` / `EDRET` — method return types (DF, RT, or ED domain)
+
+### Design Parameters
+
+Design classes accept parameters as constructor arguments using `<> CONST`:
+
+```scala
+class Counter(val width: Int <> CONST = 8) extends RTDesign:
+ val cnt = UInt(width) <> OUT.REG init 0
+```
+
+- `Int <> CONST` for integer parameters (used for widths, lengths, counts)
+- Typed constants like `Bits[8] <> CONST` and `UInt[8] <> CONST` are also possible
+- Default values are optional
+
+### `VAL` Modifier
+
+`VAL` marks a read-only value. It is used for:
+
+- **Struct field declarations:**
+ ```scala
+ case class Point(x: UInt[8] <> VAL, y: UInt[8] <> VAL) extends Struct
+ ```
+- **Method/design-def parameters:**
+ ```scala
+ def increment(x: UInt[8] <> VAL): UInt[8] <> DFRET = x + 1
+ ```
+
+`VAL` values cannot be assigned or connected — they are inputs to the computation.
+
+### Design Defs and `DFRET`
+
+Design defs are functional helpers. Arguments use `<> VAL`, return types use `<> DFRET` (or `RTRET`/`EDRET` for domain-specific defs):
+
+```scala
+// DF domain design def
+def double(value: Bits[Int] <> VAL): Bits[Int] <> DFRET = (value, value)
+
+// Opaque type extension method
+extension (c: Counter <> VAL)
+ def increment: Counter <> DFRET = (c.actual + 1).as(Counter)
+```
+
+### Bounded and Unbounded Types {#bounded-unbounded}
+
+DFHDL types carry their size (width or length) as a Scala type parameter. There are three levels of size specificity:
+
+**Bounded** — the size is a literal singleton known at compile time. All type checks happen statically:
+
+```scala
+val a: UInt[8] <> CONST = d"255"
+val b: Bits[4] <> CONST = h"A"
+val v: Bits[8] X 4 <> CONST = all(all(0))
+```
+
+**Parameterized bounded** — the size is the singleton type of a named parameter. The compiler can track the relationship, even though the concrete value isn't known until instantiation:
+
+```scala
+class Foo(val w: Int <> CONST) extends RTDesign:
+ val x: Bits[w.type] <> CONST = all(0) // width tied to parameter w
+ val y = UInt[w.type] <> VAR init 0 // same
+ val v: UInt[4] X w.type <> CONST = all(0) // vector length tied to w
+```
+
+**Unbounded** — the size is bare `Int`, with no compile-time size information. Used when the type is too complex to express at the Scala type level (e.g., results of operations on parameterized types). The DFHDL compiler still has the required size information available during elaboration, where it is checked:
+
+```scala
+val cu: UInt[Int] <> VAL = 1
+val cs: SInt[Int] <> VAL = -1
+val bv: Bits[8] X Int <> CONST = Vector(h"12", h"34")
+def twice(value: Bits[Int] <> VAL): Bits[Int] <> DFRET = (value, value)
+```
+
+/// admonition | Struct fields must be bounded
+ type: warning
+Struct field types cannot be unbounded. Each field must have a concrete or parameterized-bounded type:
+```scala
+// CORRECT: bounded fields
+case class Pkt(header: Bits[8] <> VAL, data: UInt[32] <> VAL) extends Struct
+
+// ERROR: unbounded fields are not allowed
+// case class Bad(data: Bits[Int] <> VAL) extends Struct
+```
+///
+
+## DFHDL Value Types
+
+### `Bit`/`Boolean` {#DFBitOrBool}
`Bit` DFHDL values represent binary `1` or `0` values, whereas `Boolean` DFHDL values represent `true` or `false` values, respectively. The `Bit` and `Boolean` DFHDL values are generally interchangeable, and automatically converted between one and the other.
@@ -594,11 +631,11 @@ Although they are interchangeable, it's generally recommended to use `Boolean` D
///
/// details | Why have both `Bit` and `Boolean` DFTypes?
- type: note
+ type: note
The main reason to differentiate between `Bit` and `Boolean` is that VHDL has both `std_logic` and `boolean` types, respectively. Verilog has only a single `logic` or `wire` to represent both. Indeed VHDL'2008 has relaxed some of the type constraints, but not enough. And nevertheless, DFHDL aims to support various HDL dialects, and thus enables simple implicit or explicit conversion between these two DFType values.
///
-### DFType Constructors
+#### DFType Constructors
Use the `Bit` or `Boolean` objects/types to construct `Bit` or `Boolean` DFHDL values, respectively.
@@ -609,7 +646,10 @@ val c_bit: Bit <> CONST = 1
val c_bool: Boolean <> CONST = false
```
-### Candidates
+#### Type Signatures
+`Bit` and `Boolean` have no size parameter. Type signatures: `Bit <> CONST`, `Bit <> VAL`, `Boolean <> VAL`, etc.
+
+#### Candidates
* DFHDL `Bit` values.
* DFHDL `Boolean` values.
@@ -648,209 +688,31 @@ val TrueVal: Boolean = 1
bool := TrueVal
```
-### Operations
-
-#### Explicit Casting Operations
-
-These operations propagate constant modifiers, meaning that if the casted argument is a constant, the returned value is also a constant.
-
-/// html | div.operations
-| Operation | Description | LHS Constraints | Returns |
-| ----------- | --------------------------------|-----------------------|-----------------------|
-| `lhs.bool` | Cast to a DFHDL `Boolean` value | `Bit` DFHDL value | `Boolean` DFHDL value |
-| `lhs.bit` | Cast to a DFHDL `Bit` value | `Boolean` DFHDL value | `Bit` DFHDL value |
-///
-
-```scala
-val bt1 = Bit <> VAR
-val bl1 = bt1.bool
-val bl2 = Boolean <> VAR
-val bt2 = bl2.bit
-val bt3: Bit <> CONST = 0
-val bl3: Boolean <> CONST = bt3.bool
-val bl4: Boolean <> CONST = true
-val bt4: Bit <> CONST = bt4.bit
-// error: bt1 is not a constant
-val err: Bit <> CONST = bt1
-```
-
-#### Bit History Operations
-
-Currently these operations are only supported under ED domains. However, in upcoming DFHDL updates, support will be added across all domain abstractions.
-
-/// html | div.operations
-| Operation | Description | LHS Constraints | Returns |
-| ------------ | --------------------------------|-----------------------|-----------------------|
-| `lhs.rising` | True when a value changes from `0` to `1` | `Bit` DFHDL value | `Boolean` DFHDL value |
-| `lhs.falling` | True when a value changes from `1` to `0` | `Bit` DFHDL value | `Boolean` DFHDL value |
-///
-
-```scala
-class Foo extends EDDesign:
- val clk = Bit <> IN
-
- /* VHDL-style */
- process(clk):
- if (clk.rising)
- //some sequential logic
-
- /* Verilog-style */
- process(clk.rising):
- //some sequential logic
-```
-
-/// details | Transitioning from Verilog
- type: verilog
-Under the ED domain, the `x.rising` and `x.falling` operations are equivalent to the Verilog `posedge x` and `negedge x`, respectively.
-In future releases these operations will have an expanded functionality under the other design domains.
-///
-
-/// details | Transitioning from VHDL
- type: vhdl
-Under the ED domain, the `x.rising` and `x.falling` operations are equivalent to the VHDL `rising_edge(x)` and `falling_edge(x)`, respectively.
-In future releases these operations will have an expanded functionality under the other design domains.
-///
-
-For more information see either the [design domains][design-domains] or [processes][processes] sections.
-
-#### Logical Operations
-
-Logical operations' return type always match the LHS argument's type.
-These operations propagate constant modifiers, meaning that if all arguments are constant, the returned value is also a constant.
-
-/// html | div.operations
-| Operation | Description | LHS/RHS Constraints | Returns |
-| ------------ | ----------- | ------------------- | ------- |
-| `lhs && rhs` | Logical AND | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
-| `lhs || rhs` | Logical OR | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
-| `lhs ^ rhs` | Logical XOR | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
-| `!lhs` | Logical NOT | The argument must be a `Bit`/`Boolean` DFHDL value. | LHS-Type DFHDL value |
-///
-
-```scala
-val bt = Bit <> VAR
-val bl = Boolean <> VAR
-val t1 = bt && bl //result type: Bit
-val t2 = bt ^ 1 //result type: Bit
-val t3 = bl || false //result type: Boolean
-val t4 = bt && true //result type: Bit
-val t5 = bl || bt //result type: Boolean
-val t6 = bl ^ 0 || !bt
-//`t7` after the candidate implicit
-//conversions, looks like so:
-//(bl && bt.bool) ^ (!(bt || bl.bit)).bool
-val t7 = (bl && bt) ^ !(bt || bl)
-//error: swap argument positions to have
-//the DFHDL value on the LHS.
-val e1 = 0 ^ bt
-//error: swap argument positions to have
-//the DFHDL value on the LHS.
-val e2 = false ^ bt
-//not supported since both arguments
-//are just candidates
-val e3 = 0 ^ true
-//This just yields a Scala Boolean,
-//as a basic operation between Scala
-//Boolean values.
-val sc: Boolean = true && true
-```
-
-/// details | Transitioning from Verilog
- type: verilog
-Under the ED domain, the following operations are equivalent:
-
-| DFHDL Operation | Verilog Operation |
-|-----------------|-------------------|
-| `lhs && rhs` | `lhs & rhs` |
-| `lhs || rhs` | `lhs | rhs` |
-| `lhs ^ rhs` | `lhs ^ rhs` |
-| `!lhs` | `!lhs` |
-///
-
-/// details | Transitioning from VHDL
- type: vhdl
-Under the ED domain, the following operations are equivalent:
-
-| DFHDL Operation | VHDL Operation |
-|-----------------|-------------------|
-| `lhs && rhs` | `lhs and rhs` |
-| `lhs || rhs` | `lhs or rhs` |
-| `lhs ^ rhs` | `lhs xor rhs` |
-| `!lhs` | `not lhs` |
-///
-
-#### Constant Meta Operations
-
-These operations are activated during the [elaboration stage][elaboration] of the DFHDL compilation, and are only available for constant `Bit`/`Boolean` DFHDL values.
-Their use case is for meta-programming purposes, to control the generated code without the knowledge of the DFHDL compiler (could be considered as pre-processing steps).
-
-/// html | div.operations
-| Operation | Description | LHS Constraints | Returns |
-| ------------ | ----------- | ------------------- | ------- |
-| `lhs.toScalaBitNum` | Extracts the known elaboration Scala `BitNum`(`1 | 0`) value from a constant DFHDL `Bit`/`Boolean` value | Constant `Bit`/`Boolean` DFHDL value | Scala `BitNum` value |
-| `lhs.toScalaBoolean` | Extracts the known elaboration Scala `Boolean` value from a constant DFHDL `Bit`/`Boolean` value | Constant `Bit`/`Boolean` DFHDL value | Scala `Boolean` value |
-///
-
-The following runnable example demonstrates how such meta operation affect the elaborated design.
-The `Boolean` argument `arg` of a design `Foo` is used twice within the design:
-first, in an `if` condition directly; and second, in an `if` condition after a Scala value extraction.
-When referenced directly, the `if` is elaborated as-is, but when the `if` is applied on the extracted Scala value,
-the `if` is completely removed and either the block inside the `if` is elaborated when the argument is true or completely removed if false.
-
-/// tab | `Foo`
-```scala
-class Foo(
- val arg: Boolean <> CONST
-) extends DFDesign:
- val o = Bit <> OUT
- if (!arg) o := 1
- if (arg.toScalaBoolean) o := 0
-```
-///
-
-
-/// tab | `Foo(true)`
+/// admonition | `Bit` variables accept `Boolean` comparison values as condidates
+ type: note
+All comparison operators (`==`, `!=`, `<`, `>`, `<=`, `>=`) return `Boolean`, and can be directly assigned to `Bit` variables:
```scala
-class Foo(
- val arg: Boolean <> CONST
-) extends DFDesign:
- val o = Bit <> OUT
- if (!arg) o := 1
- o := 0
+class Foo extends RTDesign:
+ val limit = UInt(8) <> IN
+ val counter = UInt(8) <> VAR.REG init 0
+ val tick = Bit <> OUT
+ tick := counter == limit // Implicit Boolean -> Bit conversion
```
///
-/// tab | `Foo(false)`
+/// admonition | `if` and `while` conditionals accept both `Boolean` and `Bit` values
+ type: note
+`if` and `while` conditional expression and statements accept both `Boolean` and `Bit` values (no conversion is taking place). In stricter backends like `vhdl.v93`, an automatic conversion is applied `Boolean` where needed.
```scala
-class Foo(
- val arg: Boolean <> CONST
-) extends DFDesign:
- val o = Bit <> OUT
- if (!arg) o := 1
-```
-///
-
-/// details | Runnable example
- type: dfhdl
-```scastie
-import dfhdl.*
-
-@top(false) class Foo(
- val arg: Boolean <> CONST
-) extends DFDesign:
- val o = Bit <> OUT
- if (!arg) o := 1
- if (arg.toScalaBoolean) o := 0
-
-@main def main =
- println("Foo(true) Elaboration:")
- Foo(true).printCodeString
- println("Foo(false) Elaboration:")
- Foo(false).printCodeString
+class Foo extends RTDesign:
+ val tick = Bit <> IN
+ if (tick) // if condition accepts both Bit and Boolean values
+ //do something
+ end if
```
///
-## `Bits` DFHDL Values {#DFBits}
+### `Bits` {#DFBits}
`Bits` DFHDL values represent vectors of DFHDL `Bit` values as elements.
The vector bits width (length) is a positive constant number (nilable [zero-width] vectors will be supported in the future).
@@ -864,7 +726,7 @@ in their implementations and externally in their API. Where applicable, both `Bi
vector of `Bits` have overlapping equivalent APIs.
///
-### DFType Constructors
+#### DFType Constructors
/// html | div.operations
| Constructor | Description | Arg Constraints | Returns |
@@ -899,11 +761,16 @@ val b6: Bits[6] <> CONST = all(0)
* __Additional constructors:__ DFHDL provides additional constructs to simplify some common VHDL bit vector declaration. For example, instead of declaring `signal addr: std_logic_vector(clog2(DEPTH)-1 downto 0)` in VHDL, in DFHDL simply declare `val addr = Bits.until(DEPTH) <> VAR`.
///
-### Literal (Constant) Value Generation
+#### Type Signatures
+- Bounded: `Bits[8]`, `Bits[4]`
+- Parameterized bounded: `Bits[w.type]` (where `w: Int <> CONST`)
+- Unbounded: `Bits[Int]`
+
+#### Literal (Constant) Value Generation
Literal (constant) DFHDL `Bits` value generation is carried out through [binary][b-interp] and [hexadecimal][h-interp] string interpolation, a core [Scala feature](https://docs.scala-lang.org/scala3/book/string-interpolation.html){target="_blank"} that was customized for DFHDL's exact use-case. There are also bit-accurate [decimal][d-interp] and [signed decimal][sd-interp] interpolations available that produce `UInt` and `SInt` DFHDL values. If needed, those values can be cast to `Bits`. No octal interpolation is currently available or planned.
-#### Binary Bits String-Interpolator {#b-interp}
+##### Binary Bits String-Interpolator {#b-interp}
```scala linenums="0" title="Binary Bits string-interpolation syntax"
b"width'bin"
@@ -947,7 +814,7 @@ This interpolation covers the Verilog binary literal use-cases, but also adds th
This interpolation covers the VHDL binary literal use-cases, but also adds the ability for parametric `width` to be set. The high impedance (high-Z) use-cases will be supported in the future, likely using a different language construct.
///
-#### Hexadecimal Bits String-Interpolator {#h-interp}
+##### Hexadecimal Bits String-Interpolator {#h-interp}
```scala linenums="0" title="Hexadecimal Bits string-interpolation syntax"
h"width'hex"
@@ -993,12 +860,12 @@ This interpolation covers the Verilog hexadecimal literal use-cases, but also ad
This interpolation covers the VHDL hexadecimal literal use-cases, but also adds the ability for parametric `width` to be set. The high impedance (high-Z) use-cases will be supported in the future, likely using a different language construct.
///
-### Candidates
+#### Candidates
* DFHDL `Bits` values
* DFHDL `Bit` or `Boolean` values. This candidate produces a single bit `Bits[1]` vector.
* DFHDL `UInt` values
* Scala `Tuple` combination of any DFHDL values and `1`/`0` literal values. This candidate performs bit concatenation of all values, according their order in the tuple, encoded from the most-significant value position down to the least-significant value position.
- * Application-only candidate - Same-Element Vector (`all(elem)`).
+ * Application-only candidate - Same-Element Vector (`all(elem)`).
```scala
val b8 = Bits(8) <> VAR
@@ -1021,7 +888,22 @@ val s4 = SInt(4) <> VAR
b8 := (1, s4, b1, b"10")
```
-### Concatenated Assignment
+/// admonition | `Bits` does not accept plain integer candidates
+ type: note
+Unlike `UInt`/`SInt`, `Bits` values **cannot** be initialized or assigned with plain integers. Use `all(0)` for zero initialization, or a sized literal:
+```scala
+// CORRECT
+val b8 = Bits(8) <> VAR init all(0) // zero via all(0)
+val b4 = Bits(4) <> VAR init b"4'0" // zero via binary literal
+val b6 = Bits(6) <> VAR init h"6'00" // zero via hex literal
+
+// error: An integer value cannot be a candidate for a Bits type.
+// Try explicitly using a decimal constant via the `d"'"` string interpolation.
+val b16 = Bits(16) <> VAR init 0 // compile error
+```
+///
+
+#### Concatenated Assignment
DFHDL supports a special-case assignment of concatenated DFHDL Bits variables, using a Scala `Tuple` syntax on LHS of the assignment operator. Both LHS and RHS bits width must be the same. This assignment is just syntactic sugar for multiple separate assignments and carried out during the design [elaboration][elaboration]. The assignment ordering is from the first value at most-significant position down to the last value at least-significant position.
/// tab | `Foo Declaration`
@@ -1067,62 +949,43 @@ given options.AppOptions.AppMode = options.AppOptions.AppMode.elaborate
```
///
-## `UInt`/`SInt`/`Int` DFHDL Values {#DFDecimal}
+### `UInt`/`SInt`/`Int` {#DFDecimal}
DFHDL provides three decimal numeric types:
-- `UInt` - Unsigned integer values
-- `SInt` - Signed integer values
-- `Int` - Constant integer values (used mainly for parameters)
-### DFType Constructors
+- `UInt` - Unsigned bit-accurate integer values
+- `SInt` - Signed bit-accurate integer values
+- `Int` - 32-bit integer values (used mainly for parameters)
+
+#### DFType Constructors
/// html | div.operations
| Constructor | Description | Arg Constraints | Returns |
| ------------ | ----------- | ------------------- | ------- |
| `UInt(width)`| Construct an unsigned integer DFType with the given `width` as number of bits. | `width` is a positive Scala `Int` or constant DFHDL `Int` value. | `UInt[width.type]` DFType |
-| `UInt.until(sup)`| Construct an unsigned integer DFType with the given `sup` supremum number the value is expected to reach. The number of bits is set as `clog2(sup)`. | `sup` is a Scala `Int` or constant DFHDL `Int` value larger than 1. | `UInt[CLog2[width.type]]` DFType |
-| `UInt.to(max)`| Construct an unsigned integer DFType with the given `max` maximum number the value is expected to reach. The number of bits is set as `clog2(max+1)`. | `max` is a positive Scala `Int` or constant DFHDL `Int` value. | `UInt[CLog2[width.type+1]]` DFType |
+| `UInt.until(sup)`| Construct an unsigned integer DFType with the given `sup` supremum number the value is expected to reach. The number of bits is set as `clog2(sup)`. | `sup` is a Scala `Int` or constant DFHDL `Int` value **larger than 1**. `UInt.until(1)` is invalid (would produce 0-bit width). | `UInt[CLog2[width.type]]` DFType |
+| `UInt.to(max)`| Construct an unsigned integer DFType with the given `max` maximum number the value is expected to reach. The number of bits is set as `clog2(max+1)`. | `max` is a positive Scala `Int` or constant DFHDL `Int` value. `UInt.to(1)` is valid (produces 1-bit width). | `UInt[CLog2[width.type+1]]` DFType |
| `SInt(width)`| Construct a signed integer DFType with the given `width` as number of bits. | `width` is a positive Scala `Int` or constant DFHDL `Int` value. | `SInt[width.type]` DFType |
| `Int`| Construct a constant integer DFType. Used mainly for parameters. | None | `Int` DFType |
+///
+
+#### Type Signatures
+- Bounded: `UInt[8]`, `SInt[16]`
+- Parameterized bounded: `UInt[w.type]`, `SInt[w.type]` (where `w: Int <> CONST`)
+- Unbounded: `UInt[Int]`, `SInt[Int]`
+- `Int` has no size parameter: `Int <> CONST`, `Int <> VAL`
-### Candidates
+#### Candidates
* DFHDL decimal values of the same type
* DFHDL `Bits` values (via `.uint` or `.sint` casting)
* Scala numeric values (Int, Long, etc.) for constant values
- * Decimal string interpolation values
+ * Decimal literals (string interpolation values)
-### Operations
+#### Constant Generation
-#### Arithmetic Operations
-These operations propagate constant modifiers and maintain proper bit widths:
-
-/// html | div.operations
-| Operation | Description | LHS/RHS Constraints | Returns |
-| ------------ | ----------- | ------------------- | ------- |
-| `lhs + rhs` | Addition | Both decimal types | Result with appropriate width |
-| `lhs - rhs` | Subtraction | Both decimal types | Result with appropriate width |
-| `lhs * rhs` | Multiplication | Both decimal types | Result with width = lhs.width + rhs.width |
-| `lhs / rhs` | Division | Both decimal types | Result with lhs width |
-| `lhs % rhs` | Modulo | Both decimal types | Result with rhs width |
+##### Decimal String-Interpolator {#d-interp}
-#### Comparison Operations
-Return Boolean values:
-
-/// html | div.operations
-| Operation | Description | LHS/RHS Constraints | Returns |
-| ------------ | ----------- | ------------------- | ------- |
-| `lhs < rhs` | Less than | Both decimal types | Boolean |
-| `lhs <= rhs` | Less than or equal | Both decimal types | Boolean |
-| `lhs > rhs` | Greater than | Both decimal types | Boolean |
-| `lhs >= rhs` | Greater than or equal | Both decimal types | Boolean |
-| `lhs == rhs` | Equal | Both decimal types | Boolean |
-| `lhs != rhs` | Not equal | Both decimal types | Boolean |
-
-### Constant Generation
-
-#### Decimal String-Interpolator {#d-interp}
-
-The decimal string interpolator `d` creates unsigned/signed integer constants (`UInt`) from decimal values.
+The decimal string interpolator `d` creates unsigned/signed integer constants (`UInt`) from decimal values.
```scala linenums="0" title="Decimal string-interpolation syntax"
d"width'dec"
@@ -1146,7 +1009,7 @@ d"1,023" // UInt[10], value = 1023
d"1_000" // UInt[10], value = 1000
```
-#### Signed Decimal String-Interpolator {#sd-interp}
+##### Signed Decimal String-Interpolator {#sd-interp}
The signed decimal string interpolator `sd` creates signed integer constants (`SInt`) from decimal values.
@@ -1170,7 +1033,7 @@ sd"8'42" // SInt[8], value = 42
sd"8'255" // Error: width too small to represent value with sign bit
```
-### Examples
+#### Examples
```scala
// Basic declarations
@@ -1192,18 +1055,21 @@ val u4 = UInt(4) <> VAR init d"4'10"
val s4 = SInt(4) <> VAR init sd"4'-2"
```
-## Enumeration DFHDL Values {#DFEnum}
+### Enumeration {#DFEnum}
DFHDL supports enumerated types through Scala's enum feature with special encoding traits. Enums provide a type-safe way to represent a fixed set of values.
-### Enum Type Definition
+#### Enum Type Definition
```scala
enum MyEnum extends Encoded:
case A, B, C, D
```
-### Encoding Types
+#### Type Signatures
+`MyEnum <> VAL`, `MyEnum <> CONST`. The enum name itself is the type — no size parameter.
+
+#### Encoding Types
DFHDL supports several encoding schemes for enums:
@@ -1239,17 +1105,9 @@ enum MyEnum(val value: UInt[8] <> CONST) extends Encoded.Manual(8):
case C extends MyEnum(50)
```
-### Operations
+ Note: the Manual encoding enum class **must** declare a constructor parameter `(val value: UInt[N] <> CONST)` and the bit width `N` must match the argument to `Encoded.Manual(N)`. Each `case` must explicitly extend the enum class and pass a constant value. Omitting the constructor parameter will cause a compile error.
-/// html | div.operations
-| Operation | Description | LHS/RHS Constraints | Returns |
-| ------------ | ----------- | ------------------- | ------- |
-| `lhs == rhs` | Equality comparison | Same enum type | Boolean |
-| `lhs != rhs` | Inequality comparison | Same enum type | Boolean |
-| `lhs.bits` | Get raw bits representation | Enum value | Bits |
-| `lhs.uint` | Get unsigned int representation | Enum value | UInt |
-
-### Pattern Matching
+#### Pattern Matching
Enums can be used in pattern matching expressions:
@@ -1262,7 +1120,7 @@ state match
case MyEnum.C => // handle C
```
-### Examples
+#### Examples
```scala
// State machine enum
@@ -1283,11 +1141,11 @@ class CPU extends RTDesign:
// Store state logic
```
-## Vector DFHDL Values {#DFVector}
+### Vector {#DFVector}
DFHDL vectors allow creating arrays of any DFHDL type. Unlike `Bits` which is specialized for bit vectors, generic vectors can hold any DFHDL type and support multi-dimensional arrays.
-### Vector Type Construction
+#### Vector Type Construction
The vector type is constructed using the `X` operator between a base type and dimension:
@@ -1302,7 +1160,13 @@ val vec2 = Bit X 8 X 8 <> VAR // 2D 8x8 vector of bits
val vec3 = MyEnum X 16 <> VAR // Vector of 16 enum values
```
-### Initialization
+#### Type Signatures
+- Bounded: `UInt[8] X 4`, `Bits[8] X 4 X 4`
+- Parameterized bounded: `UInt[4] X len.type` (where `len: Int <> CONST`)
+- Unbounded: `Bits[8] X Int`
+- Both element type and dimensions can be parameterized independently
+
+#### Initialization
Vectors can be initialized in several ways:
@@ -1317,26 +1181,7 @@ val vec2 = UInt(8) X 4 <> VAR init Vector(1, 2, 3, 4)
val mem = UInt(32) X 1024 <> VAR initFile "mem.hex"
```
-### Operations
-
-#### Element Access
-Access individual elements using array indexing:
-
-```scala
-val elem = vec(idx) // Read element at index
-vec(idx) := newValue // Write element at index
-```
-
-#### Vector-wide Operations
-
-/// html | div.operations
-| Operation | Description | Returns |
-| ------------ | ----------- | ------- |
-| `vec.elements` | Get all elements as Scala sequence | Seq[BaseType] |
-| `vec.size` | Get vector dimension | Int |
-| `vec.bits` | Get bits representation | Bits |
-
-### Multi-dimensional Vectors
+#### Multi-dimensional Vectors
Multi-dimensional vectors are created by chaining `X` operators:
@@ -1352,7 +1197,7 @@ matrix(1)(2) := 42
matrix := all(all(0)) // All elements to 0
```
-### Memory/RAM Implementation
+#### Memory/RAM Implementation
Vectors are commonly used to implement memories and RAMs:
@@ -1368,7 +1213,7 @@ class RAM extends RTDesign:
data := mem(addr) // Read
```
-### File Initialization
+#### File Initialization
Vectors support initialization from files in various formats:
@@ -1380,11 +1225,11 @@ val rom = UInt(8) X 256 <> VAR initFile("rom.hex", InitFileFormat.VerilogHex)
val ram = UInt(32) X 1024 <> VAR initFile "ram.bin"
```
-## Struct DFHDL Values {#DFStruct}
+### Struct {#DFStruct}
DFHDL structures allow creating composite types by combining multiple DFHDL values into a single type. Structs are defined using Scala case classes that extend the `Struct` trait.
-### Struct Type Definition
+#### Struct Type Definition
```scala
case class MyStruct(
@@ -1394,7 +1239,10 @@ case class MyStruct(
) extends Struct
```
-### Field Access and Assignment
+#### Type Signatures
+`MyStruct <> VAL`, `MyStruct <> CONST`. The struct name is the type. Struct fields must use bounded types (no `UInt[Int]` in fields).
+
+#### Field Access and Assignment
Fields are accessed using dot notation and can be assigned individually:
@@ -1405,7 +1253,7 @@ s.field2 := b"1010" // Assign bits
s := MyStruct(1, b"0101", true) // Assign whole struct
```
-### Nested Structs
+#### Nested Structs
Structs can be nested to create more complex data structures:
@@ -1418,16 +1266,7 @@ rect.topLeft.x := 0
rect.bottomRight.y := 100
```
-### Operations
-
-/// html | div.operations
-| Operation | Description | LHS/RHS Constraints | Returns |
-| ------------ | ----------- | ------------------- | ------- |
-| `lhs == rhs` | Equality comparison | Same struct type | Boolean |
-| `lhs != rhs` | Inequality comparison | Same struct type | Boolean |
-| `lhs.bits` | Get raw bits representation | Struct value | Bits |
-
-### Pattern Matching
+#### Pattern Matching
Structs support pattern matching for field extraction:
@@ -1438,7 +1277,7 @@ point match
case Point(0, _) => // Match x=0, any y
```
-### Examples
+#### Examples
```scala
// AXI-like interface struct
@@ -1460,17 +1299,20 @@ class MyDesign extends RTDesign:
axi.data := h"DEADBEEF"
```
-## Tuple DFHDL Values {#DFTuple}
+### Tuple {#DFTuple}
DFHDL tuples provide a way to group multiple DFHDL values together without defining a named structure. They are similar to Scala tuples but operate on DFHDL values.
-### Tuple Type Construction
+#### Tuple Type Construction
```scala
val tuple = (Type1, Type2, ..., TypeN) <> Modifier
```
-### Examples
+#### Type Signatures
+`(UInt[8], Bit) <> VAL`, `(Bits[Int], Bit) <> CONST`. Elements can be individually bounded or unbounded.
+
+#### Examples
```scala
// Basic tuple declaration
@@ -1484,7 +1326,7 @@ pair := (42, 1)
complex := ((100, 0), b"1010")
```
-### Element Access
+#### Element Access
Tuple elements can be accessed using ._N notation or pattern matching:
@@ -1496,20 +1338,11 @@ val second = pair._2 // Access second element
val (x, y) = pair
```
-### Operations
-
-/// html | div.operations
-| Operation | Description | Returns |
-| ------------ | ----------- | ------- |
-| `tuple.bits` | Get bits representation | Bits |
-| `tuple == other` | Equality comparison | Boolean |
-| `tuple != other` | Inequality comparison | Boolean |
-
-## Opaque DFHDL Values {#DFOpaque}
+### Opaque {#DFOpaque}
Opaque types allow creating new DFHDL types that wrap existing types while hiding their internal representation. This is useful for creating abstraction layers and type-safe interfaces.
-### Opaque Type Definition
+#### Opaque Type Definition
```scala
// Define opaque type wrapping UInt(8)
@@ -1522,7 +1355,10 @@ case class Counter() extends Opaque(UInt(32)):
(c.actual + 1).as(Counter)
```
-### Usage
+#### Type Signatures
+`MyOpaque <> VAL`, `MyOpaque <> CONST`. The opaque name is the type.
+
+#### Usage
```scala
val op = MyOpaque <> VAR
@@ -1530,7 +1366,7 @@ val wrapped: UInt[8] <> VAL = op.actual // Access wrapped value
op := 42.as(MyOpaque) // Assign using .as conversion
```
-### Examples
+#### Examples
```scala
// AES byte type with custom operations
@@ -1547,42 +1383,24 @@ class AESCircuit extends DFDesign:
out := in1 + in2 // Uses custom + operation
```
-## Double DFHDL Values {#DFDouble}
+### Double {#DFDouble}
DFHDL Double values represent IEEE-754 double-precision floating-point numbers.
-### Type Construction
+#### Type Construction
```scala
val d = Double <> Modifier
```
-### Operations
-
-Supports standard arithmetic operations:
-
-```scala
-val d1 = Double <> VAR
-val d2 = Double <> VAR
-
-val sum = d1 + d2
-val prod = d1 * d2
-val quot = d1 / d2
-val comp = d1 < d2
-```
-
-### Conversion
-
-```scala
-val bits = d1.bits // Get bits representation
-val d3 = bits.as(Double) // Convert back to Double
-```
+#### Type Signatures
+`Double <> VAL`, `Double <> CONST`. No size parameter (always 64 bits).
-## Time/Freq DFHDL Values {#DFPhysical}
+### Time/Freq {#DFPhysical}
DFHDL provides special types for representing time and frequency values in hardware designs through physical units. These types help ensure correct timing specifications and frequency calculations.
-### Time Values
+#### Time Values
Time values can be created using various unit suffixes:
@@ -1604,7 +1422,7 @@ val t9 = 1.5.ns // 1.5 nanoseconds
val t10 = 10.ms // 10 milliseconds
```
-### Frequency Values
+#### Frequency Values
Frequency values can be specified using standard frequency units:
@@ -1622,7 +1440,7 @@ val f5 = 100.MHz // 100 megahertz
val f6 = 2.5.GHz // 2.5 gigahertz
```
-### Usage in RT Domains
+#### Usage in RT Domains
Physical values are particularly useful when configuring RT domains and specifying clock frequencies:
@@ -1641,7 +1459,7 @@ class TimingExample extends RTDesign:
val clockFreq = 1.GHz // Clock frequency
```
-### Cycles in RT Domain
+#### Cycles in RT Domain
In RT domains, you can also specify cycle counts using the `.cy` unit:
@@ -1652,11 +1470,11 @@ class RTExample extends RTDesign:
Note: The `.cy` unit is only available within register-transfer (RT) domains.
-## Unit (Void) DFHDL Values {#DFUnit}
+### Unit (Void) {#DFUnit}
The Unit type in DFHDL represents a void or no-value type, similar to Scala's Unit type. It's typically used when an operation doesn't need to return a meaningful value.
-### Usage
+#### Usage
```scala
// Method returning Unit
@@ -1669,7 +1487,7 @@ val x = Bit <> VAR
val y: Unit <> VAL = x := 1
```
-### Common Use Cases
+#### Common Use Cases
1. Side-effect operations
2. Void method returns
@@ -1684,3 +1502,905 @@ class Example extends EDDesign:
// Process body returns Unit
doSomething
```
+## Operations
+
+### Conversions and Casts {#type-conversion}
+The diagram below shows the conversion/cast paths between DFHDL types. Solid arrows are simple casts that preserve width; dashed arrows involve width changes.
+
+{ width="70%" }
+{ width="70%" }
+
+/// html | div.conversion
+| From | To | Method | From | To | Method |
+|------|-----|--------|------|-----|--------|
+| `T` | `Bits` | `.bits` | `Bit` | `Boolean` | `.bool` |
+| `Bits` | `T` | `.as(T)` | `Boolean` | `Bit` | `.bit` |
+| `Bits(w)` | `UInt(w)` | `.uint` | `Bit`/`Boolean` | `Bits(1)` | `.bits` |
+| `Bits(w)` | `SInt(w)` | `.sint` | `Bit`/`Boolean` | `Bits(w)` | `.toBits(w)` |
+| `UInt(w)` | `SInt(w+1)` | `.signed` | `Bit`/`Boolean` | `UInt(w)` | `.toUInt(w)` |
+| `UInt`/`SInt` | `Int` | `.ToInt` | `Bit`/`Boolean` | `SInt(w)` | `.toSInt(w)` |
+///
+
+#### Any Type to/from `Bits`: `.bits` and `.as(T)` {#bits-cast}
+
+Every DFHDL type can be converted to its raw bit representation with `.bits`. The inverse operation, `.as(T)`, reinterprets a `Bits` value as a target type `T`, provided the bit widths match exactly:
+
+```scala
+val u8 = UInt(8) <> VAR
+val b8 = u8.bits // UInt(8) -> Bits(8)
+val back = b8.as(UInt(8)) // Bits(8) -> UInt(8)
+```
+
+This also works with composite types such as enums, structs, and opaques:
+
+```scala
+val e = MyEnum <> VAR
+val eBits = e.bits // Enum -> Bits
+val eBack = eBits.as(MyEnum) // Bits -> Enum
+```
+
+#### `Bits` to `UInt`/`SInt`: `.uint` and `.sint` {#uint-sint-cast}
+
+These are shorthand conversions from `Bits` that preserve width. The same bits are simply reinterpreted as unsigned or signed:
+
+```scala
+val b8 = Bits(8) <> VAR
+val u8 = b8.uint // Bits(8) -> UInt(8), same bit pattern
+val s8 = b8.sint // Bits(8) -> SInt(8), same bit pattern
+```
+
+#### `UInt` to `SInt`: `.signed` {#signed-cast}
+
+Converting an unsigned value to signed requires an extra bit for the sign, so `.signed` widens the result by one bit:
+
+```scala
+val u8 = UInt(8) <> VAR
+val s9 = u8.signed // UInt(8) -> SInt(9)
+```
+
+To get an `SInt` with the **same** width (reinterpreting the bit pattern without expanding), go through `Bits`:
+
+```scala
+val s8 = u8.bits.sint // UInt(8) -> Bits(8) -> SInt(8)
+```
+
+#### `Bit` and `Boolean` Conversions {#bit-bool-cast}
+
+`Bit` is the hardware single-bit type and `Boolean` is the logical type. They are convertible to each other with `.bit` and `.bool`:
+
+```scala
+val myBit = Bit <> VAR
+val myBool = myBit.bool // Bit -> Boolean
+val back = myBool.bit // Boolean -> Bit
+```
+
+Both `Bit` and `Boolean` can be widened (zero-extended) into `Bits`, `UInt`, or `SInt` with an explicit target width:
+
+```scala
+val flag = Bit <> VAR
+val b4 = flag.toBits(4) // Bit -> Bits(4)
+val u4 = flag.toUInt(4) // Bit -> UInt(4)
+val s4 = flag.toSInt(4) // Bit -> SInt(4)
+```
+
+When the value is `1`, these produce the value `1` at the given width (not sign-extended). The single-bit `.bits` conversion is also available, returning `Bits(1)`.
+
+#### Enum to `UInt`: `.uint` {#enum-uint-cast}
+
+Enum values can be converted to their underlying unsigned integer representation:
+
+```scala
+val e = MyEnum <> VAR
+val u = e.uint // Enum -> UInt (encoding-dependent width)
+```
+
+### Bit Selection and Slicing {#common-bit-vector-ops}
+
+Applies to: `Bits`, `UInt`, `SInt`
+
+- **Range slice**: `value(hi, lo)` extracts bits `hi` down to `lo`, returning a narrower value of the **same type** (`Bits` → `Bits`, `UInt` → `UInt`, `SInt` → `SInt`).
+- **Single-bit access**: `value(idx)` returns the bit at position `idx` (as `Bit`). The index can be a static integer or a dynamic `UInt` variable.
+
+```scala
+val b8 = Bits(8) <> VAR
+val u8 = UInt(8) <> VAR
+val s8 = SInt(8) <> VAR
+
+// Range slicing — preserves the original type
+val b4 = b8(7, 4) // Bits[4]: upper nibble
+val u4 = u8(3, 0) // UInt[4]: lower nibble
+val s4 = s8(3, 0) // SInt[4]: lower nibble
+
+// Single-bit access
+val msb = b8(7) // Bit
+val lsb = u8(0) // Bit
+
+// Dynamic bit access (index is a UInt variable)
+val idx = UInt(3) <> VAR
+val dynbit = b8(idx) // Bit at position idx
+```
+
+/// admonition | Dynamic bit indexing
+ type: tip
+You can index into a bit-vector value using a `UInt` variable, not just integer literals. The index must be a `UInt` whose width equals `clog2(bits_width)`. For example, indexing into `Bits(8)` requires a `UInt(3)` index. If the width does not match, the compiler will report an error and suggest using `.truncate` (to narrow) or `.extend` (to widen).
+
+Dynamic indexing works for both reads and writes:
+```scala
+val data = Bits(8) <> VAR init all(0)
+val pos = UInt(3) <> VAR init 0
+val din = Bit <> IN
+
+val bit_out = data(pos) // dynamic read
+process(clk):
+ if (clk.rising)
+ data(pos) :== din // dynamic write
+```
+
+When the index variable is wider than needed, use `.truncate` to automatically narrow it to the required width:
+```scala
+val data = Bits(8) <> VAR init all(0)
+val pos = UInt(4) <> VAR init 0 // 4-bit, but Bits(8) needs UInt(3)
+val bit_out = data(pos.truncate) // .truncate narrows to UInt(3) automatically
+```
+///
+
+### Width Adjustment {#width-adjustment}
+
+Applies to: `Bits`, `UInt`, `SInt`
+
+- `.resize(N)` sets the width to exactly `N` bits. For `UInt` and `Bits`, widening zero-extends; for `SInt`, widening sign-extends. Narrowing truncates the most-significant bits.
+- `.truncate` automatically narrows to the width expected by the assignment or operation context.
+- `.extend` automatically widens to the width expected by the context.
+
+```scala
+val b8 = Bits(8) <> VAR
+val b4 = Bits(4) <> VAR
+b4 := b8.resize(4) // truncate to 4 bits
+b8 := b4.extend // auto-widen to match b8's width
+
+val u8 = UInt(8) <> VAR
+val u6 = UInt(6) <> VAR
+u6 := u8.truncate // auto-narrow to match u6's width
+u8 := u6.resize(8) // explicit zero-extend to 8 bits
+
+val s8 = SInt(8) <> VAR
+val s4 = SInt(4) <> VAR
+s8 := s4.extend // sign-extend to match s8's width
+s4 := s8.resize(4) // truncate to 4 bits
+```
+
+/// admonition | `.truncate` is not `.resize(N)` -- do not pass an argument to `.truncate`
+ type: warning
+`.truncate` (no argument) narrows the width to match the assignment context. There is no `.truncate(N)` method. Writing `expr.truncate(N)` is parsed by Scala as `expr.truncate` followed by `(N)`, which applies bit selection on the truncated result -- selecting a single bit at index `N`. This causes confusing errors like "argument must be smaller than the upper-bound". To keep the lowest `N` bits, use `.resize(N)`:
+
+```scala
+val b8 = Bits(8) <> VAR
+val b4 = Bits(4) <> VAR
+b4 := b8.truncate // OK: auto-narrow from 8 to 4 bits
+b4 := b8.resize(4) // OK: explicit narrow to 4 bits
+// b8.truncate(4) // MISLEADING: this is b8.truncate followed by bit-select (4)
+```
+///
+
+### Bit Concatenation {#bit-concat}
+
+Applies to: `Bits`, `UInt`, `SInt`
+
+Multiple bit-vector values can be concatenated using Scala tuple syntax with `.toBits`:
+
+```scala
+val concat = (b"100", b"1", b"0", b"11").toBits // Bits[8]
+val u8 = UInt(8) <> VAR
+val u4 = UInt(4) <> VAR
+val wide = (u8, u4).toBits // Bits[12]
+```
+
+Values are concatenated from the first (most-significant) to the last (least-significant) position.
+
+### Logical Operations {#logical-ops}
+
+Applies to: `Bit`, `Boolean`
+
+Logical operations' return type always matches the LHS argument's type.
+These operations propagate constant modifiers, meaning that if all arguments are constant, the returned value is also a constant.
+
+/// html | div.operations
+| Operation | Description | LHS/RHS Constraints | Returns |
+| ------------ | ----------- | ------------------- | ------- |
+| `lhs && rhs` | Logical AND | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
+| `lhs || rhs` | Logical OR | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
+| `lhs & rhs` | Logical AND | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
+| `lhs | rhs` | Logical OR | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
+| `lhs ^ rhs` | Logical XOR | The LHS argument must be a `Bit`/`Boolean` DFHDL value. The RHS must be a `Bit`/`Boolean` candidate. | LHS-Type DFHDL value |
+| `!lhs` | Logical NOT | The argument must be a `Bit`/`Boolean` DFHDL value. | LHS-Type DFHDL value |
+///
+
+```scala
+val bt = Bit <> VAR
+val bl = Boolean <> VAR
+val t1 = bt && bl //result type: Bit
+val t2 = bt ^ 1 //result type: Bit
+val t3 = bl || false //result type: Boolean
+val t4 = bt && true //result type: Bit
+val t5 = bl || bt //result type: Boolean
+val t6 = bl ^ 0 || !bt
+//`t7` after the candidate implicit
+//conversions, looks like so:
+//(bl && bt.bool) ^ (!(bt || bl.bit)).bool
+val t7 = (bl && bt) ^ !(bt || bl)
+//error: swap argument positions to have
+//the DFHDL value on the LHS.
+val e1 = 0 ^ bt
+//error: swap argument positions to have
+//the DFHDL value on the LHS.
+val e2 = false ^ bt
+//not supported since both arguments
+//are just candidates
+val e3 = 0 ^ true
+//This just yields a Scala Boolean,
+//as a basic operation between Scala
+//Boolean values.
+val sc: Boolean = true && true
+```
+
+/// admonition | Logical `||`/`&&` and bitwise `|`/`&` on Bit and Boolean values
+ type: tip
+In DFHDL, the operators `||` and `&&` are equivalent to `|` and `&`, respectively, when applied on either DFHDL `Bit` or `Boolean` types. In Verilog, the actual operator printed depends on the LHS argument of the operation: if it's `Bit`, the operator will be `|`/`&`; if it's `Boolean`, the operator will be `||`/`&&`.
+///
+
+/// details | Transitioning from Verilog
+ type: verilog
+Under the ED domain, the following operations are equivalent:
+
+| DFHDL Operation | Verilog Operation (Bit LHS) | Verilog Operation (Boolean LHS) |
+|-----------------|-----------------------------|---------------------------------|
+| `lhs && rhs` | `lhs & rhs` | `lhs && rhs` |
+| `lhs || rhs` | `lhs | rhs` | `lhs || rhs` |
+| `lhs & rhs` | `lhs & rhs` | `lhs && rhs` |
+| `lhs | rhs` | `lhs | rhs` | `lhs || rhs` |
+| `lhs ^ rhs` | `lhs ^ rhs` | `lhs ^ rhs` |
+| `!lhs` | `!lhs` | `!lhs` |
+///
+
+/// details | Transitioning from VHDL
+ type: vhdl
+Under the ED domain, the following operations are equivalent:
+
+| DFHDL Operation | VHDL Operation |
+|-----------------|-------------------|
+| `lhs && rhs` | `lhs and rhs` |
+| `lhs || rhs` | `lhs or rhs` |
+| `lhs ^ rhs` | `lhs xor rhs` |
+| `!lhs` | `not lhs` |
+///
+
+### Bit Reduction Operations (`.&`, `.|`, `.^`) {#reduction-ops}
+
+Applies to: `Bits`, `UInt` (via implicit conversion to `Bits`)
+
+Reduction operators fold all bits of a `Bits` vector into a single `Bit` value. They are the DFHDL equivalents of Verilog's unary reduction operators (`&v`, `|v`, `^v`):
+
+/// html | div.operations
+| Operation | Description | Returns |
+| --------- | ----------- | ------- |
+| `bits.&` | AND reduction -- `1` if all bits are `1` | `Bit` |
+| `bits.|` | OR reduction -- `1` if any bit is `1` | `Bit` |
+| `bits.^` | XOR reduction -- `1` if an odd number of bits are `1` (parity) | `Bit` |
+///
+
+```scala
+val b8 = Bits(8) <> VAR
+val allSet = b8.& // Bit: 1 when all bits are 1
+val anySet = b8.| // Bit: 1 when at least one bit is 1
+val parity = b8.^ // Bit: 1 when odd number of bits are 1
+```
+
+/// details | Transitioning from Verilog
+ type: verilog
+
+| Verilog | DFHDL | Notes |
+|---------|-------|-------|
+| `&v` (AND reduce) | `v.&` | All bits must be `1` |
+| `|v` (OR reduce) | `v.|` | At least one bit is `1` |
+| `^v` (XOR reduce) | `v.^` | Parity (odd number of `1`s) |
+| `~&v` (NAND reduce) | `!v.&` | Not all bits are `1` |
+| `~|v` (NOR reduce) | `!v.|` | No bits are `1` |
+| `~^v` (XNOR reduce) | `!v.^` | Even parity |
+
+///
+
+### Selection (`.sel`) {#sel-ops}
+
+Condition: `Bit`, `Boolean`. Arguments: any DFHDL type.
+
+The `.sel` operation is a conditional selection — equivalent to Verilog's ternary operator `cond ? onTrue : onFalse`. It selects between two values based on a `Bit` or `Boolean` condition:
+
+/// html | div.operations
+| Operation | Description | Returns |
+| --------- | ----------- | ------- |
+| `cond.sel(onTrue, onFalse)` | Select `onTrue` when `cond` is true/1, `onFalse` otherwise | Same type as the arguments |
+///
+
+The `onTrue` and `onFalse` arguments can be any DFHDL type — `UInt`, `SInt`, `Bits`, `Enum`, `Struct`, etc. They can also be Scala literals constant parameters. The result type is determined by whichever argument is a DFHDL value (the other is auto-converted via type conversion):
+
+```scala
+val flag = Boolean <> VAR
+val u8 = UInt(8) <> VAR
+
+// Select between two literals
+val r1 = flag.sel(11, d"4'12") // UInt[4]: 11 if true, 12 if false
+
+// Select between DFHDL values
+val r2 = flag.sel(u8, d"8'0") // UInt[8]: u8 if true, 0 if false
+
+// Select with Int parameters
+val c1: Int <> CONST = 1
+val c2: Int <> CONST = 2
+val r3 = flag.sel(c1, c2) // Int: c1 if true, c2 if false
+
+// Select with other types
+val e = flag.sel(MyEnum.A, MyEnum.B) // MyEnum
+```
+
+/// admonition | Prefer `if`/`match` for complex conditions
+ type: tip
+For simple one-level selections, `.sel` is concise and maps directly to Verilog's ternary. However, nesting or chaining `.sel` operations (e.g., `a.sel(b.sel(x, y), z)`) quickly becomes unreadable. For complex conditional logic, use `if`/`else` or `match` expressions instead — they are clearer and produce equivalent hardware.
+///
+
+/// details | Transitioning from Verilog
+ type: verilog
+The `.sel` operation compiles to Verilog's ternary operator:
+
+| DFHDL | Verilog |
+|-------|---------|
+| `cond.sel(a, b)` | `cond ? a : b` |
+///
+
+/// details | Transitioning from VHDL
+ type: vhdl
+VHDL has no equivalent to Verilog's ternary expression. The DFHDL-generated VHDL package includes `bool_sel` functions that implement this behavior, with dedicated overloads generated for each type as required.
+
+| DFHDL | Generated VHDL |
+|-------|----------------|
+| `cond.sel(a, b)` | `bool_sel(cond, a, b)` |
+///
+
+### Arithmetic Operations (`+`, `-`, `*`, `/`, `%`) {#arithmetic-ops}
+
+Applies to: `UInt`, `SInt`, `Bits` (via implicit conversion to `UInt`), `Int`, `Double` (`%` not available for `Double`)
+
+/// html | div.decimal_arithmetic
+| Operation | Description | Returns |
+| ------------ | -------------- | ---------------- |
+| `lhs + rhs` | Addition | Same type as LHS |
+| `lhs - rhs` | Subtraction | Same type as LHS |
+| `lhs * rhs` | Multiplication | Same type as LHS |
+| `lhs / rhs` | Division | Same type as LHS |
+| `lhs % rhs` | Modulo | Same type as LHS |
+///
+
+#### Bit-Accurate Type Constraints (`UInt`, `SInt`)
+
+The result of a standard arithmetic operation on bit-accurate types always has the **same type as the LHS** operand. The RHS is resized to match the LHS before the operation is applied.
+
+**Sign rule** -- The LHS sign must be greater than or equal to the RHS sign (`signed >= unsigned`):
+
+/// html | div.operations
+| LHS | RHS | Allowed | Note |
+| --- | --- | ------- | ---- |
+| `UInt[W1]` | `UInt[W2]` | Yes | W1 >= W2 |
+| `SInt[W1]` | `SInt[W2]` | Yes | W1 >= W2 |
+| `SInt[W1]` | `UInt[W2]` | Yes | W1 >= W2 + 1 (RHS is implicitly widened by 1 bit for the sign bit) |
+| `UInt[W1]` | `SInt[W2]` | **No** | Compile error: an explicit conversion is required |
+///
+
+**Width rule** -- The LHS width must be greater than or equal to the (effective) RHS width. When applying `SInt op UInt`, the effective RHS width is `RHS width + 1` because the unsigned value gains an implicit sign bit.
+
+**Scala `Int` literals** are auto-promoted to a matching DFHDL type with the minimum required bit width. A negative `Int` literal on the RHS of a `UInt` operation is a compile error (unsigned LHS cannot accept a signed RHS).
+
+/// admonition | `Bits` values in arithmetic
+ type: tip
+`Bits` values are implicit `UInt` candidates, so they can participate in arithmetic directly. The compiler automatically inserts `.uint` conversions on the operands and `.bits` on the result:
+```scala
+val i = Bits(8) <> IN
+val o = Bits(8) <> OUT
+o := i + i
+```
+Elaborates to:
+```scala
+o := (i.uint + i.uint).bits
+```
+///
+
+```scala
+val u8 = UInt(8) <> VAR
+val u4 = UInt(4) <> VAR
+val s8 = SInt(8) <> VAR
+
+// UInt + UInt (same width)
+val r1 = u8 + u8 // UInt[8]
+// SInt + SInt
+val r2 = s8 + s8 // SInt[8]
+// SInt + UInt: RHS widened to 5 bits (4+1); 8 >= 5, OK
+val r3 = s8 + u4 // SInt[8]
+// UInt + Scala Int literal (200 fits in 8 bits)
+val r4 = u8 + 200 // UInt[8]
+// Scala Int literal on LHS (200 is promoted to UInt[8])
+val r5 = 200 - u8 // UInt[8]
+
+// error: Cannot apply this operation between an unsigned
+// value (LHS) and a signed value (RHS).
+// An explicit conversion must be applied.
+val e1 = u8 + s8
+// error: The applied RHS value width (8) is larger than
+// the LHS variable width (4).
+val e2 = u4 + u8
+// error: Cannot apply this operation between an unsigned
+// value (LHS) and a signed value (RHS).
+// An explicit conversion must be applied.
+val e3 = u8 + (-22)
+
+// Int arithmetic
+val param: Int <> CONST = 10
+val r6 = param * 2 // Int <> CONST = 20
+val r7 = param % 3 // Int <> CONST = 1
+
+// Double arithmetic
+val d1 = Double <> VAR
+val d2 = Double <> VAR
+val r8 = d1 + d2 // Double
+val r9 = d1 / d2 // Double
+```
+
+/// admonition | Overflow and automatic carry promotion
+ type: warning
+Standard arithmetic operations wrap on overflow. For example, `d"8'255" + d"8'1"` produces `d"8'0"`. Use the carry variants (`+^`, `-^`, `*^`) described below to get a wider result that preserves the full value.
+
+However, when an **anonymous** arithmetic expression (`+`, `-`, `*`) is assigned or connected to a variable that is **wider** than the operation's result, the operation is **automatically promoted** to a carry operation. This matches Verilog's behavior where the assignment target width determines the operation width. The carry result is then resized to fit the target if needed.
+
+```scala
+val u8 = UInt(8) <> VAR
+val u9 = UInt(9) <> VAR
+val u12 = UInt(12) <> VAR
+val u16 = UInt(16) <> VAR
+u9 := u8 + u8 // promoted to carry addition (width 9), exact fit
+u16 := u8 * u8 // promoted to carry multiplication (width 16), exact fit
+u12 := u8 * u8 // promoted to carry multiplication (width 16), resized to 12
+
+// Named expressions are NOT promoted:
+val sum = u8 + u8 // UInt[8], named value
+u9 := sum // resized from 8 to 9, no carry promotion
+```
+///
+
+### Carry Arithmetic (`+^`, `-^`, `*^`) {#carry-ops}
+
+Applies to: `UInt`, `SInt`
+
+Carry operations widen the result to prevent overflow. Unlike standard arithmetic, carry operations require both operands to have the **same sign**.
+
+/// html | div.operations
+| Operation | Description | Result Width | Result Sign |
+| ------------- | -------------------- | ------------------ | -------------------- |
+| `lhs +^ rhs` | Carry Addition | max(LW, RW) + 1 | Same sign as operands |
+| `lhs -^ rhs` | Carry Subtraction | max(LW, RW) + 1 | Same sign as operands |
+| `lhs *^ rhs` | Carry Multiplication | LW + RW | Same sign as operands |
+///
+
+```scala
+val u8 = UInt(8) <> VAR
+
+// Carry addition: width = max(8, 8) + 1 = 9
+val r1 = u8 +^ u8 // UInt[9]
+// d"8'255" +^ d"8'1" == d"9'256" (no overflow)
+
+// Carry subtraction: width = max(8, 8) + 1 = 9
+val r2 = u8 -^ u8 // UInt[9]
+
+// Carry multiplication: width = 8 + 8 = 16
+val r3 = u8 *^ u8 // UInt[16]
+
+// Scala Int literal: 100 needs 7 bits
+// width = 7 + 8 = 15
+val r4 = 100 *^ u8 // UInt[15]
+
+val s8 = SInt(8) <> VAR
+val r5 = s8 +^ s8 // SInt[9]
+val r6 = s8 *^ s8 // SInt[16]
+```
+
+/// admonition | Carry vs standard sign rules
+ type: tip
+Unlike standard arithmetic where `SInt op UInt` is allowed (the unsigned RHS is implicitly widened), carry operations require both operands to have the **same sign**. This is because carry operations produce a wider result, and mixed-sign widening semantics would be ambiguous. Scala `Int` literals are still accepted when the literal's sign matches the DFHDL value's sign.
+///
+
+### Comparison Operations (`==`, `!=`, `<`, `>`, `<=`, `>=`) {#comparison-ops}
+
+Applies to: `UInt`, `SInt`, `Int`, `Double` (all comparisons); `Bits`, `Enum`, `Struct`, `Tuple` (`==`/`!=` only)
+
+#### Decimal Comparisons
+
+Comparison operations on `UInt`/`SInt` return a `Boolean` DFHDL value and have **stricter constraints** than arithmetic:
+
+/// html | div.operations
+| Operation | Description | Returns |
+| ------------- | ---------------------- | -------- |
+| `lhs == rhs` | Equal | Boolean |
+| `lhs != rhs` | Not equal | Boolean |
+| `lhs < rhs` | Less than | Boolean |
+| `lhs > rhs` | Greater than | Boolean |
+| `lhs <= rhs` | Less than or equal | Boolean |
+| `lhs >= rhs` | Greater than or equal | Boolean |
+///
+
+Unlike arithmetic operations which use relaxed rules (LHS sign >= RHS sign, LHS width >= RHS width), comparisons require **exact matching**:
+
+- **Sign:** Must match exactly (`UInt` with `UInt`, `SInt` with `SInt`).
+- **Width:** Must match exactly (both operands must have the same bit width).
+- **Scala `Int` literals:** The literal's bit width (adjusted +1 if the DFHDL value is signed and the literal is positive) must fit within the DFHDL value's width.
+
+```scala
+val u8 = UInt(8) <> VAR
+val u4 = UInt(4) <> VAR
+val s8 = SInt(8) <> VAR
+
+val c1 = u8 == u8 // Boolean: same sign, same width
+val c2 = u8 < 200 // Boolean: 200 fits in UInt[8]
+val c3 = 0 < u8 // Boolean: Scala Int on LHS
+val c4 = s8 >= 1 // Boolean: 1 is promoted to SInt (width 2 fits in 8)
+
+// error: Cannot apply this operation between an unsigned
+// value (LHS) and a signed value (RHS).
+// An explicit conversion must be applied.
+val e1 = u8 == s8
+// error: Cannot apply this operation between a value of
+// 8 bits width (LHS) to a value of 4 bits width (RHS).
+// An explicit conversion must be applied.
+val e2 = u8 == u4
+// error: Cannot compare a DFHDL value (width = 8) with a
+// Scala `Int` argument that is wider (width = 10).
+// An explicit conversion must be applied.
+val e3 = u8 > 1000
+```
+
+/// details | Scala `Int` constants auto-lift in comparisons
+ type: note
+Plain Scala `Int` values can be used directly in comparisons and arithmetic with DFHDL typed variables. No explicit coercion is needed:
+```scala
+val LIMIT: Int <> CONST = 5208
+val counter = UInt.until(LIMIT) <> VAR
+if (counter == LIMIT - 1) // Int <> CONST compared with UInt -- works directly
+ counter := 0
+```
+///
+
+#### Bits Comparisons
+
+`Bits` values support `==` and `!=` with other `Bits` values of the same width, with `all(0)`, `all(1)`, or with sized literals (`d"..."`, `h"..."`, `b"..."`). Plain Scala `Int` literals cannot be compared directly with `Bits` -- use a sized literal or convert to `.uint` first:
+
+```scala
+val b8 = Bits(8) <> VAR
+val isAllOnes = b8 == all(1) // Boolean: all bits are 1
+val isAllZeros = b8 == all(0) // Boolean: all bits are 0
+val isMatch = b8 == h"B0" // Boolean: exact match with hex literal
+val isDec = b8 == d"8'12" // Boolean: match with sized decimal
+
+// ERROR: An integer value cannot be a candidate for a Bits type.
+// val bad = b8 == 0
+// FIX: use all(0), a sized literal, or convert to UInt first:
+// b8 == all(0) OR b8 == d"8'0" OR b8.uint == 0
+```
+
+#### Enum, Struct, and Tuple Comparisons
+
+Enums, structs, and tuples support equality comparisons (`==` and `!=`) between values of the same type:
+
+```scala
+val e1 = MyEnum <> VAR
+val e2 = MyEnum <> VAR
+val eq = e1 == e2 // Boolean
+
+val s1 = MyStruct <> VAR
+val s2 = MyStruct <> VAR
+val eq2 = s1 == s2 // Boolean
+
+val t1 = (UInt(8), Bit) <> VAR
+val t2 = (UInt(8), Bit) <> VAR
+val eq3 = t1 == t2 // Boolean
+```
+
+### Shift Operations (`<<`, `>>`) {#shift-ops}
+
+Applies to: `Bits`, `UInt`, `SInt`
+
+/// html | div.operations
+| Operation | Description | LHS/RHS Constraints | Returns |
+| ------------ | ----------- | ------------------- | ------- |
+| `lhs << rhs` | Left shift | LHS: `Bits`/`UInt`/`SInt`, RHS: unsigned or `Int` | Same type as LHS |
+| `lhs >> rhs` | Right shift (logical for `Bits`/`UInt`, arithmetic for `SInt`) | LHS: `Bits`/`UInt`/`SInt`, RHS: unsigned or `Int` | Same type as LHS |
+///
+
+The `>>` operator is **type-aware**: on `UInt` and `Bits` it performs a logical (zero-filling) right shift, and on `SInt` it performs an arithmetic (sign-extending) right shift. There is no separate `>>>` operator in DFHDL -- the operand type determines the behavior.
+
+```scala
+val b = Bits(8) <> VAR
+val u = UInt(8) <> VAR
+val s = SInt(8) <> VAR
+
+val b_shifted = b << 2 // logical left shift
+val u_shifted = u >> 2 // logical right shift (zero-fills MSBs)
+val s_shifted = s >> 2 // arithmetic right shift (sign-extends MSBs)
+```
+
+### Max/Min Operations (`max`, `min`) {#max-min-ops}
+
+Applies to: `Int`, `Double`
+
+/// html | div.operations
+| Operation | Description | Returns |
+| --------------- | ----------- | ------- |
+| `lhs max rhs` | Maximum of two values | Same type |
+| `lhs min rhs` | Minimum of two values | Same type |
+///
+
+```scala
+val param: Int <> CONST = 2
+val t1 = 1 max param // Int <> CONST = 2
+val t2 = 1 min param // Int <> CONST = 1
+
+val d1 = Double <> VAR
+val d2 = Double <> VAR
+val t3 = d1 max d2 // Double
+val t4 = d1 min d2 // Double
+```
+
+### Physical Arithmetic (`Time`, `Freq`) {#physical-ops}
+
+Applies to: `Time`, `Freq`
+
+Physical types follow dimensional analysis rules. Operations between `Time` and `Freq` produce dimensionally correct results.
+
+/// html | div.operations
+| Operation | LHS | RHS | Returns |
+| --------- | --- | --- | ------- |
+| `lhs + rhs` | `Time` | `Time` | `Time` |
+| `lhs - rhs` | `Time` | `Time` | `Time` |
+| `lhs * rhs` | `Time` | Number | `Time` |
+| `lhs * rhs` | `Freq` | Number | `Freq` |
+| `lhs * rhs` | `Time` | `Freq` | Number |
+| `lhs * rhs` | `Freq` | `Time` | Number |
+| `lhs / rhs` | `Time` | Number | `Time` |
+| `lhs / rhs` | `Freq` | Number | `Freq` |
+| `lhs / rhs` | `Time` | `Time` | Number |
+| `lhs / rhs` | `Freq` | `Freq` | Number |
+| `lhs / rhs` | Number | `Time` | `Freq` |
+| `lhs / rhs` | Number | `Freq` | `Time` |
+///
+
+```scala
+val period = 10.ns
+val freq = 100.MHz
+
+// Scaling
+val half_period = period / 2 // Time: 5 ns
+val double_freq = freq * 2 // Freq: 200 MHz
+
+// Dimensional conversions
+val cycles = period * freq // Number: 1.0
+val calc_freq = 1 / period // Freq: 100 MHz
+val calc_period = 1 / freq // Time: 10 ns
+```
+
+/// admonition | Cycle-based waits in RT domains
+ type: tip
+The `.cy` unit creates cycle-count values for use with `.wait` in register-transfer domains:
+```scala
+class Example extends RTDesign:
+ 5.cy.wait // wait 5 clock cycles
+```
+///
+
+### `Int` Parameter Operations (`**`, `clog2`) {#int-param-ops}
+
+Applies to: `Int` (constant parameters)
+
+These operations are available for Scala `Int` or DFHDL `Int <> CONST` values and are primarily used for compile-time calculations such as computing bit widths.
+
+/// html | div.operations
+| Operation | Description | Returns |
+| --------------- | ----------- | ------- |
+| `lhs ** rhs` | Power (exponentiation) | `Int` |
+| `clog2(value)` | Ceiling of log base 2 | `Int` |
+///
+
+```scala
+val param: Int <> CONST = 2
+val t1 = 3 ** param // Int <> CONST = 9
+val t2 = 2 ** param // Int <> CONST = 4
+val w = clog2(256) // Int = 8 (bits needed to represent 0..255)
+```
+
+/// admonition | Avoid using `clog2` directly for widths
+ type: warning
+A common anti-pattern is using `clog2` to declare the width of bit-accurate values:
+```scala
+// DON'T do this:
+val addr = UInt(clog2(DEPTH)) <> VAR
+val mask = Bits(clog2(SIZE)) <> VAR
+```
+Instead, use the `.until` or `.to` constructors which handle this automatically and are more readable:
+```scala
+// DO this instead:
+val addr = UInt.until(DEPTH) <> VAR // width = clog2(DEPTH)
+val mask = Bits.until(SIZE) <> VAR // width = clog2(SIZE)
+```
+See the [DFType Constructors][DFDecimal] and [Bits constructors][DFBits] sections for details on `.until` and `.to`.
+///
+
+/// admonition | Non-constant DFHDL `Int` values
+ type: note
+Non-constant DFHDL `Int` values (e.g., `Int <> VAR`) are possible and support the same arithmetic operations (`+`, `-`, `*`, `/`, `%`). However, they are discouraged for synthesizable designs because they map to a fixed 32-bit signed representation -- use `SInt[32]` instead for explicit control over the hardware. For simulation purposes, non-constant `Int` values are acceptable as long as the 32-bit width limitation is understood.
+///
+
+/// admonition | Slicing bits from a DFHDL `Int`
+ type: note
+To extract a partial bit range from a DFHDL `Int` value, first convert it to `Bits` using `.bits`, then apply the slice: `myInt.bits(hi, lo)`. This is a `.bits` conversion followed by `(hi, lo)` slicing. The `.bits` conversion is a DFHDL extension method available on DFHDL `Int <> CONST` values, not on plain Scala `Int`.
+///
+
+### History Operations {#history-ops}
+
+Applies to: `Bit` (`.rising`, `.falling`)
+
+These operations are supported under both RT and ED domains. Under RT domain, these operations are synthesizable expressions.
+
+/// html | div.operations
+| Operation | Description | LHS Constraints | Returns |
+| ------------ | --------------------------------|-----------------------|-----------------------|
+| `lhs.rising` | True when a value changes from `0` to `1` | `Bit` DFHDL value | `Boolean` DFHDL value |
+| `lhs.falling` | True when a value changes from `1` to `0` | `Bit` DFHDL value | `Boolean` DFHDL value |
+///
+
+/// tab | `ED`
+
+```scala
+class Foo extends EDDesign:
+ val clk = Bit <> IN
+
+ /* VHDL-style */
+ process(clk):
+ if (clk.rising)
+ //some sequential logic
+
+ /* Verilog-style */
+ process(clk.rising):
+ //some sequential logic
+```
+/// details | Transitioning from Verilog
+ type: verilog
+Under the ED domain, the `x.rising` and `x.falling` operations are equivalent to the Verilog `posedge x` and `negedge x`, respectively.
+///
+
+/// details | Transitioning from VHDL
+ type: vhdl
+Under the ED domain, the `x.rising` and `x.falling` operations are equivalent to the VHDL `rising_edge(x)` and `falling_edge(x)`, respectively.
+///
+///
+
+/// tab | `RT`
+The following `RT` domain edge detection design:
+```scala
+class Detector extends RTDesign:
+ val i = Bit <> IN
+ val o = Bit <> OUT
+ o := i.rising
+```
+is compiled down to the following `ED` design (depending on the clock and reset configurations):
+```scala
+class Detector extends EDDesign:
+ val clk = Bit <> IN
+ val i = Bit <> IN
+ val o = Bit <> OUT
+ val i_reg = Bit <> VAR init 1
+ process(clk.rising):
+ i_reg :== i
+ o <> !i_reg && i
+```
+The initial (reset) register value is `1`/`0` for `rising`/`falling` operations, respectively.
+This inherently prevents triggering immediately after reset, without sampling at least two input clock cycles.
+
+Both Verilog and VHDL have no equivalent synthesizable shorthand syntax.
+///
+
+For more information see either the [design domains][design-domains] or [processes][processes] sections.
+
+### Constant Meta Operations {#const-meta-ops}
+
+Applies to: constant `Bit`/`Boolean` values
+
+These operations are activated during the [elaboration stage][elaboration] of the DFHDL compilation, and are only available for constant `Bit`/`Boolean` DFHDL values.
+Their use case is for meta-programming purposes, to control the generated code without the knowledge of the DFHDL compiler (could be considered as pre-processing steps).
+
+/// html | div.operations
+| Operation | Description | LHS Constraints | Returns |
+| ------------ | ----------- | ------------------- | ------- |
+| `lhs.toScalaBitNum` | Extracts the known elaboration Scala `BitNum`(`1 | 0`) value from a constant DFHDL `Bit`/`Boolean` value | Constant `Bit`/`Boolean` DFHDL value | Scala `BitNum` value |
+| `lhs.toScalaBoolean` | Extracts the known elaboration Scala `Boolean` value from a constant DFHDL `Bit`/`Boolean` value | Constant `Bit`/`Boolean` DFHDL value | Scala `Boolean` value |
+///
+
+The following runnable example demonstrates how such meta operation affect the elaborated design.
+The `Boolean` argument `arg` of a design `Foo` is used twice within the design:
+first, in an `if` condition directly; and second, in an `if` condition after a Scala value extraction.
+When referenced directly, the `if` is elaborated as-is, but when the `if` is applied on the extracted Scala value,
+the `if` is completely removed and either the block inside the `if` is elaborated when the argument is true or completely removed if false.
+
+/// tab | `Foo`
+```scala
+class Foo(
+ val arg: Boolean <> CONST
+) extends DFDesign:
+ val o = Bit <> OUT
+ if (!arg) o := 1
+ if (arg.toScalaBoolean) o := 0
+```
+///
+
+
+/// tab | `Foo(true)`
+```scala
+class Foo(
+ val arg: Boolean <> CONST
+) extends DFDesign:
+ val o = Bit <> OUT
+ if (!arg) o := 1
+ o := 0
+```
+///
+
+/// tab | `Foo(false)`
+```scala
+class Foo(
+ val arg: Boolean <> CONST
+) extends DFDesign:
+ val o = Bit <> OUT
+ if (!arg) o := 1
+```
+///
+
+/// details | Runnable example
+ type: dfhdl
+```scastie
+import dfhdl.*
+
+@top(false) class Foo(
+ val arg: Boolean <> CONST
+) extends DFDesign:
+ val o = Bit <> OUT
+ if (!arg) o := 1
+ if (arg.toScalaBoolean) o := 0
+
+@main def main =
+ println("Foo(true) Elaboration:")
+ Foo(true).printCodeString
+ println("Foo(false) Elaboration:")
+ Foo(false).printCodeString
+```
+///
+
+### Vector Element Access {#vector-ops}
+
+Applies to: `Vector`
+
+```scala
+val elem = vec(idx) // Read element at index
+vec(idx) := newValue // Write element at index
+```
+
+/// html | div.operations
+| Operation | Description | Returns |
+| ------------ | ----------- | ------- |
+| `vec(idx)` | Access element at index | Element type |
+| `vec.elements` | Get all elements as Scala sequence | Seq[BaseType] |
+| `vec.size` | Get vector dimension | Int |
+///
+
+
diff --git a/docs/user-guide/type-system/type-conversion-dark.svg b/docs/user-guide/type-system/type-conversion-dark.svg
new file mode 100644
index 000000000..a12db8b89
--- /dev/null
+++ b/docs/user-guide/type-system/type-conversion-dark.svg
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UInt
+
+
+
+
+
+
+ Bits
+
+
+
+
+
+
+ SInt
+
+
+
+
+
+
+
+ Type T
+
+
+
+
+ Boolean
+
+
+
+
+
+
+ Bit
+
+
+
+
+
+
+ Int
+
+
+
+
+ .toUInt(w)
+
+
+
+
+ .bits
+
+
+ .bits
+
+
+ .toBits(w)
+
+
+ .uint
+
+
+ .sint
+
+
+
+
+ .toSInt(w)
+
+
+
+
+ .signed
+
+
+ .bits
+
+
+ .as(T)
+
+
+ .bits
+
+
+ .bit
+
+
+ .bool
+
+
+ .toInt
+
+
+ .toInt
+
+
+
diff --git a/docs/user-guide/type-system/type-conversion-light.svg b/docs/user-guide/type-system/type-conversion-light.svg
new file mode 100644
index 000000000..3ce450256
--- /dev/null
+++ b/docs/user-guide/type-system/type-conversion-light.svg
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UInt
+
+
+
+
+
+
+ Bits
+
+
+
+
+
+
+ SInt
+
+
+
+
+
+
+
+ Type T
+
+
+
+
+ Boolean
+
+
+
+
+
+
+ Bit
+
+
+
+
+
+
+ Int
+
+
+
+
+ .toUInt(w)
+
+
+
+
+ .bits
+
+
+ .bits
+
+
+ .toBits(w)
+
+
+ .uint
+
+
+ .sint
+
+
+
+
+ .toSInt(w)
+
+
+
+
+ .signed
+
+
+ .bits
+
+
+ .as(T)
+
+
+ .bits
+
+
+ .bit
+
+
+ .bool
+
+
+ .toInt
+
+
+ .toInt
+
+
+
diff --git a/docs/user-guide/type-system/type-conversion.graphml b/docs/user-guide/type-system/type-conversion.graphml
new file mode 100644
index 000000000..3bf943b70
--- /dev/null
+++ b/docs/user-guide/type-system/type-conversion.graphml
@@ -0,0 +1,317 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UInt
+
+
+
+
+
+
+
+
+
+
+ Bits
+
+
+
+
+
+
+
+
+
+
+ SInt
+
+
+
+
+
+
+
+
+
+
+
+ Type T
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Boolean
+
+
+
+
+
+
+
+
+
+
+ Bit
+
+
+
+
+
+
+
+
+
+
+ Int
+
+
+
+
+
+
+
+
+
+
+
+
+ .bits
+
+
+
+
+
+
+
+
+
+
+
+
+ .uint
+
+
+
+
+
+
+
+
+
+
+
+
+ .sint
+
+
+
+
+
+
+
+
+
+
+
+
+ .bits
+
+
+
+
+
+
+
+
+
+
+
+
+ .bits
+
+
+
+
+
+
+
+
+
+
+
+
+ .as(T)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .bit
+
+
+
+
+
+
+
+
+
+
+
+
+ .bool
+
+
+
+
+
+
+
+
+
+
+
+
+ .toUInt(w)
+
+
+
+
+
+
+
+
+
+
+
+
+ .toSInt(w)
+
+
+
+
+
+
+
+
+
+
+
+ .bits
+
+
+
+
+
+
+
+
+
+
+
+ .toBits(w)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .signed
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .toInt
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .toInt
+
+
+
+
+
+
+
+
diff --git a/internals/src/main/scala/dfhdl/internals/MetaContext.scala b/internals/src/main/scala/dfhdl/internals/MetaContext.scala
index 24214e574..ad984d17a 100644
--- a/internals/src/main/scala/dfhdl/internals/MetaContext.scala
+++ b/internals/src/main/scala/dfhdl/internals/MetaContext.scala
@@ -9,6 +9,7 @@ final case class Position(
lineEnd: Int,
columnEnd: Int
) derives CanEqual:
+ def shortFilePath: String = file.split("\\\\").last
override def toString: String = s"$file:$lineStart:$columnStart - $lineEnd:$columnEnd"
def fileUnixPath: String = file.replaceAll("\\\\", "/")
def isUnknown: Boolean = this == Position.unknown
diff --git a/internals/src/main/scala/dfhdl/internals/helpers.scala b/internals/src/main/scala/dfhdl/internals/helpers.scala
index 1a533ff53..c68a0c70b 100644
--- a/internals/src/main/scala/dfhdl/internals/helpers.scala
+++ b/internals/src/main/scala/dfhdl/internals/helpers.scala
@@ -343,10 +343,11 @@ extension (str: String)
def forceWindowsToLinuxPath: String = str.replaceAll("""\\""", "/")
def simplePattenToRegex: Regex =
val updatedPattern =
- "^" + str
- .replace(".", "\\.") // Escape dots to match literal dots
- .replace("*", ".*") // Replace * with .*
- .replace("?", ".") // Replace ? with .
+ "^"
+ + str
+ .replace(".", "\\.") // Escape dots to match literal dots
+ .replace("*", ".*") // Replace * with .*
+ .replace("?", ".") // Replace ? with .
+ "$"
updatedPattern.r
end extension
@@ -387,6 +388,9 @@ lazy val getShellCommand: Option[String] =
end match
end getShellCommand
+lazy val sbtnIsRunning: Boolean =
+ sbtIsRunning && getShellCommand.exists(cmd => cmd.endsWith("--server"))
+
lazy val sbtShellIsRunning: Boolean =
getShellCommand.exists(cmd => cmd.endsWith("xsbt.boot.Boot") || cmd.endsWith("sbt-launch.jar"))
diff --git a/lib/src/main/scala/dfhdl/app/DFApp.scala b/lib/src/main/scala/dfhdl/app/DFApp.scala
index 5046a2bbb..499a9f95a 100644
--- a/lib/src/main/scala/dfhdl/app/DFApp.scala
+++ b/lib/src/main/scala/dfhdl/app/DFApp.scala
@@ -6,7 +6,7 @@ import wvlet.log.{Logger, LogFormatter}
import scala.collection.mutable
import dfhdl.options.*
import org.rogach.scallop.*
-import dfhdl.internals.sbtShellIsRunning
+import dfhdl.internals.{sbtShellIsRunning, sbtnIsRunning}
import scala.util.chaining.scalaUtilChainingOps
import java.time.Instant
import dfhdl.compiler.stages.{StagedDesign, CompiledDesign}
@@ -400,7 +400,7 @@ trait DFApp:
)
parsedCommandLine.getExitCodeOption match
case Some(code) =>
- if (!sbtShellIsRunning) sys.exit(code)
+ if (!sbtShellIsRunning && !sbtnIsRunning) sys.exit(code)
case None =>
given CanEqual[ScallopConfBase, ScallopConfBase] = CanEqual.derived
// update app options from command line
@@ -423,6 +423,9 @@ trait DFApp:
printDFHDLCode = mode.`print-compile`.toOption.get,
printBackendCode = mode.`print-backend`.toOption.get
)
+ printerOptions = printerOptions.copy(
+ globalDefsFileName = mode.`global-defs-name`.toOption.get
+ )
case _ =>
// update linter options from command line
parsedCommandLine.mode match
diff --git a/lib/src/main/scala/dfhdl/app/ParsedCommandLine.scala b/lib/src/main/scala/dfhdl/app/ParsedCommandLine.scala
index 4faf67413..d320d9683 100644
--- a/lib/src/main/scala/dfhdl/app/ParsedCommandLine.scala
+++ b/lib/src/main/scala/dfhdl/app/ParsedCommandLine.scala
@@ -13,6 +13,7 @@ class ParsedCommandLine(
)(using
eo: ElaborationOptions,
co: CompilerOptions,
+ pto: PrinterOptions,
lo: LinterOptions,
so: SimulatorOptions,
bo: BuilderOptions,
@@ -81,6 +82,12 @@ class ParsedCommandLine(
hidden = hidden,
noshort = true
)
+ val `global-defs-name` = opt[String](
+ descr = "override the global definitions file name (without suffix)",
+ default = Some(pto.globalDefsFileName),
+ noshort = true,
+ hidden = hidden
+ )
end CompileMode
trait CommitMode extends CompileMode:
this: ScallopConf & Mode =>
@@ -241,11 +248,14 @@ class ParsedCommandLine(
end HelpMode
private def usageText(options: String): String =
- import dfhdl.internals.{sbtIsRunning, scala_cliIsRunning, sbtShellIsRunning}
+ import dfhdl.internals.{sbtIsRunning, scala_cliIsRunning, sbtShellIsRunning, sbtnIsRunning}
if (scala_cliIsRunning) s"scala run . -M $topScalaPath -- $options"
else if (sbtIsRunning)
- if (sbtShellIsRunning && !scastieIsRunning) s"runMain $topScalaPath $options"
- else s"""sbt "runMain $topScalaPath $options""""
+ if ((sbtShellIsRunning || sbtnIsRunning) && !scastieIsRunning)
+ s"runMain $topScalaPath $options"
+ else
+ val sbtCommand = if (sbtnIsRunning) "sbtn" else "sbt"
+ s"""$sbtCommand "runMain $topScalaPath $options""""
else s" $options"
banner(s"""Design Name: $designName\nUsage: ${usageText("[design-args] [options]")} """)
diff --git a/lib/src/main/scala/dfhdl/tools/toolsCore/IcarusVerilog.scala b/lib/src/main/scala/dfhdl/tools/toolsCore/IcarusVerilog.scala
index 919421971..18b20820d 100644
--- a/lib/src/main/scala/dfhdl/tools/toolsCore/IcarusVerilog.scala
+++ b/lib/src/main/scala/dfhdl/tools/toolsCore/IcarusVerilog.scala
@@ -66,6 +66,9 @@ object IcarusVerilog extends VerilogLinter, VerilogSimulator:
// suppress the "cannot be synthesized" warning when in simulation
if (line.contains("cannot be synthesized") && getSet.designDB.inSimulation)
true
+ // workaround for https://github.com/steveicarus/iverilog/issues/255
+ else if (line.contains("Case unique/unique0 qualities are ignored"))
+ true
else
false
)
diff --git a/lib/src/main/scala/dfhdl/tools/toolsCore/QuartusPrime.scala b/lib/src/main/scala/dfhdl/tools/toolsCore/QuartusPrime.scala
index e2f409ad7..3cbe79ca6 100644
--- a/lib/src/main/scala/dfhdl/tools/toolsCore/QuartusPrime.scala
+++ b/lib/src/main/scala/dfhdl/tools/toolsCore/QuartusPrime.scala
@@ -325,11 +325,11 @@ class QuartusPrimeIPPrinter(using
val members = qsysIP.members(MemberView.Folded)
val ipVersion = members.collectFirst {
case param: DFVal.DesignParam if param.getName == "version" =>
- " " + param.dfValRef.get.getConstData.get.asInstanceOf[Option[String]].get
+ " " + param.getConstData.get.asInstanceOf[Option[String]].get
}.getOrElse("")
val ipParams = members.collect {
case param: DFVal.DesignParam if param.getName != "version" =>
- s"set_instance_parameter_value $ipInstanceName {${param.getName}} {${param.dfValRef.get.getConstData.get.asInstanceOf[Option[Any]].get}}"
+ s"set_instance_parameter_value $ipInstanceName {${param.getName}} {${param.getConstData.get.asInstanceOf[Option[Any]].get}}"
}.mkString("\n")
val ipExports = members.collect {
case port @ DclPort() =>
diff --git a/lib/src/main/scala/dfhdl/tools/toolsCore/Vivado.scala b/lib/src/main/scala/dfhdl/tools/toolsCore/Vivado.scala
index 86d4fdc2c..a4ead792c 100644
--- a/lib/src/main/scala/dfhdl/tools/toolsCore/Vivado.scala
+++ b/lib/src/main/scala/dfhdl/tools/toolsCore/Vivado.scala
@@ -331,7 +331,7 @@ class VivadoIPPrinter(using
val members = vivadoIP.members(MemberView.Folded)
val ipVersion = members.collectFirst {
case param: DFVal.DesignParam if param.getName == "version" =>
- val version = param.dfValRef.get.getConstData.get.asInstanceOf[Option[String]].get
+ val version = param.getConstData.get.asInstanceOf[Option[String]].get
if (version.nonEmpty) Some(" -version " + version) else None
}.flatten.getOrElse("")
@@ -339,7 +339,7 @@ class VivadoIPPrinter(using
// Each DFVal.DesignParam except "version" becomes a CONFIG. {value} line
val ipConfigParams = members.collect {
case param: DFVal.DesignParam if param.getName != "version" =>
- val value = param.dfValRef.get.getConstData.get.asInstanceOf[Option[Any]].get
+ val value = param.getConstData.get.asInstanceOf[Option[Any]].get
s"CONFIG.${param.getName} {$value}"
}
val ipConfigBlock =
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker.sv b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker.sv
index 0a122d928..b1180e8c8 100644
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker.sv
+++ b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker.sv
@@ -1,7 +1,6 @@
/* This is a led blinker */
`default_nettype none
`timescale 1ns/1ps
-`include "Blinker_defs.svh"
module Blinker#(
parameter int CLK_FREQ_KHz = 50000,
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker_defs.svh b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker_defs.svh
deleted file mode 100644
index 5c11a419d..000000000
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.sv2009/hdl/Blinker_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef BLINKER_DEFS
-`define BLINKER_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker.v b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker.v
index de1d0356e..f7d2673d3 100644
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker.v
+++ b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker.v
@@ -1,7 +1,6 @@
/* This is a led blinker */
`default_nettype none
`timescale 1ns/1ps
-`include "Blinker_defs.vh"
module Blinker#(
parameter integer CLK_FREQ_KHz = 50000,
@@ -13,7 +12,6 @@ module Blinker#(
output reg led
);
`include "dfhdl_defs.vh"
- `include "Blinker_defs.vh"
/* Half-count of the toggle for 50% duty cycle */
parameter integer HALF_PERIOD = (CLK_FREQ_KHz * 1000) / (LED_FREQ_Hz * 2);
reg [clog2(HALF_PERIOD) - 1:0] cnt;
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker_defs.vh b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker_defs.vh
deleted file mode 100644
index 44cc9875c..000000000
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v2001/hdl/Blinker_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef BLINKER_DEFS
-`define BLINKER_DEFS
-`endif
-`ifndef BLINKER_DEFS_MODULE
-`define BLINKER_DEFS_MODULE
-`else
-`undef BLINKER_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker.v b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker.v
index c55460553..69e54c06d 100644
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker.v
+++ b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker.v
@@ -1,7 +1,6 @@
/* This is a led blinker */
`default_nettype none
`timescale 1ns/1ps
-`include "Blinker_defs.vh"
module Blinker(
clk,
@@ -9,7 +8,6 @@ module Blinker(
led
);
`include "dfhdl_defs.vh"
- `include "Blinker_defs.vh"
parameter integer CLK_FREQ_KHz = 50000;
parameter integer LED_FREQ_Hz = 1;
/* Half-count of the toggle for 50% duty cycle */
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker_defs.vh b/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker_defs.vh
deleted file mode 100644
index 44cc9875c..000000000
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/verilog.v95/hdl/Blinker_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef BLINKER_DEFS
-`define BLINKER_DEFS
-`endif
-`ifndef BLINKER_DEFS_MODULE
-`define BLINKER_DEFS_MODULE
-`else
-`undef BLINKER_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker.vhd b/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker.vhd
index 79dac3e62..8da5dd70c 100644
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker.vhd
+++ b/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker.vhd
@@ -3,7 +3,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.Blinker_pkg.all;
entity Blinker is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker_pkg.vhd b/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker_pkg.vhd
deleted file mode 100644
index 9eef929ff..000000000
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v2008/hdl/Blinker_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package Blinker_pkg is
-end package Blinker_pkg;
-
-package body Blinker_pkg is
-end package body Blinker_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker.vhd b/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker.vhd
index cec07a688..f06111cec 100644
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker.vhd
+++ b/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker.vhd
@@ -3,7 +3,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.Blinker_pkg.all;
entity Blinker is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker_pkg.vhd b/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker_pkg.vhd
deleted file mode 100644
index 9eef929ff..000000000
--- a/lib/src/test/resources/ref/docExamples.BlinkerSpec/vhdl.v93/hdl/Blinker_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package Blinker_pkg is
-end package Blinker_pkg;
-
-package body Blinker_pkg is
-end package body Blinker_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter.sv b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter.sv
index fb082b6f9..c5ccd846f 100644
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter.sv
+++ b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "Counter_defs.svh"
module Counter#(parameter int width = 8)(
input wire logic clk,
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter_defs.svh b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter_defs.svh
deleted file mode 100644
index eb369b141..000000000
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.sv2009/hdl/Counter_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef COUNTER_DEFS
-`define COUNTER_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter.v b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter.v
index 9c3c0e012..2eb7f222a 100644
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter.v
+++ b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "Counter_defs.vh"
module Counter#(parameter integer width = 8)(
input wire clk,
@@ -9,7 +8,6 @@ module Counter#(parameter integer width = 8)(
output reg [width - 1:0] cnt
);
`include "dfhdl_defs.vh"
- `include "Counter_defs.vh"
always @(posedge clk)
begin
if (rst == 1'b1) cnt <= `dPW(0, 1, width);
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter_defs.vh b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter_defs.vh
deleted file mode 100644
index ee2ed1b95..000000000
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v2001/hdl/Counter_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef COUNTER_DEFS
-`define COUNTER_DEFS
-`endif
-`ifndef COUNTER_DEFS_MODULE
-`define COUNTER_DEFS_MODULE
-`else
-`undef COUNTER_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter.v b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter.v
index dbcb73567..23514d912 100644
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter.v
+++ b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "Counter_defs.vh"
module Counter(
clk,
@@ -9,7 +8,6 @@ module Counter(
cnt
);
`include "dfhdl_defs.vh"
- `include "Counter_defs.vh"
parameter integer width = 8;
input wire clk;
input wire rst;
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter_defs.vh b/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter_defs.vh
deleted file mode 100644
index ee2ed1b95..000000000
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/verilog.v95/hdl/Counter_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef COUNTER_DEFS
-`define COUNTER_DEFS
-`endif
-`ifndef COUNTER_DEFS_MODULE
-`define COUNTER_DEFS_MODULE
-`else
-`undef COUNTER_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter.vhd b/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter.vhd
index 9572b7058..884b62e07 100644
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter.vhd
+++ b/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.Counter_pkg.all;
entity Counter is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter_pkg.vhd b/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter_pkg.vhd
deleted file mode 100644
index 74ad8b33e..000000000
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v2008/hdl/Counter_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package Counter_pkg is
-end package Counter_pkg;
-
-package body Counter_pkg is
-end package body Counter_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter.vhd b/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter.vhd
index ca06ff824..2921c2804 100644
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter.vhd
+++ b/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.Counter_pkg.all;
entity Counter is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter_pkg.vhd b/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter_pkg.vhd
deleted file mode 100644
index 74ad8b33e..000000000
--- a/lib/src/test/resources/ref/docExamples.CounterSpec/vhdl.v93/hdl/Counter_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package Counter_pkg is
-end package Counter_pkg;
-
-package body Counter_pkg is
-end package body Counter_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1.sv b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1.sv
index 73001a45a..0b6f43b99 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1.sv
+++ b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdder1_defs.svh"
module FullAdder1(
input wire logic a,
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1_defs.svh b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1_defs.svh
deleted file mode 100644
index 83e5e9ff9..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.sv2009/hdl/FullAdder1_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef FULLADDER1_DEFS
-`define FULLADDER1_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1.v b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1.v
index dfa5fcd0f..4d3248626 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1.v
+++ b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdder1_defs.vh"
module FullAdder1(
input wire a,
@@ -10,7 +9,6 @@ module FullAdder1(
output wire c_out
);
`include "dfhdl_defs.vh"
- `include "FullAdder1_defs.vh"
assign sum = (a ^ b) ^ c_in;
assign c_out = ((a & b) | (b & c_in)) | (c_in & a);
endmodule
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1_defs.vh b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1_defs.vh
deleted file mode 100644
index 652b16c28..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v2001/hdl/FullAdder1_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef FULLADDER1_DEFS
-`define FULLADDER1_DEFS
-`endif
-`ifndef FULLADDER1_DEFS_MODULE
-`define FULLADDER1_DEFS_MODULE
-`else
-`undef FULLADDER1_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1.v b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1.v
index 4255f1b54..d994fb3ff 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1.v
+++ b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdder1_defs.vh"
module FullAdder1(
a,
@@ -10,7 +9,6 @@ module FullAdder1(
c_out
);
`include "dfhdl_defs.vh"
- `include "FullAdder1_defs.vh"
input wire a;
input wire b;
input wire c_in;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1_defs.vh b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1_defs.vh
deleted file mode 100644
index 652b16c28..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/verilog.v95/hdl/FullAdder1_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef FULLADDER1_DEFS
-`define FULLADDER1_DEFS
-`endif
-`ifndef FULLADDER1_DEFS_MODULE
-`define FULLADDER1_DEFS_MODULE
-`else
-`undef FULLADDER1_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1.vhd b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1.vhd
index 5fb6396f8..e2be3df93 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1.vhd
+++ b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.FullAdder1_pkg.all;
entity FullAdder1 is
port (
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1_pkg.vhd b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1_pkg.vhd
deleted file mode 100644
index 44a6d88c9..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v2008/hdl/FullAdder1_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package FullAdder1_pkg is
-end package FullAdder1_pkg;
-
-package body FullAdder1_pkg is
-end package body FullAdder1_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1.vhd b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1.vhd
index 5fb6396f8..e2be3df93 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1.vhd
+++ b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.FullAdder1_pkg.all;
entity FullAdder1 is
port (
diff --git a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1_pkg.vhd b/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1_pkg.vhd
deleted file mode 100644
index 44a6d88c9..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdder1Spec/vhdl.v93/hdl/FullAdder1_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package FullAdder1_pkg is
-end package FullAdder1_pkg;
-
-package body FullAdder1_pkg is
-end package body FullAdder1_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdder1.sv b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdder1.sv
index 7689a1359..0b6f43b99 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdder1.sv
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdder1.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdderN_defs.svh"
module FullAdder1(
input wire logic a,
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN.sv b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN.sv
index 36f54e96c..97be2f5c3 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN.sv
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdderN_defs.svh"
module FullAdderN(
input wire logic [3:0] a,
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN_defs.svh b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN_defs.svh
deleted file mode 100644
index 3cab3ebce..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.sv2009/hdl/FullAdderN_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef FULLADDERN_DEFS
-`define FULLADDERN_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdder1.v b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdder1.v
index 7149b5fd6..4d3248626 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdder1.v
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdder1.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdderN_defs.vh"
module FullAdder1(
input wire a,
@@ -10,7 +9,6 @@ module FullAdder1(
output wire c_out
);
`include "dfhdl_defs.vh"
- `include "FullAdderN_defs.vh"
assign sum = (a ^ b) ^ c_in;
assign c_out = ((a & b) | (b & c_in)) | (c_in & a);
endmodule
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN.v b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN.v
index 39cd161a8..23c85f734 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN.v
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdderN_defs.vh"
module FullAdderN(
input wire [3:0] a,
@@ -10,7 +9,6 @@ module FullAdderN(
output wire c_out
);
`include "dfhdl_defs.vh"
- `include "FullAdderN_defs.vh"
wire adder_0_a;
wire adder_0_b;
wire adder_0_c_in;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN_defs.vh b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN_defs.vh
deleted file mode 100644
index 0ec185153..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v2001/hdl/FullAdderN_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef FULLADDERN_DEFS
-`define FULLADDERN_DEFS
-`endif
-`ifndef FULLADDERN_DEFS_MODULE
-`define FULLADDERN_DEFS_MODULE
-`else
-`undef FULLADDERN_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdder1.v b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdder1.v
index 652b63bb0..d994fb3ff 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdder1.v
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdder1.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdderN_defs.vh"
module FullAdder1(
a,
@@ -10,7 +9,6 @@ module FullAdder1(
c_out
);
`include "dfhdl_defs.vh"
- `include "FullAdderN_defs.vh"
input wire a;
input wire b;
input wire c_in;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN.v b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN.v
index 3fd4b2615..77588f115 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN.v
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "FullAdderN_defs.vh"
module FullAdderN(
a,
@@ -10,7 +9,6 @@ module FullAdderN(
c_out
);
`include "dfhdl_defs.vh"
- `include "FullAdderN_defs.vh"
input wire [3:0] a;
input wire [3:0] b;
input wire c_in;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN_defs.vh b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN_defs.vh
deleted file mode 100644
index 0ec185153..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/verilog.v95/hdl/FullAdderN_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef FULLADDERN_DEFS
-`define FULLADDERN_DEFS
-`endif
-`ifndef FULLADDERN_DEFS_MODULE
-`define FULLADDERN_DEFS_MODULE
-`else
-`undef FULLADDERN_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdder1.vhd b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdder1.vhd
index 3dc80d3de..e2be3df93 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdder1.vhd
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdder1.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.FullAdderN_pkg.all;
entity FullAdder1 is
port (
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN.vhd b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN.vhd
index b0b2f60bf..65c615061 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN.vhd
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.FullAdderN_pkg.all;
entity FullAdderN is
port (
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN_pkg.vhd b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN_pkg.vhd
deleted file mode 100644
index 2912cd37e..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v2008/hdl/FullAdderN_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package FullAdderN_pkg is
-end package FullAdderN_pkg;
-
-package body FullAdderN_pkg is
-end package body FullAdderN_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdder1.vhd b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdder1.vhd
index 3dc80d3de..e2be3df93 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdder1.vhd
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdder1.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.FullAdderN_pkg.all;
entity FullAdder1 is
port (
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN.vhd b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN.vhd
index 56085de99..d6ac5d84d 100644
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN.vhd
+++ b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.FullAdderN_pkg.all;
entity FullAdderN is
port (
diff --git a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN_pkg.vhd b/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN_pkg.vhd
deleted file mode 100644
index 2912cd37e..000000000
--- a/lib/src/test/resources/ref/docExamples.FullAdderNSpec/vhdl.v93/hdl/FullAdderN_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package FullAdderN_pkg is
-end package FullAdderN_pkg;
-
-package body FullAdderN_pkg is
-end package body FullAdderN_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile.sv b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile.sv
index 32d8138c0..991b74167 100644
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile.sv
+++ b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "RegFile_defs.svh"
module RegFile#(
parameter int DATA_WIDTH = 32,
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile_defs.svh b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile_defs.svh
deleted file mode 100644
index 8505bc1e4..000000000
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.sv2009/hdl/RegFile_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef REGFILE_DEFS
-`define REGFILE_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile.v b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile.v
index cef0a6c8e..81b50ae73 100644
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile.v
+++ b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "RegFile_defs.vh"
module RegFile#(
parameter integer DATA_WIDTH = 32,
@@ -16,7 +15,6 @@ module RegFile#(
input wire rd_wren
);
`include "dfhdl_defs.vh"
- `include "RegFile_defs.vh"
reg [DATA_WIDTH - 1:0] regs [0:REG_NUM - 1];
always @(posedge clk)
begin
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile_defs.vh b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile_defs.vh
deleted file mode 100644
index 1dcaad88b..000000000
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v2001/hdl/RegFile_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef REGFILE_DEFS
-`define REGFILE_DEFS
-`endif
-`ifndef REGFILE_DEFS_MODULE
-`define REGFILE_DEFS_MODULE
-`else
-`undef REGFILE_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile.v b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile.v
index d21b85bca..222e49e9b 100644
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile.v
+++ b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "RegFile_defs.vh"
module RegFile(
clk,
@@ -13,7 +12,6 @@ module RegFile(
rd_wren
);
`include "dfhdl_defs.vh"
- `include "RegFile_defs.vh"
parameter integer DATA_WIDTH = 32;
parameter integer REG_NUM = 32;
input wire clk;
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile_defs.vh b/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile_defs.vh
deleted file mode 100644
index 1dcaad88b..000000000
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/verilog.v95/hdl/RegFile_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef REGFILE_DEFS
-`define REGFILE_DEFS
-`endif
-`ifndef REGFILE_DEFS_MODULE
-`define REGFILE_DEFS_MODULE
-`else
-`undef REGFILE_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile.vhd b/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile.vhd
index b9ad459b4..df5c33443 100644
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile.vhd
+++ b/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.RegFile_pkg.all;
entity RegFile is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile_pkg.vhd b/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile_pkg.vhd
deleted file mode 100644
index 25ee852ce..000000000
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v2008/hdl/RegFile_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package RegFile_pkg is
-end package RegFile_pkg;
-
-package body RegFile_pkg is
-end package body RegFile_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile.vhd b/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile.vhd
index df815655b..de8f519da 100644
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile.vhd
+++ b/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.RegFile_pkg.all;
entity RegFile is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile_pkg.vhd b/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile_pkg.vhd
deleted file mode 100644
index 25ee852ce..000000000
--- a/lib/src/test/resources/ref/docExamples.RegFileSpec/vhdl.v93/hdl/RegFile_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package RegFile_pkg is
-end package RegFile_pkg;
-
-package body RegFile_pkg is
-end package body RegFile_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR.sv b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR.sv
index d141c2eac..7909a4580 100644
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR.sv
+++ b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "TrueDPR_defs.svh"
module TrueDPR#(
parameter int DATA_WIDTH = 8,
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR_defs.svh b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR_defs.svh
deleted file mode 100644
index 19c985635..000000000
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.sv2009/hdl/TrueDPR_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef TRUEDPR_DEFS
-`define TRUEDPR_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR.v b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR.v
index 8f11982e7..200600c9c 100644
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR.v
+++ b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "TrueDPR_defs.vh"
module TrueDPR#(
parameter integer DATA_WIDTH = 8,
@@ -18,7 +17,6 @@ module TrueDPR#(
input wire b_we
);
`include "dfhdl_defs.vh"
- `include "TrueDPR_defs.vh"
reg [DATA_WIDTH - 1:0] ram [0:(2 ** ADDR_WIDTH) - 1];
always @(posedge a_clk)
begin
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR_defs.vh b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR_defs.vh
deleted file mode 100644
index 1719dbb00..000000000
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v2001/hdl/TrueDPR_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef TRUEDPR_DEFS
-`define TRUEDPR_DEFS
-`endif
-`ifndef TRUEDPR_DEFS_MODULE
-`define TRUEDPR_DEFS_MODULE
-`else
-`undef TRUEDPR_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR.v b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR.v
index cc52f0d25..db25bf457 100644
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR.v
+++ b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "TrueDPR_defs.vh"
module TrueDPR(
a_clk,
@@ -15,7 +14,6 @@ module TrueDPR(
b_we
);
`include "dfhdl_defs.vh"
- `include "TrueDPR_defs.vh"
parameter integer DATA_WIDTH = 8;
parameter integer ADDR_WIDTH = 8;
input wire a_clk;
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR_defs.vh b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR_defs.vh
deleted file mode 100644
index 1719dbb00..000000000
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/verilog.v95/hdl/TrueDPR_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef TRUEDPR_DEFS
-`define TRUEDPR_DEFS
-`endif
-`ifndef TRUEDPR_DEFS_MODULE
-`define TRUEDPR_DEFS_MODULE
-`else
-`undef TRUEDPR_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR.vhd b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR.vhd
index 643f0a6c4..2360f9c9e 100644
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR.vhd
+++ b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.TrueDPR_pkg.all;
entity TrueDPR is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR_pkg.vhd b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR_pkg.vhd
deleted file mode 100644
index edd333ecd..000000000
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v2008/hdl/TrueDPR_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package TrueDPR_pkg is
-end package TrueDPR_pkg;
-
-package body TrueDPR_pkg is
-end package body TrueDPR_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR.vhd b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR.vhd
index 5bfabb3a6..47592fe69 100644
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR.vhd
+++ b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.TrueDPR_pkg.all;
entity TrueDPR is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR_pkg.vhd b/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR_pkg.vhd
deleted file mode 100644
index edd333ecd..000000000
--- a/lib/src/test/resources/ref/docExamples.TrueDPRSpec/vhdl.v93/hdl/TrueDPR_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package TrueDPR_pkg is
-end package TrueDPR_pkg;
-
-package body TrueDPR_pkg is
-end package body TrueDPR_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx.sv b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx.sv
index 1704e8e35..936cd1413 100644
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx.sv
+++ b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx.sv
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "UART_Tx_defs.svh"
module UART_Tx#(
parameter int CLK_FREQ_KHz = 50000,
@@ -16,7 +15,7 @@ module UART_Tx#(
);
`include "dfhdl_defs.svh"
localparam int BIT_CLOCKS = (CLK_FREQ_KHz * 1000) / BAUD_RATE_BPS;
- typedef enum {
+ typedef enum logic [4:0] {
Status_Idle = 1,
Status_StartBit = 2,
Status_DataBits = 4,
@@ -35,7 +34,7 @@ module UART_Tx#(
dataBitCnt <= 3'd0;
end
else begin
- case (status)
+ unique case (status)
Status_Idle: begin
tx_en <= 1'b0;
tx <= 1'b1;
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx_defs.svh b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx_defs.svh
deleted file mode 100644
index ef4db63a6..000000000
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.sv2009/hdl/UART_Tx_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef UART_TX_DEFS
-`define UART_TX_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx.v b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx.v
index c07e7d415..875dff3c9 100644
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx.v
+++ b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "UART_Tx_defs.vh"
module UART_Tx#(
parameter integer CLK_FREQ_KHz = 50000,
@@ -15,7 +14,6 @@ module UART_Tx#(
output reg tx_done
);
`include "dfhdl_defs.vh"
- `include "UART_Tx_defs.vh"
parameter integer BIT_CLOCKS = (CLK_FREQ_KHz * 1000) / BAUD_RATE_BPS;
`define Status_Idle 1
`define Status_StartBit 2
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx_defs.vh b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx_defs.vh
deleted file mode 100644
index 186b0a671..000000000
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v2001/hdl/UART_Tx_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef UART_TX_DEFS
-`define UART_TX_DEFS
-`endif
-`ifndef UART_TX_DEFS_MODULE
-`define UART_TX_DEFS_MODULE
-`else
-`undef UART_TX_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx.v b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx.v
index df71b3854..13a9d8a07 100644
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx.v
+++ b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx.v
@@ -1,6 +1,5 @@
`default_nettype none
`timescale 1ns/1ps
-`include "UART_Tx_defs.vh"
module UART_Tx(
clk,
@@ -12,7 +11,6 @@ module UART_Tx(
tx_done
);
`include "dfhdl_defs.vh"
- `include "UART_Tx_defs.vh"
parameter integer CLK_FREQ_KHz = 50000;
parameter integer BAUD_RATE_BPS = 115200;
parameter integer BIT_CLOCKS = (CLK_FREQ_KHz * 1000) / BAUD_RATE_BPS;
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx_defs.vh b/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx_defs.vh
deleted file mode 100644
index 186b0a671..000000000
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/verilog.v95/hdl/UART_Tx_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef UART_TX_DEFS
-`define UART_TX_DEFS
-`endif
-`ifndef UART_TX_DEFS_MODULE
-`define UART_TX_DEFS_MODULE
-`else
-`undef UART_TX_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx.vhd b/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx.vhd
index 80ac54ec1..5c8dd2df1 100644
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx.vhd
+++ b/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.UART_Tx_pkg.all;
entity UART_Tx is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx_pkg.vhd b/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx_pkg.vhd
deleted file mode 100644
index 487a30013..000000000
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v2008/hdl/UART_Tx_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package UART_Tx_pkg is
-end package UART_Tx_pkg;
-
-package body UART_Tx_pkg is
-end package body UART_Tx_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx.vhd b/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx.vhd
index 15e99debc..05ccdb87b 100644
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx.vhd
+++ b/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx.vhd
@@ -2,7 +2,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.UART_Tx_pkg.all;
entity UART_Tx is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx_pkg.vhd b/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx_pkg.vhd
deleted file mode 100644
index 487a30013..000000000
--- a/lib/src/test/resources/ref/docExamples.UART_TxSpec/vhdl.v93/hdl/UART_Tx_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package UART_Tx_pkg is
-end package UART_Tx_pkg;
-
-package body UART_Tx_pkg is
-end package body UART_Tx_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2.sv b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2.sv
index a7b381e2e..319d630ea 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2.sv
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2.sv
@@ -1,7 +1,6 @@
/* A two-bits left shifter */
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShift2_defs.svh"
module LeftShift2(
/* bits input */
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2_defs.svh b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2_defs.svh
deleted file mode 100644
index 7c012faf5..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.sv2009/hdl/LeftShift2_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef LEFTSHIFT2_DEFS
-`define LEFTSHIFT2_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2.v b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2.v
index c8454b4a6..e5af17844 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2.v
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2.v
@@ -1,7 +1,6 @@
/* A two-bits left shifter */
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShift2_defs.vh"
module LeftShift2(
/* bits input */
@@ -10,6 +9,5 @@ module LeftShift2(
output wire [7:0] oBits
);
`include "dfhdl_defs.vh"
- `include "LeftShift2_defs.vh"
assign oBits = iBits << 2;
endmodule
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2_defs.vh b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2_defs.vh
deleted file mode 100644
index 9dc730828..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v2001/hdl/LeftShift2_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef LEFTSHIFT2_DEFS
-`define LEFTSHIFT2_DEFS
-`endif
-`ifndef LEFTSHIFT2_DEFS_MODULE
-`define LEFTSHIFT2_DEFS_MODULE
-`else
-`undef LEFTSHIFT2_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2.v b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2.v
index b4efff3a8..ed0b812b1 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2.v
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2.v
@@ -1,14 +1,12 @@
/* A two-bits left shifter */
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShift2_defs.vh"
module LeftShift2(
iBits,
oBits
);
`include "dfhdl_defs.vh"
- `include "LeftShift2_defs.vh"
/* bits input */
input wire [7:0] iBits;
/* bits output */
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2_defs.vh b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2_defs.vh
deleted file mode 100644
index 9dc730828..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/verilog.v95/hdl/LeftShift2_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef LEFTSHIFT2_DEFS
-`define LEFTSHIFT2_DEFS
-`endif
-`ifndef LEFTSHIFT2_DEFS_MODULE
-`define LEFTSHIFT2_DEFS_MODULE
-`else
-`undef LEFTSHIFT2_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2.vhd
index dafcd564d..b0c28bffd 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2.vhd
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2.vhd
@@ -3,7 +3,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.LeftShift2_pkg.all;
entity LeftShift2 is
port (
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2_pkg.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2_pkg.vhd
deleted file mode 100644
index 98e980ea8..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v2008/hdl/LeftShift2_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package LeftShift2_pkg is
-end package LeftShift2_pkg;
-
-package body LeftShift2_pkg is
-end package body LeftShift2_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2.vhd
index dafcd564d..b0c28bffd 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2.vhd
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2.vhd
@@ -3,7 +3,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.LeftShift2_pkg.all;
entity LeftShift2 is
port (
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2_pkg.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2_pkg.vhd
deleted file mode 100644
index 98e980ea8..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo1.LeftShift2Spec/vhdl.v93/hdl/LeftShift2_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package LeftShift2_pkg is
-end package LeftShift2_pkg;
-
-package body LeftShift2_pkg is
-end package body LeftShift2_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic.sv b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic.sv
index 0e47cdaa0..24e5c224f 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic.sv
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic.sv
@@ -1,7 +1,6 @@
/* A basic left shifter */
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShiftBasic_defs.svh"
module LeftShiftBasic(
/* bits input */
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic_defs.svh b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic_defs.svh
deleted file mode 100644
index c1d7b0a2c..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.sv2009/hdl/LeftShiftBasic_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef LEFTSHIFTBASIC_DEFS
-`define LEFTSHIFTBASIC_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic.v b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic.v
index dedfaef60..7a9c0da50 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic.v
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic.v
@@ -1,7 +1,6 @@
/* A basic left shifter */
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShiftBasic_defs.vh"
module LeftShiftBasic(
/* bits input */
@@ -12,6 +11,5 @@ module LeftShiftBasic(
output wire [7:0] oBits
);
`include "dfhdl_defs.vh"
- `include "LeftShiftBasic_defs.vh"
assign oBits = iBits << shift;
endmodule
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic_defs.vh b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic_defs.vh
deleted file mode 100644
index 6cb4101a1..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v2001/hdl/LeftShiftBasic_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef LEFTSHIFTBASIC_DEFS
-`define LEFTSHIFTBASIC_DEFS
-`endif
-`ifndef LEFTSHIFTBASIC_DEFS_MODULE
-`define LEFTSHIFTBASIC_DEFS_MODULE
-`else
-`undef LEFTSHIFTBASIC_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic.v b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic.v
index 0b0d55fee..2526d4263 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic.v
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic.v
@@ -1,7 +1,6 @@
/* A basic left shifter */
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShiftBasic_defs.vh"
module LeftShiftBasic(
iBits,
@@ -9,7 +8,6 @@ module LeftShiftBasic(
oBits
);
`include "dfhdl_defs.vh"
- `include "LeftShiftBasic_defs.vh"
/* bits input */
input wire [7:0] iBits;
/* requested shift */
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic_defs.vh b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic_defs.vh
deleted file mode 100644
index 6cb4101a1..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/verilog.v95/hdl/LeftShiftBasic_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef LEFTSHIFTBASIC_DEFS
-`define LEFTSHIFTBASIC_DEFS
-`endif
-`ifndef LEFTSHIFTBASIC_DEFS_MODULE
-`define LEFTSHIFTBASIC_DEFS_MODULE
-`else
-`undef LEFTSHIFTBASIC_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic.vhd
index 1f7627399..ace9fd9ec 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic.vhd
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic.vhd
@@ -3,7 +3,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.LeftShiftBasic_pkg.all;
entity LeftShiftBasic is
port (
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic_pkg.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic_pkg.vhd
deleted file mode 100644
index 4e02534fe..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v2008/hdl/LeftShiftBasic_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package LeftShiftBasic_pkg is
-end package LeftShiftBasic_pkg;
-
-package body LeftShiftBasic_pkg is
-end package body LeftShiftBasic_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic.vhd
index 1f7627399..ace9fd9ec 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic.vhd
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic.vhd
@@ -3,7 +3,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.LeftShiftBasic_pkg.all;
entity LeftShiftBasic is
port (
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic_pkg.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic_pkg.vhd
deleted file mode 100644
index 4e02534fe..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo2.LeftShiftBasicSpec/vhdl.v93/hdl/LeftShiftBasic_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package LeftShiftBasic_pkg is
-end package LeftShiftBasic_pkg;
-
-package body LeftShiftBasic_pkg is
-end package body LeftShiftBasic_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen.sv b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen.sv
index fad9cc77b..8aa8b2510 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen.sv
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen.sv
@@ -5,7 +5,6 @@
*/
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShiftGen_defs.svh"
module LeftShiftGen#(parameter int width = 8)(
/* bits input */
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen_defs.svh b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen_defs.svh
deleted file mode 100644
index 458c38ad4..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.sv2009/hdl/LeftShiftGen_defs.svh
+++ /dev/null
@@ -1,3 +0,0 @@
-`ifndef LEFTSHIFTGEN_DEFS
-`define LEFTSHIFTGEN_DEFS
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen.v b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen.v
index 9c6b302d4..380beb54a 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen.v
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen.v
@@ -5,7 +5,6 @@
*/
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShiftGen_defs.vh"
module LeftShiftGen#(parameter integer width = 8)(
/* bits input */
@@ -16,6 +15,5 @@ module LeftShiftGen#(parameter integer width = 8)(
output wire [width - 1:0] oBits
);
`include "dfhdl_defs.vh"
- `include "LeftShiftGen_defs.vh"
assign oBits = iBits << shift;
endmodule
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen_defs.vh b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen_defs.vh
deleted file mode 100644
index a0dcc749d..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v2001/hdl/LeftShiftGen_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef LEFTSHIFTGEN_DEFS
-`define LEFTSHIFTGEN_DEFS
-`endif
-`ifndef LEFTSHIFTGEN_DEFS_MODULE
-`define LEFTSHIFTGEN_DEFS_MODULE
-`else
-`undef LEFTSHIFTGEN_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen.v b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen.v
index 4e9ef9368..0b268a7ef 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen.v
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen.v
@@ -5,7 +5,6 @@
*/
`default_nettype none
`timescale 1ns/1ps
-`include "LeftShiftGen_defs.vh"
module LeftShiftGen(
iBits,
@@ -13,7 +12,6 @@ module LeftShiftGen(
oBits
);
`include "dfhdl_defs.vh"
- `include "LeftShiftGen_defs.vh"
parameter integer width = 8;
/* bits input */
input wire [width - 1:0] iBits;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen_defs.vh b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen_defs.vh
deleted file mode 100644
index a0dcc749d..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/verilog.v95/hdl/LeftShiftGen_defs.vh
+++ /dev/null
@@ -1,8 +0,0 @@
-`ifndef LEFTSHIFTGEN_DEFS
-`define LEFTSHIFTGEN_DEFS
-`endif
-`ifndef LEFTSHIFTGEN_DEFS_MODULE
-`define LEFTSHIFTGEN_DEFS_MODULE
-`else
-`undef LEFTSHIFTGEN_DEFS_MODULE
-`endif
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen.vhd
index 92a5b0696..eec45aff2 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen.vhd
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen.vhd
@@ -6,7 +6,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.LeftShiftGen_pkg.all;
entity LeftShiftGen is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen_pkg.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen_pkg.vhd
deleted file mode 100644
index bffa2421d..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v2008/hdl/LeftShiftGen_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package LeftShiftGen_pkg is
-end package LeftShiftGen_pkg;
-
-package body LeftShiftGen_pkg is
-end package body LeftShiftGen_pkg;
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen.vhd
index 92a5b0696..eec45aff2 100644
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen.vhd
+++ b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen.vhd
@@ -6,7 +6,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dfhdl_pkg.all;
-use work.LeftShiftGen_pkg.all;
entity LeftShiftGen is
generic (
diff --git a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen_pkg.vhd b/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen_pkg.vhd
deleted file mode 100644
index bffa2421d..000000000
--- a/lib/src/test/resources/ref/docExamples.ugdemos.demo3.LeftShiftGenSpec/vhdl.v93/hdl/LeftShiftGen_pkg.vhd
+++ /dev/null
@@ -1,10 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use work.dfhdl_pkg.all;
-
-package LeftShiftGen_pkg is
-end package LeftShiftGen_pkg;
-
-package body LeftShiftGen_pkg is
-end package body LeftShiftGen_pkg;
diff --git a/lib/src/test/scala/issues/IssueSpec.scala b/lib/src/test/scala/issues/IssueSpec.scala
index 1becff9d1..dce572d81 100644
--- a/lib/src/test/scala/issues/IssueSpec.scala
+++ b/lib/src/test/scala/issues/IssueSpec.scala
@@ -23,7 +23,6 @@ class IssuesSpec extends FunSuite:
|use ieee.std_logic_1164.all;
|use ieee.numeric_std.all;
|use work.dfhdl_pkg.all;
- |use work.ArrayIssue_pkg.all;
|
|entity ArrayIssue is
|port (
@@ -61,7 +60,6 @@ class IssuesSpec extends FunSuite:
i135.VerilogSRA().getCompiledCodeString,
"""|`default_nettype none
|`timescale 1ns/1ps
- |`include "VerilogSRA_defs.svh"
|
|module VerilogSRA(
| input wire logic signed [9:0] a
diff --git a/plugin/src/main/scala/plugin/CommonPhase.scala b/plugin/src/main/scala/plugin/CommonPhase.scala
index 2255f8647..f121d004b 100755
--- a/plugin/src/main/scala/plugin/CommonPhase.scala
+++ b/plugin/src/main/scala/plugin/CommonPhase.scala
@@ -311,11 +311,19 @@ abstract class CommonPhase extends PluginPhase:
case _ => None
end extension
+ type PosKey = String
+ extension (sym: Symbol)(using Context)
+ def posKey: PosKey = sym.srcPos.show
+ extension (tree: Tree)(using Context)
+ def posKey: PosKey = tree.srcPos.show
+
extension (srcPos: util.SrcPos)(using Context)
def show: String =
- val pos = srcPos.startPos
- val endPos = srcPos.endPos
- s"${pos.source.path}:${pos.line}:${pos.column}-${endPos.line}:${endPos.column}"
+ if (srcPos.span == util.Spans.NoSpan) "NoSpan"
+ else
+ val pos = srcPos.startPos
+ val endPos = srcPos.endPos
+ s"${pos.source.path}:${pos.line}:${pos.column}-${endPos.line}:${endPos.column}"
extension (tree: Apply)(using Context)
def replaceArg(fromArg: Tree, toArg: Tree): Apply =
diff --git a/plugin/src/main/scala/plugin/CustomControlPhase.scala b/plugin/src/main/scala/plugin/CustomControlPhase.scala
index 9b1515ff9..060f35c34 100644
--- a/plugin/src/main/scala/plugin/CustomControlPhase.scala
+++ b/plugin/src/main/scala/plugin/CustomControlPhase.scala
@@ -38,8 +38,8 @@ class CustomControlPhase(setting: Setting) extends CommonPhase:
// override val debugFilter: String => Boolean = _.contains("Playground.scala")
override val runsAfter = Set(transform.Pickler.name)
override val runsBefore = Set("MetaContextGen")
- val ignoreIfs = mutable.Set.empty[String]
- val replaceIfs = mutable.Set.empty[String]
+ val ignoreIfs = mutable.Set.empty[PosKey]
+ val replaceIfs = mutable.Set.empty[PosKey]
var fromBooleanSym: Symbol = uninitialized
var toFunc1Sym: Symbol = uninitialized
var fromBranchesSym: Symbol = uninitialized
@@ -99,16 +99,16 @@ class CustomControlPhase(setting: Setting) extends CommonPhase:
case _ => false
@tailrec private def ignoreElseIfRecur(tree: If)(using Context): Unit =
- ignoreIfs += tree.srcPos.show
+ ignoreIfs += tree.posKey
tree.elsep match
case tree: If => ignoreElseIfRecur(tree)
case _ => // done
override def prepareForIf(tree: If)(using Context): Context =
- if (!ignoreIfs.contains(tree.srcPos.show) && isHackedIfRecur(tree))
+ if (!ignoreIfs.contains(tree.posKey) && isHackedIfRecur(tree))
tree.elsep match
case tree: If => ignoreElseIfRecur(tree)
case _ => // do nothing
- replaceIfs += tree.srcPos.show
+ replaceIfs += tree.posKey
ctx
private def transformIfCond(condTree: Tree, dfcTree: Tree)(using
@@ -167,7 +167,7 @@ class CustomControlPhase(setting: Setting) extends CommonPhase:
case _ => false
override def transformIf(tree: If)(using Context): Tree =
- if (replaceIfs.contains(tree.srcPos.show))
+ if (replaceIfs.contains(tree.posKey))
// debug("=======================")
val dfcTree = dfcStack.head
val combinedTpe = tree.tpe.widen
@@ -780,7 +780,8 @@ class CustomControlPhase(setting: Setting) extends CommonPhase:
}
if (idxHigh != -1)
report.error(
- s"""Cannot compare a value of ${selectorWidth} bits width (LHS) to a value of ${selectorWidth - idxHigh - 1} bits width (RHS).
+ s"""Cannot compare a value of ${selectorWidth} bits width (LHS) to a value of ${selectorWidth -
+ idxHigh - 1} bits width (RHS).
|An explicit conversion must be applied.""".stripMargin,
patternTree.srcPos
)
diff --git a/plugin/src/main/scala/plugin/LoopFSMPhase.scala b/plugin/src/main/scala/plugin/LoopFSMPhase.scala
index 0cdacfde7..7c2b49d65 100644
--- a/plugin/src/main/scala/plugin/LoopFSMPhase.scala
+++ b/plugin/src/main/scala/plugin/LoopFSMPhase.scala
@@ -36,10 +36,11 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
var processAnonDefSym: Symbol = uninitialized
var processScopeCtxSym: Symbol = uninitialized
var stepType: Type = uninitialized
- var pluginOnEntryExitSym: Symbol = uninitialized
+ var fallThroughType: Type = uninitialized
+ var pluginOnEntryExitFallThroughSym: Symbol = uninitialized
var waitSym: Symbol = uninitialized
var dfcStack: List[Tree] = Nil
- val processStepDefs = mutable.LinkedHashMap.empty[Symbol, DefDef]
+ val processStepDefs = mutable.LinkedHashMap.empty[PosKey, DefDef]
override val runsAfter = Set(transform.Pickler.name)
override val runsBefore = Set("CustomControl")
@@ -53,7 +54,7 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
override def transformDefDef(tree: DefDef)(using Context): Tree =
val updatedDefDef =
if (tree.symbol == processAnonDefSym)
- val registeredSteps = processStepDefs.view.map { (sym, dd) =>
+ val registeredSteps = processStepDefs.valuesIterator.map { dd =>
ref(registerStepSym)
.appliedTo(dd.genMeta)
.appliedTo(dfcStack.head, ref(processScopeCtxSym))
@@ -85,12 +86,14 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
report.error("Process blocks must only declare step `def`s or no step`def`s at all.", srcPos)
enum CheckType derives CanEqual:
- case None, Return, Loop, OnEntryExit
+ case None, Return, Loop, OnEntryExitFallThrough
def processStatCheck(tree: Tree, returnCheck: CheckType)(using Context): Unit =
tree match
+ case vd: ValDef if vd.tpt.tpe =:= defn.UnitType =>
+ processStatCheck(vd.rhs, returnCheck)
case Block(stats, expr) =>
returnCheck match
- case CheckType.OnEntryExit =>
+ case CheckType.OnEntryExitFallThrough =>
(expr :: stats).foreach(t => processStatCheck(t, returnCheck))
case _ =>
processStatCheck(stats, tree.srcPos)
@@ -98,8 +101,8 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
case Literal(Constant(_: Unit)) =>
case _ =>
stats.headOption match
- case Some(OnEntryDef() | OnExitDef()) =>
- case Some(dd: DefDef) =>
+ case Some(OnEntryDef() | OnExitDef() | FallThroughDef()) =>
+ case Some(dd: DefDef) =>
// allDefsErrMsg(expr.srcPos)
case _ =>
processStatCheck(expr, returnCheck)
@@ -130,13 +133,16 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
// |For a purely combinational loop, call `0.cy.wait` at the end of the loop block.""".stripMargin,
// tree.srcPos
// )
- case CheckType.OnEntryExit =>
+ case CheckType.OnEntryExitFallThrough =>
tree match
case dd: DefDef =>
- report.error("onEntry/onExit must not contain any other `def`s.", dd.srcPos)
+ report.error(
+ "onEntry/onExit/fallThrough must not contain any other `def`s.",
+ dd.srcPos
+ )
case Goto() | Wait() =>
report.error(
- "onEntry/onExit `def`s cannot have `wait` or step goto statements.",
+ "onEntry/onExit/fallThrough `def`s cannot have `wait` or step goto statements.",
tree.srcPos
)
case _ =>
@@ -151,23 +157,22 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
case _: DefDef => true
case _ => false
}).runtimeChecked
- val (onEntryExit: List[DefDef], stepDefs: List[DefDef]) = allDefs.partition {
- case OnEntryDef() => true
- case OnExitDef() => true
- case _ => false
+ val (onEntryExitFallThrough: List[DefDef], stepDefs: List[DefDef]) = allDefs.partition {
+ case OnEntryDef() | OnExitDef() | FallThroughDef() => true
+ case _ => false
}
// if (stepDefs.nonEmpty && allStepBlocks.nonEmpty) allDefsErrMsg(srcPos)
// checking onEntry and onExit defs syntax
- onEntryExit.foreach { dd =>
+ onEntryExitFallThrough.foreach { dd =>
if (dd.paramss != Nil)
- report.error(s"An ${dd.name} def must not have arguments.", dd.srcPos)
+ report.error(s"`def ${dd.name}` must not have arguments.", dd.srcPos)
}
var errFound = false
// checking process defs syntax and caching the process def symbols
stepDefs.foreach {
case dd @ DefDef(_, Nil, retTypeTree, _) if retTypeTree.tpe =:= stepType =>
- processStepDefs += (dd.symbol -> dd)
+ processStepDefs += (dd.symbol.posKey -> dd)
case dd =>
report.error(
"Unexpected register-transfer (RT) process `def` syntax. Must be `def xyz: Step = ...`",
@@ -177,7 +182,9 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
}
if (!errFound)
stepDefs.foreach { dd => processStatCheck(dd.rhs, returnCheck = CheckType.Return) }
- onEntryExit.foreach { dd => processStatCheck(dd.rhs, returnCheck = CheckType.OnEntryExit) }
+ onEntryExitFallThrough.foreach { dd =>
+ processStatCheck(dd.rhs, returnCheck = CheckType.OnEntryExitFallThrough)
+ }
allStepBlocks.foreach { step => processStatCheck(step, returnCheck = CheckType.None) }
end processStatCheck
@@ -271,7 +278,8 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
List(domainTypeTree)
)
if anonfun.toString.startsWith("$anonfun") && process.toString == "process" &&
- forever.toString == "forever" && domainTypeTree.tpe.widenDealias.typeSymbol.name.toString == "RT" =>
+ forever.toString == "forever" &&
+ domainTypeTree.tpe.widenDealias.typeSymbol.name.toString == "RT" =>
processAnonDefSym = dd.symbol
processScopeCtxSym = scopeCtx.symbol
Some(ProcessForever(scopeCtx, dd.rhs))
@@ -283,13 +291,6 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
tree match
case ProcessForever(scopeCtx, block) =>
processStatCheck(block, returnCheck = CheckType.None)
- processStepDefs.view.groupBy(_._2.name.toString).foreach { case (name, defs) =>
- if (defs.size > 1)
- report.error(
- s"Process step `def`s must be unique. Found multiple `def $name: Step = ...`s.",
- defs.head._2.srcPos
- )
- }
case Apply(Select(This(_), wait), args) if wait.toString == "wait" => // DFHDL/Java wait
if (!tree.tpe.isContextualMethod) // Java's wait wouldn't be contextual
report.error(
@@ -307,9 +308,19 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
object OnExitDef:
def unapply(tree: DefDef)(using Context): Boolean =
tree.name.toString == "onExit"
+ object FallThroughDef:
+ def unapply(tree: DefDef)(using Context): Boolean =
+ if (tree.name.toString == "fallThrough")
+ if (!(tree.tpt.tpe <:< fallThroughType))
+ report.error(
+ s"`def fallThrough` must return a DFHDL Boolean or Bit value.",
+ tree.srcPos
+ )
+ true
+ else false
object Goto:
def unapply(tree: Ident)(using Context): Boolean =
- processStepDefs.contains(tree.symbol)
+ processStepDefs.contains(tree.symbol.posKey)
object Wait:
def unapply(tree: Apply)(using Context): Boolean =
tree.tpe.typeSymbol.fullName.toString == "dfhdl.core.Wait$package$.Wait"
@@ -317,7 +328,7 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
tree match
case Goto() =>
ref(gotoStepSym)
- .appliedTo(Literal(Constant(tree.name.toString)))
+ .appliedTo(Literal(Constant(getStepKey(tree))))
.appliedTo(dfcStack.head, ref(processScopeCtxSym))
case _ => tree
@@ -346,15 +357,22 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
case _ =>
tree
+ // this is used to get a unique key for the step,
+ // because the step name may be repeated when declared internally in another step or loop.
+ // the line position makes sure we get a unique key for the step.
+ private def getStepKey(tree: DefDef | Ident)(using Context): String =
+ val sym = tree.symbol
+ s"${sym.name}_${sym.srcPos.startPos.line + 1}"
+
override def transformStats(trees: List[Tree])(using Context): List[Tree] =
trees.map {
- case dd: DefDef if processStepDefs.contains(dd.symbol) =>
+ case dd: DefDef if processStepDefs.contains(dd.symbol.posKey) =>
ref(addStepSym)
- .appliedTo(Literal(Constant(dd.name.toString)))
+ .appliedTo(Literal(Constant(getStepKey(dd))))
.appliedTo(dd.rhs.changeOwner(dd.symbol, ctx.owner))
.appliedTo(dfcStack.head, ref(processScopeCtxSym))
- case dd @ (OnEntryDef() | OnExitDef()) =>
- ref(pluginOnEntryExitSym)
+ case dd @ (OnEntryDef() | OnExitDef() | FallThroughDef()) =>
+ ref(pluginOnEntryExitFallThroughSym)
.appliedTo(dd.genMeta)
.appliedTo(dd.rhs.changeOwner(dd.symbol, ctx.owner))
.appliedTo(dfcStack.head)
@@ -372,7 +390,16 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
fromBooleanSym = requiredMethod("dfhdl.core.r__For_Plugin.fromBoolean")
customWhileSym = requiredMethod("dfhdl.core.DFWhile.plugin")
stepType = requiredClassRef("dfhdl.core.Step")
- pluginOnEntryExitSym = requiredMethod("dfhdl.core.Step.pluginOnEntryExit")
+ val dfTypeType = requiredClassRef("dfhdl.core.DFType")
+ val noArgsType = requiredClassRef("dfhdl.core.NoArgs")
+ val dfBoolOrBitType =
+ dfTypeType.appliedTo(requiredClassRef("dfhdl.compiler.ir.DFBoolOrBit"), noArgsType)
+ val modifierType = requiredClassRef("dfhdl.core.Modifier")
+ val modifierAnyType =
+ modifierType.appliedTo(List(defn.AnyType, defn.AnyType, defn.AnyType, defn.AnyType))
+ val dfValType = requiredClassRef("dfhdl.core.DFVal")
+ fallThroughType = dfValType.appliedTo(dfBoolOrBitType, modifierAnyType)
+ pluginOnEntryExitFallThroughSym = requiredMethod("dfhdl.core.Step.pluginOnEntryExitFallThrough")
processStepDefs.clear()
ctx
end prepareForUnit
diff --git a/plugin/src/main/scala/plugin/MetaContextGenPhase.scala b/plugin/src/main/scala/plugin/MetaContextGenPhase.scala
index 98f4e1c28..00d84d7c8 100755
--- a/plugin/src/main/scala/plugin/MetaContextGenPhase.scala
+++ b/plugin/src/main/scala/plugin/MetaContextGenPhase.scala
@@ -153,7 +153,8 @@ class MetaContextGenPhase(setting: Setting) extends CommonPhase:
val origApply = applyStack.head
applyStack = applyStack.drop(1)
if (
- fixedApply.tpe.isParameterless && !fixedApply.fun.symbol.ignoreMetaContext && !fixedApply.fun.symbol.forwardMetaContext
+ fixedApply.tpe.isParameterless && !fixedApply.fun.symbol.ignoreMetaContext &&
+ !fixedApply.fun.symbol.forwardMetaContext
)
fixedApply match
// found a context argument
@@ -390,8 +391,10 @@ class MetaContextGenPhase(setting: Setting) extends CommonPhase:
tree match
case Apply(Select(lhs, fun), List(rhs))
if (fun == nme.EQ || fun == nme.NE) &&
- (lhs.tpe <:< defn.IntType || lhs.tpe <:< defn.BooleanType || lhs.tpe <:< defn
- .TupleTypeRef) =>
+ (lhs.tpe <:< defn.IntType || lhs.tpe <:< defn.BooleanType ||
+ lhs.tpe <:<
+ defn
+ .TupleTypeRef) =>
val rhsSym = rhs.tpe.dealias.typeSymbol
if (rhsSym == dfValSym)
report.error(
@@ -399,7 +402,8 @@ class MetaContextGenPhase(setting: Setting) extends CommonPhase:
pos
)
case Apply(Select(lhs, fun), List(Apply(Apply(Ident(hackName), _), _)))
- if (fun == nme.ZOR || fun == nme.ZAND || fun == nme.XOR) && hackName.toString == "BooleanHack" =>
+ if (fun == nme.ZOR || fun == nme.ZAND || fun == nme.XOR) &&
+ hackName.toString == "BooleanHack" =>
report.error(
s"Unsupported Scala Boolean primitive at the LHS of `$fun` with a DFHDL value.\nConsider switching positions of the arguments.",
pos
diff --git a/plugin/src/main/scala/plugin/MetaContextPlacerPhase.scala b/plugin/src/main/scala/plugin/MetaContextPlacerPhase.scala
index ebfd04491..72ffa9038 100644
--- a/plugin/src/main/scala/plugin/MetaContextPlacerPhase.scala
+++ b/plugin/src/main/scala/plugin/MetaContextPlacerPhase.scala
@@ -27,6 +27,7 @@ import dotty.tools.dotc.ast.Trees.Alternative
is instantiated regularly the instance is transformed into an anonymous
class instance with the override, otherwise all is required is to add the
additional override to an existing anonymous DFHDL class instance.
+ Additionally, it transforms basic val x = y to val x = dfhdl.core.r__For_Plugin.identVal(y) if y is a DFVal
*/
class MetaContextPlacerPhase(setting: Setting) extends CommonPhase:
import tpd._
@@ -49,6 +50,7 @@ class MetaContextPlacerPhase(setting: Setting) extends CommonPhase:
var noTopAnnotIsRequired: TypeRef = uninitialized
var listMapEmptySym: TermSymbol = uninitialized
var listMapSym: TermSymbol = uninitialized
+ var dfhdlDFValIdentSym: TermSymbol = uninitialized
val defaultParamMap = mutable.Map.empty[ClassSymbol, Map[Int, Tree]]
override def prepareForTypeDef(tree: TypeDef)(using Context): Context =
val sym = tree.symbol
@@ -237,7 +239,8 @@ class MetaContextPlacerPhase(setting: Setting) extends CommonPhase:
case Apply(Select(New(Ident(n)), _), _) if n == StdNames.tpnme.ANON_CLASS => tree
case _
if (
- tree.fun.symbol.isClassConstructor && tpe.isParameterless && !ctx.owner.isClassConstructor &&
+ tree.fun.symbol.isClassConstructor && tpe.isParameterless &&
+ !ctx.owner.isClassConstructor &&
!ctx.owner.isClassConstructor && tpe.typeConstructor <:< hasDFCTpe
) =>
val cls = newNormalizedClassSymbol(
@@ -291,6 +294,29 @@ class MetaContextPlacerPhase(setting: Setting) extends CommonPhase:
cpy.Block(tree)(stats = List(updatedTypeDef), expr = tree.expr)
case _ =>
tree
+ // transform basic val x = y to val x = dfhdl.core.r__For_Plugin.identVal(y) if y is a DFVal
+ override def transformValDef(tree: ValDef)(using Context): ValDef =
+ object DFValIdent:
+ def unapply(tree: Tree)(using Context): Option[Tree] =
+ tree match
+ case ident @ Ident(name) if !name.toString.contains("$") => Some(tree)
+ case Select(DFValIdent(_), _) => Some(tree)
+ case This(DFValIdent(_)) => Some(tree)
+ case _ => None
+ end DFValIdent
+ tree.rhs match
+ case DFValIdent(rhs)
+ if !tree.symbol.flags.is(InlineProxy) && tree.tpt.tpe.dfValTpeOpt.nonEmpty =>
+ val dfc = dfcArgStack.headOption.getOrElse(ref(emptyNoEODFCSym))
+ val updatedRHS =
+ ref(dfhdlDFValIdentSym)
+ .appliedToType(rhs.tpe.widen)
+ .appliedTo(rhs)
+ .appliedTo(dfc)
+ cpy.ValDef(tree)(rhs = updatedRHS)
+ case _ => tree
+ end match
+ end transformValDef
override def prepareForUnit(tree: Tree)(using Context): Context =
super.prepareForUnit(tree)
@@ -306,6 +332,7 @@ class MetaContextPlacerPhase(setting: Setting) extends CommonPhase:
noTopAnnotIsRequired = requiredClassRef("dfhdl.internals.NoTopAnnotIsRequired")
listMapEmptySym = requiredMethod("scala.collection.immutable.ListMap.empty")
listMapSym = requiredModule("scala.collection.immutable.ListMap")
+ dfhdlDFValIdentSym = requiredMethod("dfhdl.core.r__For_Plugin.identVal")
dfcArgStack = Nil
defaultParamMap.clear()
ctx
diff --git a/project/build.properties b/project/build.properties
index c8cca6491..8430e165c 100755
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version = 1.12.1
\ No newline at end of file
+sbt.version = 1.12.8
\ No newline at end of file