chisel
                                
                                 chisel copied to clipboard
                                
                                    chisel copied to clipboard
                            
                            
                            
                        Error When Connecting Analog-Only Bundle to Verilog Blackbox
@seldridge bringing from chisel:matrix.org
Type of issue: Bug Report
Please provide the steps to reproduce the problem:
- Define a Verilog blackbox with inout signals.
- Connect these inout signals to Chisel Analog IO.
- Use a bundle in IO that consists only of Analog signals.
- Run the build process, converting .fir to .sv.
- Observe the error during FIRRTL lowering.
Error messages
error: analog types may not be connected 
note: see current operation: "firrtl.strictconnect"(%172, %arg90) : (!firrtl.bundle<signal_0: analog<1>, signal_1: analog<1>>, !firrtl.bundle<signal_0: analog<1>, signal_1: analog<1>>) -> ()
What is the current behavior?
- If the IO bundle contains only Analog signals, the build fails.
- The .fir output appears correct, showing attach statements.
- However, in intermediate IRs, strictconnect is used instead of attach, leading to an error.
- This issue occurs regardless of whether attach or bulk connections are used.
What is the expected behavior?
- The Analog-only bundle should be correctly handled, similar to when Analog is mixed with regular Chisel IO.
- The FIRRTL lowering process should preserve attach semantics without causing an error.
Please tell us about your environment: I will provide example code.
- example1.scala: Works fine because the bundle contains a mix of Analog and regular Chisel IO signals.
//> using scala "2.13.12"
//> using dep "org.chipsalliance::chisel::6.5.0"
//> using options  "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", "-Xmaxerrs", "1500", "-Ymacro-annotations",
import chisel3._
import chisel3.experimental.{Analog, attach}
import chisel3.stage.ChiselStage
class PhyMixedInterface extends Bundle {
  val analog_signal_0 = Analog(1.W)
  val analog_signal_1 = Analog(1.W)
  val digital_signal = Output(UInt(1.W))
}
class PhyInterfaceIO extends Bundle { 
  val mixed = new PhyMixedInterface
}
// BlackBox implementation
class PhyImpl extends BlackBox with HasBlackBoxPath {
  override val desiredName = "phy_impl"
  val io = IO(new Bundle {
    val phy = new PhyInterfaceIO
  })
  addPath("phy_impl.v")
}
// Wrapper module that contains the BlackBox
class PhyWrapper extends Module {
  val io = IO(new PhyInterfaceIO)
  
  val impl = Module(new PhyImpl)
  
  io.mixed <> impl.io.phy.mixed
}
object Main extends App {
    (new chisel3.stage.ChiselStage).emitVerilog(new PhyWrapper)
}
- example2.scala: Fails because the bundle (PhyAnalogInterface) consists only of Analog signals.
//> using scala "2.13.12"
//> using dep "org.chipsalliance::chisel::6.5.0"
//> using options  "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", "-Xmaxerrs", "1500", "-Ymacro-annotations",
import chisel3._
import chisel3.experimental.{Analog, attach}
import chisel3.stage.ChiselStage
// Interface definition
class PhyAnalogInterface extends Bundle {
  val signal_0 = Analog(1.W)
  val signal_1 = Analog(1.W)
}
class PhyDigitalInterface extends Bundle {
  val signal = Output(UInt(1.W))
}
class PhyInterfaceIO extends Bundle {
  val digital = new PhyDigitalInterface
  val analog = new PhyAnalogInterface
}
// BlackBox implementation
class PhyImpl extends BlackBox with HasBlackBoxPath {
  override val desiredName = "phy_impl"
  val io = IO(new Bundle {
    val phy = new PhyInterfaceIO
  })
  addPath("phy_impl.v")
}
// Wrapper module that contains the BlackBox
class PhyWrapper extends Module {
  val io = IO(new PhyInterfaceIO)
  
  val impl = Module(new PhyImpl)
  
  io.digital.signal := impl.io.phy.digital.signal
  
  // Connect analog signals using attach
  attach(io.analog.signal_0, impl.io.phy.analog.signal_0)
  attach(io.analog.signal_1, impl.io.phy.analog.signal_1)
}
object Main extends App {
    (new chisel3.stage.ChiselStage).emitVerilog(new PhyWrapper)
}
- example3.scala: bulk connection is used instead of attach, but the result is same (also fails)
//> using scala "2.13.12"
//> using dep "org.chipsalliance::chisel::6.5.0"
//> using options  "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", "-Xmaxerrs", "1500", "-Ymacro-annotations",
import chisel3._
import chisel3.experimental.{Analog, attach}
import chisel3.stage.ChiselStage
// Interface definition
class PhyAnalogInterface extends Bundle {
  val signal_0 = Analog(1.W)
  val signal_1 = Analog(1.W)
}
class PhyDigitalInterface extends Bundle {
  val signal = Output(UInt(1.W))
}
class PhyInterfaceIO extends Bundle {
  val digital = new PhyDigitalInterface
  val analog = new PhyAnalogInterface
}
// BlackBox implementation
class PhyImpl extends BlackBox with HasBlackBoxPath {
  override val desiredName = "phy_impl"
  val io = IO(new Bundle {
    val phy = new PhyInterfaceIO
  })
  addPath("phy_impl.v")
}
// Wrapper module that contains the BlackBox
class PhyWrapper extends Module {
  val io = IO(new PhyInterfaceIO)
  
  val impl = Module(new PhyImpl)
  
  io.digital.signal := impl.io.phy.digital.signal
  
  // Connect analog signals using bulk connection
  io.analog <> impl.io.phy.analog
}
object Main extends App {
    (new chisel3.stage.ChiselStage).emitVerilog(new PhyWrapper)
}
- phy_impl.v: blackbox verilog code
// blackbox
module phy_impl (
    output wire digital_signal,
    
    // Analog interface
    inout wire signal_0,
    inout wire signal_1
);
    // Empty module implementation
    assign digital_signal = 1'b0;
    
endmodule
Other Information
Please note that I am not using scala-cli, so my build might not exactly match the standard setup. And I used firtool 1.75.0. If there are any additional details I should provide about my environment to help reproduce the issue, please let me know. Thanks!
What is the use case for changing the behavior?