DFiantHDL / DFHDL

DFiant HDL (DFHDL): A Dataflow Hardware Descripition Language
https://dfianthdl.github.io/
GNU Lesser General Public License v3.0
78 stars 8 forks source link

Compile error when using struct fields in nested if #116

Closed MartinC45 closed 5 months ago

MartinC45 commented 5 months ago

Description

Trying to use a field of a struct in a level other than the outermost one of a nested if yields an error. It works fine otherwise and also works when assigning the field to a variable and using that variable in an inner level.

Example

//> using scala 3.4.0
//> using lib io.github.dfianthdl::dfhdl::0.4.3
//> using plugin io.github.dfianthdl:::dfhdl-plugin:0.4.3
//> using option -deprecation -language:implicitConversions

import dfhdl.* //import all the DFHDL goodness

case class Test (
  a : Bit <> VAL,
  b : Bit <> VAL
) extends Struct

class GlobCounter (val width: Int <> CONST) extends RTDesign:
  val req = Bit <> IN
  val req2 = Bit <> IN
  val t = Test <> IN
  val t_b = Bit <> VAR
  t_b := t.b
  val t_int = Test <> VAR 
  t_int := t

  val cnt = UInt(width) <> OUT.REG init 0

  // doesn't work
  if (t.a) {
    if (t.b) { 
        cnt.din := cnt + 1
    }
  }

  // doesn't work
//   if (req) {
//     if (t.b) { 
//         cnt.din := cnt + 1
//     }
//   }

  // no if nesting, works
//   if (t.a && t.b) {
//     cnt.din := cnt + 1
//   }

  // works
//   if (t.a) {
//     if (t_b) { 
//         cnt.din := cnt + 1
//     }
//   }

  // doesn't work
//   if (t_int.a) {
//     if (t_int.b) { 
//         cnt.din := cnt + 1
//     }
//   }

  // works
//   if (req) {
//     if (req2) {
//       cnt.din := cnt + 1
//     }
//   }

////////////////////////////////////////////////////////////////////////////////////////////////
// DFHDL Compiler Options:                                                                    //
////////////////////////////////////////////////////////////////////////////////////////////////
// Enables printing the generated chosen backend code:
given options.CompilerOptions.PrintGenFiles = true
// Uncomment to select vhdl compilation (default is verilog):
// given options.CompilerOptions.Backend = backends.vhdl
// Uncomment to enable printing design code before compilation (after elaboration):
// given options.CompilerOptions.PrintDesignCodeBefore = true
// Uncomment to enable printing design code after compilation:
// given options.CompilerOptions.PrintDesignCodeAfter = true
// Uncomment to set different clock and reset configurations:
// given options.CompilerOptions.DefaultClkCfg = ClkCfg(ClkCfg.Edge.Rising)
// given options.CompilerOptions.DefaultRstCfg = RstCfg(RstCfg.Mode.Async, RstCfg.Active.Low)
////////////////////////////////////////////////////////////////////////////////////////////////

//The entry point to your compilation program starts here
@main def main = GlobCounter(64).compile

Output

When run with scala-cli this is the output

[warn] ./GlobCounter.scala:2:11
[warn] Using 'lib' is deprecated, use 'dep' instead
[warn] //> using lib io.github.dfianthdl::dfhdl::0.4.3
[warn]           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compiling project (Scala 3.4.0, JVM (17))
Compiled project (Scala 3.4.0, JVM (17))
Exception in thread "main" java.util.NoSuchElementException: head of empty list
        at scala.collection.immutable.Nil$.head(List.scala:662)
        at scala.collection.immutable.Nil$.head(List.scala:661)
        at dfhdl.compiler.ir.DB.OMLGen(DB.scala:137)
        at dfhdl.compiler.ir.DB.ownerMemberList$lzyINIT1(DB.scala:165)
        at dfhdl.compiler.ir.DB.ownerMemberList(DB.scala:165)
        at dfhdl.compiler.ir.DB.ownerMemberTable$lzyINIT1(DB.scala:190)
        at dfhdl.compiler.ir.DB.ownerMemberTable(DB.scala:190)
        at dfhdl.compiler.ir.DB.getMembersOf(DB.scala:181)
        at dfhdl.compiler.analysis.DFOwnerAnalysis$package$.members(DFOwnerAnalysis.scala:8)
        at dfhdl.compiler.stages.VHDLProcToVerilog$.$anonfun$1(VHDLProcToVerilog.scala:33)
        at scala.collection.immutable.List.flatMap(List.scala:293)
        at dfhdl.compiler.stages.VHDLProcToVerilog$.transform(VHDLProcToVerilog.scala:82)
        at dfhdl.compiler.stages.StageRunner.runSingleStage(StageRunner.scala:22)
        at dfhdl.compiler.stages.StageRunner.dfhdl$compiler$stages$StageRunner$$run(StageRunner.scala:43)
        at dfhdl.compiler.stages.StageRunner$.run(StageRunner.scala:55)
        at dfhdl.backends$verilog.printer(backends.scala:15)
        at dfhdl.compiler.stages.BackendCompiler.compile(BackendCompiler.scala:19)
        at dfhdl.compiler.stages.BackendCompiler.compile$(BackendCompiler.scala:8)
        at dfhdl.backends$verilog.compile(backends.scala:11)
        at dfhdl.compiler.stages.StagedDesign$.compile(StagedDesign.scala:13)
        at dfhdl.ops$package$.compile(ops.scala:10)
        at GlobCounter$package$.main(GlobCounter.scala:82)
        at main.main(GlobCounter.scala:82)
soronpo commented 5 months ago

@MartinC45 Hi. Thank you very much for trying out DFHDL and reporting this! Would fix this very soon.

soronpo commented 5 months ago

BTW, I have a question, if you don't mind answering. Currently our documentation shows nothing about the struct feature (one of the reasons is to first flush out most of the bugs ourselves). How did you go about learning this feature?

MartinC45 commented 5 months ago

Hi, no problem and sure. I found it in some slides you shared on Reddit some time ago. Should I wait until the release of the full documentation before opening further issues?

soronpo commented 5 months ago

Feel free to open issues. Your time is valuable and I don't want to waste it, and I want your experience to be fun. But if you like being on the cutting bleeding edge, hack away :)

soronpo commented 5 months ago

This is a more general problem in the RT to ED compilation stage, and fails in this example:

class GlobCounter(val width: Int <> CONST) extends RTDesign:
  val t = Bit <> IN

  val cnt = UInt(width) <> OUT.REG init 0

  // doesn't work
  if (t || t)
    if (t || t)
      cnt.din := cnt + 1
end GlobCounter

Should be resolved tomorrow.

soronpo commented 5 months ago

@MartinC45 v0.4.4 fixes this issue.

MartinC45 commented 5 months ago

Yes, it works nicely now. Thanks!