I am trying to write a Scala transform for firrtl, and at some point , I have a bunch of wires which should be connected to the input port. Because the number of wires could be to high, I dont want to connect each wire with a port, but concatenate all the wires together and use a single port with a bigger width.
Im using the seqCat function :
val seq_cat = seqCat(wires.map(x=>WRef(x.name,port.tpe,WireKind,BIGENDER)))
then I connect the output of the cat, which is an expression composed by several cats:
val connect_pin = Connect(NoInfo, seq_cat, WRef(port.name, port.tpe, PortKind, BIGENDER))
Because the expression of connect_pin is quite complex:
Connect(,DoPrim(cat,List(WRef(_GEN_0,UIntType(IntWidth(3)),WireKind,BIGENDER), DoPrim(cat,ArrayBuffer(WRef(_GEN_1,UIntType(IntWidth(3)),WireKind,BIGENDER), WRef(_GEN_2,UIntType(IntWidth(3)),WireKind,BIGENDER)),List(),UIntType(UnknownWidth))),List(),UIntType(UnknownWidth)),WRef(faultPin,UIntType(IntWidth(3)),PortKind,BIGENDER))
I try to split it to simpler nodes, using the Splitter function provided on the Chisel Bootcamp and the output of splitter is what expected :
Block(ArrayBuffer(DefNode(,_GEN_6,DoPrim(cat,ArrayBuffer(WRef(_GEN_1,UIntType(IntWidth(3)),WireKind,BIGENDER), WRef(_GEN_2,UIntType(IntWidth(3)),WireKind,BIGENDER)),List(),UIntType(UnknownWidth))), DefNode(,_GEN_7,DoPrim(cat,List(WRef(_GEN_0,UIntType(IntWidth(3)),WireKind,BIGENDER), WRef(_GEN_6,UIntType(UnknownWidth),ExpKind,UNKNOWNGENDER)),List(),UIntType(UnknownWidth))), Connect(,WRef(_GEN_7,UIntType(UnknownWidth),ExpKind,UNKNOWNGENDER),WRef(faultPin,UIntType(IntWidth(3)),PortKind,BIGENDER))))
When I run the transform, I get a runtime error :
======== Starting Transform CheckGenders$ ========
[error] (run-main-0) firrtl.passes.CheckGenders$WrongGender: @[:Top_adder_muxed.fir@22.2]: [module Top_adder] Expression _GEN_7 is used as a FEMALE but can only be used as a MALE.
[error] firrtl.passes.CheckGenders$WrongGender: @[:Top_adder_muxed.fir@22.2]: [module Top_adder] Expression _GEN_7 is used as a FEMALE but can only be used as a MALE.
[error] at firrtl.passes.CheckGenders$.firrtl$passes$CheckGenders$$check_gender$1(Checks.scala:511)
[error] at firrtl.passes.CheckGenders$.firrtl$passes$CheckGenders$$check_genders_s$1(Checks.scala:542)
[error] at firrtl.passes.CheckGenders$$anonfun$firrtl$passes$CheckGenders$$check_genders_s$1$4.apply(Checks.scala:558)
[error] at firrtl.passes.CheckGenders$$anonfun$firrtl$passes$CheckGenders$$check_genders_s$1$4.apply(Checks.scala:558) ``` ```
I dont get why this error is happening, its just a wire, which should be connected with an input port. The fact that this wire is the output of a cat, it doesn't make it a MALE, because is just putting some wires together, cat operator doesn't synthesize any driver for driving the wires.
If you have any hint on this, I'm stucked for some days on this error.
The issue is that the output of primitive operations (DoPrims) are MALE (SourceFlow in the new terminology, basically a read-only value). While notionally concatenating wires together does not necessarily mean it's read-only, in the semantics of FIRRTL it does. This is described in section 8 of the FIRRTL Spec: "The flow of all other expressions are source".
So this leaves us with the question of how to accomplish connecting a single port to several wires. You do this with multiple connections. Here is a sketch of what the code might look like but, of course, it depends on your exact types:
// Assuming 3-bit wires and UInt port as suggested by the code in the question
val portRef = WRef(port) // same as val portRef = WRef(port.name, port.tpe, PortKind, UNKNOWNGENDER)
val cons = wires.zipWithIndex.map { case (wire, idx) =>
val msb = (idx * 3) - 1
val lsb = msb - 2
val rhs = DoPrim(PrimOps.Bits, Seq(portRef), Seq(msb, lsb), UIntType(IntWidth(3)))
val lhs = WRef(wire) // same as WRef(wire.name, wire.tpe, WireKind, UNKNOWNGENDER)
Connect(NoInfo, lhs, rhs)
}
All of this logic could be wrapped up in a reusable utility function which would probably be pretty useful, of course such a utility would need to work for other types (not just UInts).