Skip to content

[firrtl] Hardware with nested direction generates failing firrtl with Reg / RegNext #5411

Description

@Hamster5295

Type of issue: Bug Report

Please provide the steps to reproduce the problem:

Create an empty Chisel project, then add Foo.scala below:

package foo

import chisel3._
import chisel3.util._

// This is a bundle with nested direction
class BundleWithDirection extends Bundle {
    val a = Input(UInt(3.W))
}

class Foo extends Module {
    val io = IO(new Bundle{
        // And I'd like to make it an input for this module
        // For now this works smoothly
        val in = new BundleWithDirection
        val out = Output(UInt(3.W))
    })

    // In this example we'll simply delay the input for 1 cycle
    val buffer = RegNext(io.in)
    io.out := buffer.a
}

Then generate verilog code using (new ChiselStage).execute( ... ) with argument --target verilog

What is the current behavior?

firtool will throw the following error:

src/main/scala/Foo.scala:18:25: error: 'firrtl.reg' op result #0 must be a passive non-'const' base type that does not contain analog, but got '!firrtl.bundle<a flip: uint<3>>'
    val buffer = RegNext(io.in)
                        ^
src/main/scala/Foo.scala:18:25: note: see current operation: %3 = "firrtl.reg"(%arg0) <{annotations = [], name = "buffer", nameKind = #firrtl<name_kind interesting_name>}> : (!firrtl.clock) -> !firrtl.bundle<a flip: uint<3>>

What is the expected behavior?

The BundleWithDirection bundle only contains Input signal, so RegNext(io.in) should be able to generate verilog code like

reg [2:0] buffer_a;	// src/main/scala/Foo.scala:18:25
always @(posedge clock)	// src/main/scala/Foo.scala:12:7
  buffer_a <= io_in_a;	// src/main/scala/Foo.scala:18:25
assign io_out = buffer_a;	// src/main/scala/Foo.scala:12:7, :18:25

Please tell us about your environment:
- version: 7.7.0
- OS: Linux <hostname> 6.8.0-124-generic #124~22.04.1-Ubuntu SMP x86_64 GNU/Linux

Other Information

The Chisel code above could generate fir code with --target chirrtl:

FIRRTL version 6.0.0
circuit Foo :%[[
  {
    "class":"firrtl.transforms.DedupGroupAnnotation",
    "target":"~|Foo",
    "group":"Foo"
  }
]]
  layer Verification, bind, "verification" :
    layer Assert, bind, "verification/assert" :
      layer Temporal, inline :
    layer Assume, bind, "verification/assume" :
      layer Temporal, inline :
    layer Cover, bind, "verification/cover" :
      layer Temporal, inline :

  public module Foo : @[src/main/scala/Foo.scala 12:7]
    input clock : Clock @[src/main/scala/Foo.scala 12:7]
    input reset : UInt<1> @[src/main/scala/Foo.scala 12:7]
    output io : { in : { flip a : UInt<3>}, out : UInt<3>} @[src/main/scala/Foo.scala 13:16]

    reg buffer : { flip a : UInt<3>}, clock @[src/main/scala/Foo.scala 18:25]
    connect buffer.a, io.in.a @[src/main/scala/Foo.scala 18:25]
    connect io.out, buffer.a @[src/main/scala/Foo.scala 19:12]

It seems that the Input in Chisel code is interpeted as output io : { in : { flip a : UInt<3>}, ...}, and the RegNext clones the type flip a: UInt<3>, which is considered a non-passive signal by firtool, causing it unable to connect buffer.a with io.in.a

This problem persists with val buffer = Reg(chiselTypeOf(io.in))

When removing the flip in reg buffer : { flip a : UInt<3>}, clock, the firtool is able to generate the correct verilog code, indicating that this issue might be fixed by removing the direction notation in fir reg.

What is the use case for changing the behavior?

Bundles with nested direction works well for grouping signals with similar functionalities together, e.g. gathering all the signals that connects to another specific module, so that they're easy to find, and can be connected using one line of source <> dest.

When a bundle consists of signal with the same direction, it should be able to use with RegNext or Reg for convenient buffering.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions