From 70ab7b71c9702a4c5476693bfcd2f30de31801eb Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 11:12:15 +0800 Subject: [PATCH 01/10] refactor: Rename ModLocalInfo to ModuleData for clarity and consistency --- .../scala/dependentChisel/codegen/compiler.scala | 4 ++-- .../scala/dependentChisel/codegen/firrtlTypes.scala | 4 ++-- .../typesAndSyntax/chiselModules.scala | 12 +++++++++--- .../dependentChisel/typesAndSyntax/statements.scala | 4 ++-- .../dependentChisel/typesAndSyntax/varDecls.scala | 4 ++-- .../scala/dependentChisel/examples/BubbleFifo.scala | 6 +++--- .../dependentChisel/examples/BubbleFifoErr.scala | 4 ++-- 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/main/scala/dependentChisel/codegen/compiler.scala b/src/main/scala/dependentChisel/codegen/compiler.scala index 8ee2001..bfe02af 100644 --- a/src/main/scala/dependentChisel/codegen/compiler.scala +++ b/src/main/scala/dependentChisel/codegen/compiler.scala @@ -39,7 +39,7 @@ object compiler { /** chisel ModLocalInfo to FirrtlModule(IO bundle,AST for the circuit) */ def chiselMod2firrtlCircuits(chiselMod: UserModule, printCmdList: Boolean = false) = { - val modInfo: ModLocalInfo = chiselMod.modLocalInfo + val modInfo: ModuleData = chiselMod.modLocalInfo val allMods: List[UserModule] = chiselMod.globalInfo.modules.toList val typeMap = @@ -72,7 +72,7 @@ object compiler { typeMap: mutable.Map[Expr[?], Int], printCmdList: Boolean )(chiselMod: UserModule): FirrtlModule = { - val modInfo: ModLocalInfo = chiselMod.modLocalInfo + val modInfo: ModuleData = chiselMod.modLocalInfo // pp(modInfo.typeMap) val cmdList = modInfo.commands.toList if printCmdList then pp(modInfo.commands.toList) diff --git a/src/main/scala/dependentChisel/codegen/firrtlTypes.scala b/src/main/scala/dependentChisel/codegen/firrtlTypes.scala index f6be8b0..ca5870f 100644 --- a/src/main/scala/dependentChisel/codegen/firrtlTypes.scala +++ b/src/main/scala/dependentChisel/codegen/firrtlTypes.scala @@ -2,7 +2,7 @@ package dependentChisel.codegen import dependentChisel.algo.seqCmd2tree.AST import com.doofin.stdScalaCross.* -import dependentChisel.typesAndSyntax.chiselModules.ModLocalInfo +import dependentChisel.typesAndSyntax.chiselModules.ModuleData import dependentChisel.typesAndSyntax.typesAndOps.VarType object firrtlTypes { @@ -15,7 +15,7 @@ object firrtlTypes { ) /** one firrtl module */ - case class FirrtlModule(modInfo: ModLocalInfo, io: List[IOdef], ast: AST) + case class FirrtlModule(modInfo: ModuleData, io: List[IOdef], ast: AST) /** the whole circuit with multiple modules */ case class FirrtlCircuit(mainModuleName: String, modules: List[FirrtlModule]) diff --git a/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala b/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala index 2be2cc8..b5e3b27 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala @@ -25,11 +25,17 @@ import scala.util.Success /** imperative style for chisel ,record info in mutable vars inside class chiselModules */ object chiselModules { + /** global info + * + */ case class GlobalInfo( names: ArrayBuffer[String] = ArrayBuffer(), modules: ArrayBuffer[UserModule] = ArrayBuffer() ) - case class ModLocalInfo( + /** + * represent info for each module instance + */ + case class ModuleData( className: String, thisInstanceName: String, io: ArrayBuffer[IOdef] = ArrayBuffer(), @@ -53,8 +59,8 @@ object chiselModules { val thisInstanceName = naming.mkUidFrom(thisClassName) if (global.debugVerbose) println(s"new inst $thisInstanceName for $thisClassName") - given modLocalInfo: ModLocalInfo = - ModLocalInfo(className = thisClassName, thisInstanceName = thisInstanceName) + given modLocalInfo: ModuleData = + ModuleData(className = thisClassName, thisInstanceName = thisInstanceName) // def name = this.getClass.getCanonicalName.split('.').last val globalInfo = parent diff --git a/src/main/scala/dependentChisel/typesAndSyntax/statements.scala b/src/main/scala/dependentChisel/typesAndSyntax/statements.scala index 695a260..954e45a 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/statements.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/statements.scala @@ -21,7 +21,7 @@ object statements { /** typed API for assign */ extension [w <: Int, V <: Var[w]](v: V) { - inline def :=(using mli: ModLocalInfo)(oth: Expr[w]) = { + inline def :=(using mli: ModuleData)(oth: Expr[w]) = { val name = v.getname /* v match { @@ -39,7 +39,7 @@ object statements { /** untyped API for assign */ extension (v: VarDymTyped) { - inline def :=(using mli: ModLocalInfo)(oth: Expr[?]) = { + inline def :=(using mli: ModuleData)(oth: Expr[?]) = { val name = v.getname mli.typeMap.addOne(v, v.width) diff --git a/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala b/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala index 5c76b4d..3b29528 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala @@ -41,7 +41,7 @@ object varDecls { /** allow to be called outside module */ inline def newIO[w <: Int: ValueOf](using - mli: ModLocalInfo + mli: ModuleData )( tp: VarType.Input.type | VarType.Output.type, // widthOpt: Option[Int] = None, @@ -61,7 +61,7 @@ object varDecls { } def newIODym[w <: Int](using - mli: ModLocalInfo + mli: ModuleData )(width: Int, tp: VarType.Input.type | VarType.Output.type, givenName: String = "") = { val genName = naming.genNameForVar(givenName, tp) diff --git a/src/test/scala/dependentChisel/examples/BubbleFifo.scala b/src/test/scala/dependentChisel/examples/BubbleFifo.scala index b701b4d..0743a73 100644 --- a/src/test/scala/dependentChisel/examples/BubbleFifo.scala +++ b/src/test/scala/dependentChisel/examples/BubbleFifo.scala @@ -31,7 +31,7 @@ object BubbleFifo extends mainRunnable { val din = Input(UInt(size.W)) } */ - class WriterIO(using ModLocalInfo)(size: Int :| Positive) { + class WriterIO(using ModuleData)(size: Int :| Positive) { /** Input */ val write = newIO[1](VarType.Input) // Bool is same as UInt<1> @@ -43,7 +43,7 @@ object BubbleFifo extends mainRunnable { // val din = newIO(VarType.Input, Some(size)) } - class ReaderIO(using ModLocalInfo)(size: Int) { + class ReaderIO(using ModuleData)(size: Int) { /** Input */ val read = newIO[1](VarType.Input) // Bool() = UInt<1> @@ -109,7 +109,7 @@ object BubbleFifo extends mainRunnable { buffers(depth - 1).deq.read := deq.read } - def bulkConn(using ModLocalInfo)(enq: WriterIO, enq2: WriterIO) = { + def bulkConn(using ModuleData)(enq: WriterIO, enq2: WriterIO) = { enq.din := enq2.din enq2.full := enq.full enq.write := enq2.write diff --git a/src/test/scala/dependentChisel/examples/BubbleFifoErr.scala b/src/test/scala/dependentChisel/examples/BubbleFifoErr.scala index 2ce8f3b..9783395 100644 --- a/src/test/scala/dependentChisel/examples/BubbleFifoErr.scala +++ b/src/test/scala/dependentChisel/examples/BubbleFifoErr.scala @@ -20,7 +20,7 @@ object BubbleFifoErr { chiselMod2verilog(mod) } - class WriterIO_err(size: Int)(using mli: ModLocalInfo) { + class WriterIO_err(size: Int)(using mli: ModuleData) { /** Input */ val write = newIO[1](VarType.Input) @@ -32,7 +32,7 @@ object BubbleFifoErr { val din = newIODym(size + 1, VarType.Input) // correct should be just size } - class ReaderIO(size: Int)(using mli: ModLocalInfo) { + class ReaderIO(size: Int)(using mli: ModuleData) { /** Input */ val read = newIO[1](VarType.Input) // Bool() = UInt<1> From 44aef1c626afdb03a1010fe68b6d5e537e070075 Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 11:35:10 +0800 Subject: [PATCH 02/10] refactor: Rename seqCommands to sequentialCommands for improved clarity and consistency --- .../dependentChisel/algo/seqCmd2tree.scala | 6 +-- .../dependentChisel/codegen/compiler.scala | 38 +++++++-------- ...ommands.scala => sequentialCommands.scala} | 15 ++++-- .../dependentChisel/codegen/typeCheck.scala | 4 +- .../staticAnalysis/checkUnInitAnalysis.scala | 10 ++-- .../staticAnalysis/progGraph.scala | 2 +- .../staticAnalysis/test.worksheet.sc | 4 +- .../typesAndSyntax/chiselModules.scala | 48 +++++++++++-------- .../typesAndSyntax/control.scala | 4 +- .../typesAndSyntax/statements.scala | 6 +-- .../typesAndSyntax/varDecls.scala | 6 +-- 11 files changed, 79 insertions(+), 64 deletions(-) rename src/main/scala/dependentChisel/codegen/{seqCommands.scala => sequentialCommands.scala} (83%) diff --git a/src/main/scala/dependentChisel/algo/seqCmd2tree.scala b/src/main/scala/dependentChisel/algo/seqCmd2tree.scala index c43cb34..bad7d41 100644 --- a/src/main/scala/dependentChisel/algo/seqCmd2tree.scala +++ b/src/main/scala/dependentChisel/algo/seqCmd2tree.scala @@ -5,11 +5,11 @@ import scala.util.* import Tree.* import com.doofin.stdScalaCross.* -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* /** algorithm to convert sequential commands to AST */ object seqCmd2tree { - type AST = TreeNode[NewInstStmt | FirStmt | Ctrl | VarDecls] + type AST = TreeNode[NewInstance | WeakStmt | Ctrl | VarDecls] /** convert sequential commands to AST. multiple stmt is appended as multiple nodes */ @@ -33,7 +33,7 @@ object seqCmd2tree { // end of block, pop out one parent parents.pop() // for other stmt,just append - case stmt: (FirStmt | NewInstStmt | VarDecls) => + case stmt: (WeakStmt | NewInstance | VarDecls) => val newNd: AST = TreeNode(stmt) parents.top.cld += newNd case _ => diff --git a/src/main/scala/dependentChisel/codegen/compiler.scala b/src/main/scala/dependentChisel/codegen/compiler.scala index bfe02af..6a5819e 100644 --- a/src/main/scala/dependentChisel/codegen/compiler.scala +++ b/src/main/scala/dependentChisel/codegen/compiler.scala @@ -11,7 +11,7 @@ import dependentChisel.global import dependentChisel.typesAndSyntax.chiselModules.* import dependentChisel.algo.seqCmd2tree.* -import seqCommands.* +import sequentialCommands.* import firrtlTypes.* import scala.util.* @@ -81,7 +81,7 @@ object compiler { val cmds_ANF: List[Cmds] = expandCmdList(cmds_widthChk) // dbg(cmds_ANF) - val ioNameChanged: List[Cmds] = cmdsTransform(modInfo.thisInstanceName, cmds_ANF) + val ioNameChanged: List[Cmds] = cmdsTransform(modInfo.instanceName, cmds_ANF) // dbg(ioNameChanged) val tree: AST = list2tree(ioNameChanged) FirrtlModule(modInfo, modInfo.io.toList, tree) @@ -103,7 +103,7 @@ object compiler { val circuitStr = tree2firrtlStr(fMod.ast, indent) + skip // println("circuitStr.isEmpty:" + circuitStr.trim().isEmpty()) // pp(circuitStr) - val instName: String = fMod.modInfo.thisInstanceName // name changes for io + val instName: String = fMod.modInfo.instanceName // name changes for io val ioInfoStr = fMod.io.reverse // looks better .map { (x: IOdef) => @@ -137,14 +137,14 @@ object compiler { /** can insert more commands */ def expandCmdList(cmdList: List[Cmds]): List[Cmds] = { cmdList flatMap { - case x: FirStmt => + case x: WeakStmt => val fir = stmtToSingleAssign(x) // dbg(fir) fir case orig @ Start(ctrl: Ctrl, uid) => ctrl match { case ctrlIf @ Ctrl.If(bool) => - val anf_stmts: List[FirStmt] = + val anf_stmts: List[WeakStmt] = stmtToSingleAssign(expr2stmtBind(bool)) val anf_res = anf_stmts :+ orig.copy(ctrl = @@ -167,8 +167,8 @@ object compiler { case Ctrl.Else() => "else :" case Ctrl.Top() => "" }) - case stmt: FirStmt => indent + stmt2firrtlStr(stmt) - case stmt: NewInstStmt => newInstStmt2firrtlStr(indent, stmt) + "\n" + case stmt: WeakStmt => indent + stmt2firrtlStr(stmt) + case stmt: NewInstance => newInstStmt2firrtlStr(indent, stmt) + "\n" case stmt: VarDecls => indent + varDecl2firrtlStr(indent, stmt) } @@ -243,13 +243,13 @@ object compiler { } } - def stmt2firrtlStr(stmt: FirStmt) = { - val FirStmt(lhs, op, rhs, prefix) = stmt + def stmt2firrtlStr(stmt: WeakStmt) = { + val WeakStmt(lhs, op, rhs, prefix) = stmt val opName = firrtlOpMap.find(_._1 == op).map(_._2).getOrElse(op) prefix + expr2firrtlStr(lhs) + s" $opName ${expr2firrtlStr(rhs)}" } - def newInstStmt2firrtlStr(indent: String, stmt: NewInstStmt) = { + def newInstStmt2firrtlStr(indent: String, stmt: NewInstance) = { /* m1.clock <= clock m1.reset <= reset */ Seq( @@ -291,7 +291,7 @@ object compiler { /** convert expr to stmt bind: turn a+b into gen_ = a+b */ def expr2stmtBind(a: Expr[?]) = { val newValue = "g_" + global.getUid - FirStmt(VarLit(newValue), ":=", a, prefix = "node ") + WeakStmt(VarLit(newValue), ":=", a, prefix = "node ") } /* to A-normal form https://en.wikipedia.org/wiki/A-normal_form @@ -303,10 +303,10 @@ object compiler { stmt-> list stmt */ def stmtToSingleAssign( - stmt: FirStmt, - resList: List[FirStmt] = List() - ): List[FirStmt] = { - val FirStmt(stmtLhs, op, stmtRhs, _) = stmt + stmt: WeakStmt, + resList: List[WeakStmt] = List() + ): List[WeakStmt] = { + val WeakStmt(stmtLhs, op, stmtRhs, _) = stmt stmtRhs match { // fresh stmt for the first 2 case @@ -315,7 +315,7 @@ object compiler { stmtToSingleAssign( genStmt, List( - FirStmt( + WeakStmt( stmt.lhs, ":=", bop.copy(a = VarLit(genStmt.lhs.getname)), @@ -332,7 +332,7 @@ object compiler { */ case uop @ UniOp(a, nm) => val genStmt = expr2stmtBind(a) - val stmtNew = FirStmt( + val stmtNew = WeakStmt( stmtLhs, ":=", genStmt.lhs @@ -352,7 +352,7 @@ object compiler { /** if lhs is IO,change := to <= and make new conn io.y:=a+b becomes y0=a+b;io.y<=y0 new * : don't do above */ - def IOassignTransform(stmt: FirStmt): List[FirStmt] = { + def IOassignTransform(stmt: WeakStmt): List[WeakStmt] = { stmt.lhs match { /* if lhs is IO,change := to <= and make new conn io.y:=a+b becomes y0=a+b;io.y<=y0 @@ -432,7 +432,7 @@ object compiler { */ def cmdsTransform(thisInstName: String, cmdList: List[Cmds]): List[Cmds] = { cmdList map { - case x @ FirStmt(lhs, op, rhs, prefix) => + case x @ WeakStmt(lhs, op, rhs, prefix) => val newStmt = x.copy( lhs = varNameTransform(thisInstName, lhs), rhs = exprTransform(thisInstName, rhs) diff --git a/src/main/scala/dependentChisel/codegen/seqCommands.scala b/src/main/scala/dependentChisel/codegen/sequentialCommands.scala similarity index 83% rename from src/main/scala/dependentChisel/codegen/seqCommands.scala rename to src/main/scala/dependentChisel/codegen/sequentialCommands.scala index 173f1c8..0b34602 100644 --- a/src/main/scala/dependentChisel/codegen/seqCommands.scala +++ b/src/main/scala/dependentChisel/codegen/sequentialCommands.scala @@ -6,7 +6,7 @@ import dependentChisel.typesAndSyntax.statements.* import dependentChisel.global /** sequential commands used in chisel UserModule to build circuit */ -object seqCommands { +object sequentialCommands { type Uid = Int /** control structures like if */ @@ -17,8 +17,15 @@ object seqCommands { case Top() } - /** all sorts of sequential commands */ + /** all sorts of sequential commands + */ sealed trait Cmds + + /** represent start/end of control block + * + * @param ctrl + * @param uid + */ case class Start[CT <: Ctrl](ctrl: CT, uid: Uid) extends Cmds // uid is not used case class End[CT <: Ctrl](ctrl: CT, uid: Uid) extends Cmds @@ -26,11 +33,11 @@ object seqCommands { sealed trait AtomicCmds extends Cmds /** for new mod */ - case class NewInstStmt(instNm: String, modNm: String) extends AtomicCmds + case class NewInstance(instNm: String, modNm: String) extends AtomicCmds /** firrtl statements: weakly typed which doesn't require width of lhs = wid of rhs. */ - case class FirStmt( + case class WeakStmt( lhs: Var[?], op: String, rhs: Expr[?], diff --git a/src/main/scala/dependentChisel/codegen/typeCheck.scala b/src/main/scala/dependentChisel/codegen/typeCheck.scala index 1acfe60..e709cc5 100644 --- a/src/main/scala/dependentChisel/codegen/typeCheck.scala +++ b/src/main/scala/dependentChisel/codegen/typeCheck.scala @@ -5,7 +5,7 @@ import scala.collection.mutable import com.doofin.stdScalaJvm.* import dependentChisel.typesAndSyntax.chiselModules.* import dependentChisel.typesAndSyntax.typesAndOps.* -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* /** various checks like checking width */ object typeCheck { @@ -42,7 +42,7 @@ object typeCheck { /* 1.add width field in FirStmt 2. add width in lhs var and rhs expr 3. use a map to store width of var and expr */ - case FirStmt(lhs, op, rhs, prefix) => + case WeakStmt(lhs, op, rhs, prefix) => val lr = (getExprWidth(typeMap, lhs), getExprWidth(typeMap, rhs)) match { // only check if both result are numbers case lrWidth @ (i, j) => diff --git a/src/main/scala/dependentChisel/staticAnalysis/checkUnInitAnalysis.scala b/src/main/scala/dependentChisel/staticAnalysis/checkUnInitAnalysis.scala index bc453c5..fba74cd 100644 --- a/src/main/scala/dependentChisel/staticAnalysis/checkUnInitAnalysis.scala +++ b/src/main/scala/dependentChisel/staticAnalysis/checkUnInitAnalysis.scala @@ -1,13 +1,13 @@ package dependentChisel.staticAnalysis -import dependentChisel.codegen.seqCommands.AtomicCmds +import dependentChisel.codegen.sequentialCommands.AtomicCmds import dependentChisel.staticAnalysis.MonotoneFramework.domainMapT import dependentChisel.staticAnalysis.checkUnInitLattice import dependentChisel.staticAnalysis.MonotoneFramework.MonoFrameworkT -import dependentChisel.codegen.seqCommands.NewInstStmt -import dependentChisel.codegen.seqCommands.FirStmt -import dependentChisel.codegen.seqCommands.VarDecls +import dependentChisel.codegen.sequentialCommands.NewInstance +import dependentChisel.codegen.sequentialCommands.WeakStmt +import dependentChisel.codegen.sequentialCommands.VarDecls /** check if vars have an value */ @@ -27,7 +27,7 @@ object checkUnInitAnalysis { : ((Int, mStmt, Int), domainMapT[mDomain]) => domainMapT[mDomain] = { case ((q0, cmd, q1), varmap) => cmd match { - case FirStmt(lhs, op, rhs, prefix) => + case WeakStmt(lhs, op, rhs, prefix) => if op == ":=" then varmap.updated(lhs.getname, true) else varmap // case NewInstStmt(instNm, modNm) => // case VarDecls(v) => diff --git a/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala b/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala index 499b1f5..649709a 100644 --- a/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala +++ b/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala @@ -2,7 +2,7 @@ package dependentChisel.staticAnalysis import com.doofin.stdScala.mainRunnable -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* import dependentChisel.algo.seqCmd2tree.AST import dependentChisel.typesAndSyntax.typesAndOps.* diff --git a/src/main/scala/dependentChisel/staticAnalysis/test.worksheet.sc b/src/main/scala/dependentChisel/staticAnalysis/test.worksheet.sc index bd86d86..b2d4911 100644 --- a/src/main/scala/dependentChisel/staticAnalysis/test.worksheet.sc +++ b/src/main/scala/dependentChisel/staticAnalysis/test.worksheet.sc @@ -1,6 +1,6 @@ import dependentChisel.typesAndSyntax.typesAndOps.Lit import dependentChisel.typesAndSyntax.typesAndOps.VarLit -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* import dependentChisel.staticAnalysis.checkUnInitAnalysis import com.doofin.stdScalaCross.* @@ -25,7 +25,7 @@ val initMap: Map[String, Boolean] = */ val pg = List( - (0, FirStmt(VarLit("x"), ":=", Lit[1](1)), 1), + (0, WeakStmt(VarLit("x"), ":=", Lit[1](1)), 1), (1, Skip, 3), (0, Skip, 2), (2, Skip, 4), diff --git a/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala b/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala index b5e3b27..c142ce0 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala @@ -8,8 +8,8 @@ import dependentChisel.typesAndSyntax.statements.* import dependentChisel.typesAndSyntax.control.* import dependentChisel.codegen.firrtlTypes.* -import dependentChisel.codegen.seqCommands.* -import dependentChisel.codegen.seqCommands +import dependentChisel.codegen.sequentialCommands.* +import dependentChisel.codegen.sequentialCommands import scala.reflect.ClassTag import dependentChisel.global.getUid @@ -22,45 +22,53 @@ import scala.util.Try import scala.util.Failure import scala.util.Success -/** imperative style for chisel ,record info in mutable vars inside class chiselModules +/** IR for current implementation + * + * imperative chisel like DSL, which records info in mutable vars inside class chiselModules during + * construction */ object chiselModules { - /** global info - * - */ + + /** global info like list of all module + * + * @param names + * @param modules + */ case class GlobalInfo( names: ArrayBuffer[String] = ArrayBuffer(), modules: ArrayBuffer[UserModule] = ArrayBuffer() ) - /** - * represent info for each module instance + + /** AST(Abstract Syntax Tree) for each module, contains all info about a module + * + * @param commands: + * list of statements, to represent the circuits */ case class ModuleData( className: String, - thisInstanceName: String, + instanceName: String, io: ArrayBuffer[IOdef] = ArrayBuffer(), - commands: ArrayBuffer[Cmds] = ArrayBuffer(), // list of seq cmds + commands: ArrayBuffer[Cmds] = ArrayBuffer(), // list of statements typeMap: mutable.Map[Expr[?] | Var[?], Int] = mutable.Map() // list of seq cmds ) - // trait Module {} - /* function style UserModule ,for example: when {} else {} */ trait UserModule(using parent: GlobalInfo) extends UserModuleOps, UserModuleDecls { + val classSimpleName = this.getClass.getCanonicalName.split('.').last.mkString + val thisClassName = - (Try( - this.getClass.getCanonicalName.split('.').last.mkString - ) match + (Try(classSimpleName) match { case Failure(exception) => "noName" case Success(value) => value - ) + naming.getIdWithDash + }) + naming.getIdWithDash /** Name for this Instance after new class.. */ val thisInstanceName = naming.mkUidFrom(thisClassName) - if (global.debugVerbose) println(s"new inst $thisInstanceName for $thisClassName") + if (global.debugVerbose) + println(s"new inst $thisInstanceName for $thisClassName") given modLocalInfo: ModuleData = - ModuleData(className = thisClassName, thisInstanceName = thisInstanceName) + ModuleData(className = thisClassName, instanceName = thisInstanceName) // def name = this.getClass.getCanonicalName.split('.').last val globalInfo = parent @@ -70,9 +78,9 @@ object chiselModules { def pushBlk(ctr: Ctrl)(block: => Any) = { val uid = naming.getIntId - pushCmd(seqCommands.Start(ctr, uid)) + pushCmd(sequentialCommands.Start(ctr, uid)) block - pushCmd(seqCommands.End(ctr, uid)) + pushCmd(sequentialCommands.End(ctr, uid)) } add2parent(parent, this) diff --git a/src/main/scala/dependentChisel/typesAndSyntax/control.scala b/src/main/scala/dependentChisel/typesAndSyntax/control.scala index 5824c63..9c34352 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/control.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/control.scala @@ -5,7 +5,7 @@ import com.doofin.stdScalaCross.* import dependentChisel.typesAndSyntax.typesAndOps.* import dependentChisel.typesAndSyntax.statements.* -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* import dependentChisel.typesAndSyntax.chiselModules.* import dependentChisel.syntax.naming @@ -31,7 +31,7 @@ object control { def newMod[M <: UserModule](newMod: M) = { /* m1.clock <= clock m1.reset <= reset */ - pushCmd(NewInstStmt(newMod.thisInstanceName, newMod.thisClassName)) + pushCmd(NewInstance(newMod.thisInstanceName, newMod.thisClassName)) newMod } diff --git a/src/main/scala/dependentChisel/typesAndSyntax/statements.scala b/src/main/scala/dependentChisel/typesAndSyntax/statements.scala index 954e45a..6590c50 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/statements.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/statements.scala @@ -9,7 +9,7 @@ import com.doofin.stdScalaJvm.* import dependentChisel.* import dependentChisel.typesAndSyntax.chiselModules.* import typesAndOps.* -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* import codegen.firrtlTypes.* import dependentChisel.syntax.naming import dependentChisel.misc.macros @@ -32,7 +32,7 @@ object statements { // dbg(v) // dbg(oth) // mli.typeMap.addOne(v, constValueOpt[w].get) - mli.commands += FirStmt(v, ":=", oth) + mli.commands += WeakStmt(v, ":=", oth) } } @@ -43,7 +43,7 @@ object statements { val name = v.getname mli.typeMap.addOne(v, v.width) - mli.commands += FirStmt(v, ":=", oth) + mli.commands += WeakStmt(v, ":=", oth) } } } diff --git a/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala b/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala index 3b29528..a9d7e91 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala @@ -5,7 +5,7 @@ import com.doofin.stdScalaCross.* import dependentChisel.typesAndSyntax.typesAndOps.* import dependentChisel.typesAndSyntax.statements.* -import dependentChisel.codegen.seqCommands.* +import dependentChisel.codegen.sequentialCommands.* import dependentChisel.typesAndSyntax.chiselModules.* import dependentChisel.syntax.naming @@ -50,7 +50,7 @@ object varDecls { val genName = naming.genNameForVar(givenName, tp) val r = VarTyped[w]( - mli.thisInstanceName + "." + genName, + mli.instanceName + "." + genName, tp ) val width = constValueOpt[w].getOrElse(valueOf[w]) // .orElse(widthOpt) @@ -68,7 +68,7 @@ object varDecls { val r = VarDymTyped( width, tp, - mli.thisInstanceName + "." + genName + mli.instanceName + "." + genName ) // when refered in expr , use this name mli.typeMap.addOne(r, width) From 88cd0e46a4995c6bea637e1f0e47e12198264e36 Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 11:50:02 +0800 Subject: [PATCH 03/10] refactor: Rename cld to children for improved clarity and consistency; update related comments and usages --- src/main/scala/dependentChisel/algo/Tree.scala | 2 +- .../scala/dependentChisel/algo/seqCmd2tree.scala | 12 +++++++----- .../scala/dependentChisel/codegen/compiler.scala | 8 ++++---- .../dependentChisel/codegen/sequentialCommands.scala | 6 +++++- .../dependentChisel/monadic/monadicCompilers.scala | 4 ++-- .../dependentChisel/staticAnalysis/progGraph.scala | 4 ++-- .../typesAndSyntax/chiselModules.scala | 4 ++-- .../dependentChisel/typesAndSyntax/statements.scala | 10 +++++----- .../dependentChisel/typesAndSyntax/varDecls.scala | 12 ++++++------ .../scala/dependentChisel/examples/BubbleFifo.scala | 11 +++++++++-- 10 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/main/scala/dependentChisel/algo/Tree.scala b/src/main/scala/dependentChisel/algo/Tree.scala index 9614287..ca391c4 100644 --- a/src/main/scala/dependentChisel/algo/Tree.scala +++ b/src/main/scala/dependentChisel/algo/Tree.scala @@ -5,6 +5,6 @@ import scala.collection.mutable.ArrayBuffer object Tree { case class TreeNode[t]( val value: t, - val cld: ArrayBuffer[TreeNode[t]] = ArrayBuffer[TreeNode[t]]() + val children: ArrayBuffer[TreeNode[t]] = ArrayBuffer[TreeNode[t]]() ) } diff --git a/src/main/scala/dependentChisel/algo/seqCmd2tree.scala b/src/main/scala/dependentChisel/algo/seqCmd2tree.scala index bad7d41..857ed18 100644 --- a/src/main/scala/dependentChisel/algo/seqCmd2tree.scala +++ b/src/main/scala/dependentChisel/algo/seqCmd2tree.scala @@ -7,17 +7,19 @@ import com.doofin.stdScalaCross.* import dependentChisel.codegen.sequentialCommands.* -/** algorithm to convert sequential commands to AST */ +/** algorithm to convert sequential commands to AST in tree structure + */ object seqCmd2tree { type AST = TreeNode[NewInstance | WeakStmt | Ctrl | VarDecls] /** convert sequential commands to AST. multiple stmt is appended as multiple nodes + * + * @param cmdList + * list of sequential commands which implicitly has stack structure */ def list2tree(cmdList: List[Cmds]): AST = { import scala.collection.mutable.Stack val parents: Stack[AST] = Stack(TreeNode(Ctrl.Top())) // new Stack[AST] - // parents.push(TreeNode(Ctrl.Top())) - // ppc(cmdList) cmdList.foreach { cmd => // dbg(cmd) @@ -27,7 +29,7 @@ object seqCmd2tree { then push new node into parent stack as new top elem*/ val newParNode: AST = TreeNode(ctrl) // new parent node // add this newParNode as child - parents.top.cld += newParNode + parents.top.children += newParNode parents push newParNode case End(ctrl, uid) => // end of block, pop out one parent @@ -35,7 +37,7 @@ object seqCmd2tree { // for other stmt,just append case stmt: (WeakStmt | NewInstance | VarDecls) => val newNd: AST = TreeNode(stmt) - parents.top.cld += newNd + parents.top.children += newNd case _ => } diff --git a/src/main/scala/dependentChisel/codegen/compiler.scala b/src/main/scala/dependentChisel/codegen/compiler.scala index 6a5819e..f6bef9a 100644 --- a/src/main/scala/dependentChisel/codegen/compiler.scala +++ b/src/main/scala/dependentChisel/codegen/compiler.scala @@ -39,11 +39,11 @@ object compiler { /** chisel ModLocalInfo to FirrtlModule(IO bundle,AST for the circuit) */ def chiselMod2firrtlCircuits(chiselMod: UserModule, printCmdList: Boolean = false) = { - val modInfo: ModuleData = chiselMod.modLocalInfo + val modInfo: ModuleData = chiselMod.moduleData val allMods: List[UserModule] = chiselMod.globalInfo.modules.toList val typeMap = - allMods.map(_.modLocalInfo.typeMap) reduce (_ ++ _) + allMods.map(_.moduleData.typeMap) reduce (_ ++ _) val mainModuleName = modInfo.className @@ -72,7 +72,7 @@ object compiler { typeMap: mutable.Map[Expr[?], Int], printCmdList: Boolean )(chiselMod: UserModule): FirrtlModule = { - val modInfo: ModuleData = chiselMod.modLocalInfo + val modInfo: ModuleData = chiselMod.moduleData // pp(modInfo.typeMap) val cmdList = modInfo.commands.toList if printCmdList then pp(modInfo.commands.toList) @@ -173,7 +173,7 @@ object compiler { indent + varDecl2firrtlStr(indent, stmt) } - nodeStr + (tr.cld map (cld => "\n" + tree2firrtlStr(cld, indent + " "))).mkString + nodeStr + (tr.children map (cld => "\n" + tree2firrtlStr(cld, indent + " "))).mkString } /** rm module or instance names from io name, for usage in gen firrtl io section diff --git a/src/main/scala/dependentChisel/codegen/sequentialCommands.scala b/src/main/scala/dependentChisel/codegen/sequentialCommands.scala index 0b34602..7db02bd 100644 --- a/src/main/scala/dependentChisel/codegen/sequentialCommands.scala +++ b/src/main/scala/dependentChisel/codegen/sequentialCommands.scala @@ -5,7 +5,11 @@ import com.doofin.stdScalaCross.* import dependentChisel.typesAndSyntax.statements.* import dependentChisel.global -/** sequential commands used in chisel UserModule to build circuit */ +/** sequential commands used in chisel UserModule to build circuit + * + * nested control structures are implemented using start/end commands which is implicitly a stack, + * so we can later convert it to a tree with seqCmd2tree + */ object sequentialCommands { type Uid = Int diff --git a/src/main/scala/dependentChisel/monadic/monadicCompilers.scala b/src/main/scala/dependentChisel/monadic/monadicCompilers.scala index ff4c1ee..69df472 100644 --- a/src/main/scala/dependentChisel/monadic/monadicCompilers.scala +++ b/src/main/scala/dependentChisel/monadic/monadicCompilers.scala @@ -76,14 +76,14 @@ object monadicCompilers { then push new node into parent stack as new top elem*/ val newParNode: AST = TreeNode(ctrl) // new parent node // add this newParNode as child - parents.top.cld += newParNode + parents.top.children += newParNode parents push newParNode case End(ctrl) => // end of block, pop out one parent parents.pop() // for other stmt,just append case stmt => - parents.top.cld += TreeNode(stmt) + parents.top.children += TreeNode(stmt) } } diff --git a/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala b/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala index 649709a..01cbef6 100644 --- a/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala +++ b/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala @@ -79,10 +79,10 @@ object progGraph extends mainRunnable { case x: Ctrl => x match { case Ctrl.Top() => - val r = ast.cld.zipWithIndex flatMap ((x, i) => ast2progGraph(q + i, x)) + val r = ast.children.zipWithIndex flatMap ((x, i) => ast2progGraph(q + i, x)) List((p, Skip, q)) ++ r.toList case _ => - val r = ast.cld.zipWithIndex flatMap ((x, i) => ast2progGraph(q + i, x)) + val r = ast.children.zipWithIndex flatMap ((x, i) => ast2progGraph(q + i, x)) List((p, Skip, q)) ++ r.toList } diff --git a/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala b/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala index c142ce0..4b7741b 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/chiselModules.scala @@ -67,13 +67,13 @@ object chiselModules { if (global.debugVerbose) println(s"new inst $thisInstanceName for $thisClassName") - given modLocalInfo: ModuleData = + given moduleData: ModuleData = ModuleData(className = thisClassName, instanceName = thisInstanceName) // def name = this.getClass.getCanonicalName.split('.').last val globalInfo = parent def pushCmd(cmd: Cmds) = { - modLocalInfo.commands.append(cmd) + moduleData.commands.append(cmd) } def pushBlk(ctr: Ctrl)(block: => Any) = { diff --git a/src/main/scala/dependentChisel/typesAndSyntax/statements.scala b/src/main/scala/dependentChisel/typesAndSyntax/statements.scala index 6590c50..1b9f7ca 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/statements.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/statements.scala @@ -21,7 +21,7 @@ object statements { /** typed API for assign */ extension [w <: Int, V <: Var[w]](v: V) { - inline def :=(using mli: ModuleData)(oth: Expr[w]) = { + inline def :=(using md: ModuleData)(oth: Expr[w]) = { val name = v.getname /* v match { @@ -32,18 +32,18 @@ object statements { // dbg(v) // dbg(oth) // mli.typeMap.addOne(v, constValueOpt[w].get) - mli.commands += WeakStmt(v, ":=", oth) + md.commands += WeakStmt(v, ":=", oth) } } /** untyped API for assign */ extension (v: VarDymTyped) { - inline def :=(using mli: ModuleData)(oth: Expr[?]) = { + inline def :=(using md: ModuleData)(oth: Expr[?]) = { val name = v.getname - mli.typeMap.addOne(v, v.width) + md.typeMap.addOne(v, v.width) - mli.commands += WeakStmt(v, ":=", oth) + md.commands += WeakStmt(v, ":=", oth) } } } diff --git a/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala b/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala index a9d7e91..9254919 100644 --- a/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala +++ b/src/main/scala/dependentChisel/typesAndSyntax/varDecls.scala @@ -89,8 +89,8 @@ object varDecls { ) val width = constValueOpt[w].getOrElse(valueOf[w]) // .orElse(widthOpt) - modLocalInfo.typeMap.addOne(r, width) - modLocalInfo.commands.append(VarDecls(r.toDym(width))) + moduleData.typeMap.addOne(r, width) + moduleData.commands.append(VarDecls(r.toDym(width))) r } @@ -98,8 +98,8 @@ object varDecls { // need to push this cmd for varDecl val genName = naming.genNameForVar(givenName, VarType.Reg) val r = VarDymTyped(width, VarType.Reg, genName) - modLocalInfo.typeMap.addOne(r, width) - modLocalInfo.commands.append(VarDecls(r)) + moduleData.typeMap.addOne(r, width) + moduleData.commands.append(VarDecls(r)) r } @@ -108,8 +108,8 @@ object varDecls { val width = init.width val genName = naming.genNameForVar(givenName, VarType.Reg) val r = VarDymTyped(width, VarType.RegInit(init), genName) - modLocalInfo.typeMap.addOne(r, width) - modLocalInfo.commands.append(VarDecls(r)) + moduleData.typeMap.addOne(r, width) + moduleData.commands.append(VarDecls(r)) r } diff --git a/src/test/scala/dependentChisel/examples/BubbleFifo.scala b/src/test/scala/dependentChisel/examples/BubbleFifo.scala index 0743a73..cba9e11 100644 --- a/src/test/scala/dependentChisel/examples/BubbleFifo.scala +++ b/src/test/scala/dependentChisel/examples/BubbleFifo.scala @@ -20,6 +20,7 @@ object BubbleFifo extends mainRunnable { val mod = makeModule { implicit p => new BubbleFifo(2, 3) // ok } + pprint.pprintln(chiselMod2firrtlCircuits(mod)) chiselMod2verilog(mod) } @@ -83,8 +84,14 @@ object BubbleFifo extends mainRunnable { deq.dout := dataReg } - class BubbleFifo(using GlobalInfo)(size: Int :| Positive, depth: Int) - extends UserModule { + /** an typed bubble fifo example + * + * @param x + * @param size + * guaranteed to be positive + * @param depth + */ + class BubbleFifo(using GlobalInfo)(size: Int :| Positive, depth: Int) extends UserModule { val enq = new WriterIO(size) val deq = new ReaderIO(size) From 240550f16e12959a86c841a9380f14450b7080ff Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 11:55:08 +0800 Subject: [PATCH 04/10] refactor: Rename CI job from 'test' to 'Compile' for clarity; update unit test step name --- .github/workflows/ci.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f02872c..1358293 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ env: jobs: run: - name: test + name: Compile strategy: matrix: java-version: [17] @@ -27,5 +27,10 @@ jobs: java-version: ${{ matrix.java-version }} cache: sbt - - name: Run the unit tests + # cache sbt dependencies + - uses: coursier/cache-action@v6 + + - uses: sbt/setup-sbt@v1 + + - name: unit test run: sbt test From d2b13fb7338e4c32b6d7216d6db0335564ef9f5d Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 11:56:09 +0800 Subject: [PATCH 05/10] refactor: Remove pull_request trigger from CI workflow for simplification --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1358293..c0bf39d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,6 @@ name: Continuous Integration on: - pull_request: push: env: From a4350715ced87a174a8114badc3281bb6f2c6089 Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 11:59:31 +0800 Subject: [PATCH 06/10] refactor: Replace seqCmd2tree with stackList2tree for improved algorithm clarity --- .../algo/{seqCmd2tree.scala => stackList2tree.scala} | 6 ++++-- src/main/scala/dependentChisel/codegen/compiler.scala | 2 +- src/main/scala/dependentChisel/codegen/firrtlTypes.scala | 2 +- .../scala/dependentChisel/staticAnalysis/progGraph.scala | 4 ++-- src/test/scala/dependentChisel/examples/ifTest.scala | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) rename src/main/scala/dependentChisel/algo/{seqCmd2tree.scala => stackList2tree.scala} (90%) diff --git a/src/main/scala/dependentChisel/algo/seqCmd2tree.scala b/src/main/scala/dependentChisel/algo/stackList2tree.scala similarity index 90% rename from src/main/scala/dependentChisel/algo/seqCmd2tree.scala rename to src/main/scala/dependentChisel/algo/stackList2tree.scala index 857ed18..7e0d1c3 100644 --- a/src/main/scala/dependentChisel/algo/seqCmd2tree.scala +++ b/src/main/scala/dependentChisel/algo/stackList2tree.scala @@ -9,13 +9,15 @@ import dependentChisel.codegen.sequentialCommands.* /** algorithm to convert sequential commands to AST in tree structure */ -object seqCmd2tree { +object stackList2tree { type AST = TreeNode[NewInstance | WeakStmt | Ctrl | VarDecls] - /** convert sequential commands to AST. multiple stmt is appended as multiple nodes + /** convert sequential commands to AST. * * @param cmdList * list of sequential commands which implicitly has stack structure + * @return + * AST tree structure where parent node has multiple children nodes */ def list2tree(cmdList: List[Cmds]): AST = { import scala.collection.mutable.Stack diff --git a/src/main/scala/dependentChisel/codegen/compiler.scala b/src/main/scala/dependentChisel/codegen/compiler.scala index f6bef9a..61332e2 100644 --- a/src/main/scala/dependentChisel/codegen/compiler.scala +++ b/src/main/scala/dependentChisel/codegen/compiler.scala @@ -9,7 +9,7 @@ import dependentChisel.typesAndSyntax.statements.* import dependentChisel.global import dependentChisel.typesAndSyntax.chiselModules.* -import dependentChisel.algo.seqCmd2tree.* +import dependentChisel.algo.stackList2tree.* import sequentialCommands.* import firrtlTypes.* diff --git a/src/main/scala/dependentChisel/codegen/firrtlTypes.scala b/src/main/scala/dependentChisel/codegen/firrtlTypes.scala index ca5870f..c845f51 100644 --- a/src/main/scala/dependentChisel/codegen/firrtlTypes.scala +++ b/src/main/scala/dependentChisel/codegen/firrtlTypes.scala @@ -1,6 +1,6 @@ package dependentChisel.codegen -import dependentChisel.algo.seqCmd2tree.AST +import dependentChisel.algo.stackList2tree.AST import com.doofin.stdScalaCross.* import dependentChisel.typesAndSyntax.chiselModules.ModuleData import dependentChisel.typesAndSyntax.typesAndOps.VarType diff --git a/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala b/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala index 01cbef6..c06cd42 100644 --- a/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala +++ b/src/main/scala/dependentChisel/staticAnalysis/progGraph.scala @@ -3,7 +3,7 @@ package dependentChisel.staticAnalysis import com.doofin.stdScala.mainRunnable import dependentChisel.codegen.sequentialCommands.* -import dependentChisel.algo.seqCmd2tree.AST +import dependentChisel.algo.stackList2tree.AST import dependentChisel.typesAndSyntax.typesAndOps.* import dependentChisel.* @@ -18,7 +18,7 @@ import dependentChisel.typesAndSyntax.control.* import dependentChisel.codegen.compiler.* -import algo.seqCmd2tree.* +import algo.stackList2tree.* import dependentChisel.typesAndSyntax.chiselModules.* import dependentChisel.codegen.firrtlTypes.FirrtlCircuit diff --git a/src/test/scala/dependentChisel/examples/ifTest.scala b/src/test/scala/dependentChisel/examples/ifTest.scala index e8f5758..151020a 100644 --- a/src/test/scala/dependentChisel/examples/ifTest.scala +++ b/src/test/scala/dependentChisel/examples/ifTest.scala @@ -13,7 +13,7 @@ import dependentChisel.typesAndSyntax.chiselModules.* import dependentChisel.codegen.compiler.* -import algo.seqCmd2tree.* +import algo.stackList2tree.* object ifTest extends mainRunnable { override def main(args: Array[String] = Array()): Unit = run From f123a1e4ace04c8138ecc604f76f976a76b72206 Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 12:21:29 +0800 Subject: [PATCH 07/10] refactor: Remove redundant import and add tree traversal algorithms --- .../dependentChisel/algo/stackList2tree.scala | 2 +- .../dependentChisel/algo/treeTraverse.scala | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/dependentChisel/algo/treeTraverse.scala diff --git a/src/main/scala/dependentChisel/algo/stackList2tree.scala b/src/main/scala/dependentChisel/algo/stackList2tree.scala index 7e0d1c3..3d16f0a 100644 --- a/src/main/scala/dependentChisel/algo/stackList2tree.scala +++ b/src/main/scala/dependentChisel/algo/stackList2tree.scala @@ -1,6 +1,7 @@ package dependentChisel.algo import scala.util.* +import scala.collection.mutable.Stack import Tree.* import com.doofin.stdScalaCross.* @@ -20,7 +21,6 @@ object stackList2tree { * AST tree structure where parent node has multiple children nodes */ def list2tree(cmdList: List[Cmds]): AST = { - import scala.collection.mutable.Stack val parents: Stack[AST] = Stack(TreeNode(Ctrl.Top())) // new Stack[AST] cmdList.foreach { cmd => diff --git a/src/main/scala/dependentChisel/algo/treeTraverse.scala b/src/main/scala/dependentChisel/algo/treeTraverse.scala new file mode 100644 index 0000000..b2b959e --- /dev/null +++ b/src/main/scala/dependentChisel/algo/treeTraverse.scala @@ -0,0 +1,46 @@ +package dependentChisel.algo + +import scala.collection.mutable.ArrayBuffer + +/** tree traversal algorithms + */ +object treeTraverse { + + /** imperitive pre-order traversal + * + * @param node + * @param visit + */ + def preOrder[t](visit: t => Unit, node: Tree.TreeNode[t]): Unit = { + visit(node.value) + node.children.foreach(preOrder(visit, _)) + } + + /** filter tree nodes based on predicate + * + * TODO: test this function + * @param predicate + * @param node + * @return + * tree with nodes filtered + */ + def filter[t]( + predicate: t => Boolean, + node: Tree.TreeNode[t] + ): Tree.TreeNode[t] = { + val flag @ (yes, hasChild) = (predicate(node.value), node.children.nonEmpty) + + // if children is empty, it's leaf node, just return itself if satisfies predicate + if hasChild then { + // recursively filter its children + val filteredChildren = node.children + .map(child => filter(predicate, child)) + .filter(child => predicate(child.value) || child.children.nonEmpty) + Tree.TreeNode(node.value, filteredChildren) + } else { + // leaf node, just return itself if satisfies predicate + if yes then node else Tree.TreeNode(node.value, ArrayBuffer()) + } + + } +} From 14a5bf7c9077696c65072774d3361b0e533c6c89 Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 16:27:03 +0800 Subject: [PATCH 08/10] docs: Update README to clarify project purpose and architecture --- README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d5a7854..9286c19 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,24 @@ # dependentChisel -This is the impl for Master thesis : Dependent Chisel: Statically-checked hardware designs based on Chisel and Scala 3, by Yuchen du +This is an ongoing research project to bring dependent type features to hardware design in Chisel-like syntax, as an embedded DSL(eDSL) in Scala 3. + +It originally started as Master thesis "Dependent Chisel: Statically-checked hardware designs based on Chisel and Scala 3", by Yuchen du in 2023 https://github.com/doofin/dependentChisel/blob/master/Msc_Thesis_yuchen.pdf -It uses partial dependent types in Scala 3 to provide early error message for Chisel, a hardware description language embedded in Scala. -This allows you to identify bitwidth mismatch at compile time where IDE can show errors instantly in the editor. +## Design +The main philosophy is to make it clean and simple, and avoid complex language features. The core intermediate representation is an algebraic AST, which is easy to analyze and transform. + +**algebraic AST** + +The layer of DSL translation: + +Chisel-like syntax -> list of commands as stack data structure -> Algebraic AST (FIRRTL like IR in Scala ADT) + +when we have the algebraic AST, it's convenient to do various analysis, transformation and finally code generation to FIRRTL. This algebraic AST is similar to FIRRTL IR in Chisel, but Chisel seems to discourage direct manipulation of FIRRTL IR AST, while we embrace it. + +**dependent types** + +It uses partial dependent types in Scala 3 to provide early error message, which can be directly shown in IDE when writing code, allowing you to catch bitwidth mismatch at compile time. ## examples examples like adder, etc. can be found in src/test/scala/dependentChisel/ @@ -85,6 +99,9 @@ many tests under src/test can be run by ## theories and related work related work : https://github.com/doofin/dependentChisel/blob/master/resources.md +similar projects: +- [zaozi] : https://github.com/sequencer/zaozi + ## misc From 8f4b90399c8a9f85c404237ae67846b5d4ef2593 Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 16:30:55 +0800 Subject: [PATCH 09/10] docs: Update README for clarity on Chisel interop and IDE support --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9286c19..4120f93 100644 --- a/README.md +++ b/README.md @@ -69,13 +69,12 @@ Instantiate those modules : ## Interop with chisel -The current implementation is based on Chisel 3.5.1, which is used internally. There's no direct interop with the original Chisel, but you can probably use the generated FIRRTL for that. +The current implementation is based on Chisel 3.5.1, which is used internally. There's no direct interop with the original Chisel, but you can probably use the generated FIRRTL for interop. -Although scala 3 can invoke scala 2.13 libraries,chisel uses scala 2 macros different from scala 3 ,making it partially incompatible. +Although scala 3 can invoke scala 2.13 libraries,chisel uses scala 2 macros which is different from scala 3 ,making it incompatible. To fix the mismatch, there are several possible ways: - - Rewrite all macros and make everything compatible. - Rewrite some macros and extend some base class. - Write a new frontend and emit FIRRTL. @@ -92,16 +91,16 @@ many tests under src/test can be run by ### IDE support +recommended IDEs: [Metals](https://scalameta.org/metals/) with vscode -[IntelliJ](https://blog.jetbrains.com/scala/) - ## theories and related work related work : https://github.com/doofin/dependentChisel/blob/master/resources.md similar projects: - [zaozi] : https://github.com/sequencer/zaozi +and more are listed in the thesis pdf. ## misc @@ -109,4 +108,4 @@ with git ls-files | grep '\.scala$' | xargs wc -l -chisel has 60927 total loc +chisel has 60927 total loc, while dependentChisel only has 3765 total loc, so it's a good idea to understand dependentChisel before diving into chisel codebase. From 93122975e8fe5b0743e28c7efe3a2e3928aa105b Mon Sep 17 00:00:00 2001 From: doofin <8177dph@gmail.com> Date: Tue, 18 Nov 2025 16:32:49 +0800 Subject: [PATCH 10/10] refactor: Clean up code formatting and improve readability in compiler.scala --- .../dependentChisel/codegen/compiler.scala | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/scala/dependentChisel/codegen/compiler.scala b/src/main/scala/dependentChisel/codegen/compiler.scala index 61332e2..5e81533 100644 --- a/src/main/scala/dependentChisel/codegen/compiler.scala +++ b/src/main/scala/dependentChisel/codegen/compiler.scala @@ -106,7 +106,6 @@ object compiler { val instName: String = fMod.modInfo.instanceName // name changes for io val ioInfoStr = fMod.io.reverse // looks better .map { (x: IOdef) => - val prefix = x.tpe match { case VarType.Input => "flip" case VarType.Output => "" @@ -147,9 +146,7 @@ object compiler { val anf_stmts: List[WeakStmt] = stmtToSingleAssign(expr2stmtBind(bool)) val anf_res = - anf_stmts :+ orig.copy(ctrl = - ctrlIf.copy(cond = anf_stmts.last.lhs.asTypedUnsafe[1]) - ) + anf_stmts :+ orig.copy(ctrl = ctrlIf.copy(cond = anf_stmts.last.lhs.asTypedUnsafe[1])) // dbg(anf_res) anf_res case _ => List(orig) // bug! will eat "else" @@ -167,7 +164,7 @@ object compiler { case Ctrl.Else() => "else :" case Ctrl.Top() => "" }) - case stmt: WeakStmt => indent + stmt2firrtlStr(stmt) + case stmt: WeakStmt => indent + stmt2firrtlStr(stmt) case stmt: NewInstance => newInstStmt2firrtlStr(indent, stmt) + "\n" case stmt: VarDecls => indent + varDecl2firrtlStr(indent, stmt) @@ -188,11 +185,11 @@ object compiler { else fullName */ - if fullName.contains(".") then + if fullName.contains(".") then { val (instNameSplit, name) = splitName(fullName) if instNameSplit == instName then "io." + name else fullName - else fullName + } else fullName } def expr2firrtlStr(expr: Expr[?]): String = { @@ -216,13 +213,13 @@ object compiler { } } - /** Compute the log2 of a Scala integer, rounded up. Useful for getting the number of - * bits needed to represent some number of states (in - 1). To get the number of bits - * needed to represent some number n, use log2Ceil(n + 1). Note: can return zero, and - * should not be used in cases where it may generate unsupported zero-width wires. + /** Compute the log2 of a Scala integer, rounded up. Useful for getting the number of bits needed + * to represent some number of states (in - 1). To get the number of bits needed to represent + * some number n, use log2Ceil(n + 1). Note: can return zero, and should not be used in cases + * where it may generate unsupported zero-width wires. * @example - * {{{ log2Ceil(1) // returns 0 log2Ceil(2) // returns 1 log2Ceil(3) // returns 2 - * log2Ceil(4) // returns 2 }}} + * {{{ log2Ceil(1) // returns 0 log2Ceil(2) // returns 1 log2Ceil(3) // returns 2 log2Ceil(4) + * // returns 2 }}} */ object log2Ceil { // (0 until n).map(_.U((1.max(log2Ceil(n))).W)) @@ -349,8 +346,8 @@ object compiler { } } - /** if lhs is IO,change := to <= and make new conn io.y:=a+b becomes y0=a+b;io.y<=y0 new - * : don't do above + /** if lhs is IO,change := to <= and make new conn io.y:=a+b becomes y0=a+b;io.y<=y0 new : don't + * do above */ def IOassignTransform(stmt: WeakStmt): List[WeakStmt] = { stmt.lhs match { @@ -400,8 +397,8 @@ object compiler { } } - /** modify names for io: check if instantiated instance have same name, if so refer to - * it by io.a, otherwise add inst name as prefix + /** modify names for io: check if instantiated instance have same name, if so refer to it by io.a, + * otherwise add inst name as prefix */ def ioNameTransform(thisInstName: String, ioFullName: String) = { val instName :: name :: Nil = ioFullName.split('.').toList: @unchecked