chisel icon indicating copy to clipboard operation
chisel copied to clipboard

Error When Connecting Analog-Only Bundle to Verilog Blackbox

Open ysljung opened this issue 7 months ago • 0 comments

@seldridge bringing from chisel:matrix.org

Type of issue: Bug Report

Please provide the steps to reproduce the problem:

  1. Define a Verilog blackbox with inout signals.
  2. Connect these inout signals to Chisel Analog IO.
  3. Use a bundle in IO that consists only of Analog signals.
  4. Run the build process, converting .fir to .sv.
  5. 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?

ysljung avatar Mar 06 '25 18:03 ysljung