Skip to content

Commit d64bada

Browse files
Patch VecInit.fill(0) invocation to successfully compile and yield a zero-width Vec (#3171)
1 parent 30131f3 commit d64bada

File tree

5 files changed

+70
-2
lines changed

5 files changed

+70
-2
lines changed

core/src/main/scala/chisel3/Aggregate.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,8 @@ object VecInit extends SourceInfoDoc {
777777

778778
/** @group SourceInfoTransformMacro */
779779
def do_fill[T <: Data](n: Int)(gen: => T)(implicit sourceInfo: SourceInfo): Vec[T] =
780-
apply(Seq.fill(n)(gen))
780+
if (n == 0) { Wire(Vec(0, gen.cloneTypeFull)) }
781+
else { apply(Seq.fill(n)(gen)) }
781782

782783
/** Creates a new 2D [[Vec]] of length `n by m` composed of the result of the given
783784
* function applied to an element of data type T.

core/src/main/scala/chisel3/connectable/Connection.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
package chisel3.connectable
44

5-
import chisel3.{Aggregate, BiConnectException, Data, DontCare, InternalErrorException, RawModule}
5+
import chisel3.{Aggregate, BiConnectException, Data, DontCare, InternalErrorException, RawModule, Vec}
66
import chisel3.internal.{BiConnect, Builder}
77
import chisel3.internal.Builder.pushCommand
88
import chisel3.internal.firrtl.DefInvalid
@@ -204,6 +204,15 @@ private[chisel3] object Connection {
204204
// Recursive Case 4: non-empty orientations
205205
case (conAlign: NonEmptyAlignment, proAlign: NonEmptyAlignment) =>
206206
(conAlign.member, proAlign.member) match {
207+
// Check for zero-width Vectors: both Vecs must be type equivalent, e.g.
208+
// a UInt<8>[0] should not be connectable with a SInt<8>[0]
209+
// TODO: This is a "band-aid" fix and needs to be unified with the existing logic in a
210+
// more generalized and robust way
211+
case (consumer: Vec[Data @unchecked], producer: Vec[Data @unchecked])
212+
if (consumer.length == 0 && !consumer.typeEquivalent(producer)) =>
213+
errors =
214+
(s"Consumer (${consumer.cloneType.toString}) and producer (${producer.cloneType.toString}) have different types.") +: errors
215+
207216
case (consumer: Aggregate, producer: Aggregate) =>
208217
matchingZipOfChildren(Some(conAlign), Some(proAlign)).foreach {
209218
case (ceo, peo) =>

core/src/main/scala/chisel3/internal/BiConnect.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ private[chisel3] object BiConnect {
108108
throw MismatchedVecException
109109
}
110110

111+
// Check for zero-width Vectors: both Vecs must be type equivalent, e.g.
112+
// a UInt<8>[0] should not be connectable with a SInt<8>[0]
113+
// TODO: This is a "band-aid" fix and needs to be unified with the existing logic in a
114+
// more generalized and robust way, to account for things like Views
115+
if (left_v.length == 0 && !left_v.typeEquivalent(right_v)) {
116+
throw MismatchedException(left_v.cloneType.toString, right_v.cloneType.toString)
117+
}
118+
111119
val leftReified: Option[Aggregate] = if (isView(left_v)) reifyToAggregate(left_v) else Some(left_v)
112120
val rightReified: Option[Aggregate] = if (isView(right_v)) reifyToAggregate(right_v) else Some(right_v)
113121

core/src/main/scala/chisel3/internal/MonoConnect.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ private[chisel3] object MonoConnect {
125125
case (sink_v: Vec[Data @unchecked], source_v: Vec[Data @unchecked]) =>
126126
if (sink_v.length != source_v.length) { throw MismatchedVecException }
127127

128+
// Check for zero-width Vectors: both Vecs must be type equivalent, e.g.
129+
// a UInt<8>[0] should not be connectable with a SInt<8>[0]
130+
// TODO: This is a "band-aid" fix and needs to be unified with the existing logic in a
131+
// more generalized and robust way, to account for things like Views
132+
if (sink_v.length == 0 && !sink_v.typeEquivalent(source_v)) {
133+
throw MismatchedException(sink, source)
134+
}
135+
128136
val sinkReified: Option[Aggregate] = if (isView(sink_v)) reifyToAggregate(sink_v) else Some(sink_v)
129137
val sourceReified: Option[Aggregate] = if (isView(source_v)) reifyToAggregate(source_v) else Some(source_v)
130138

src/test/scala/chiselTests/Vec.scala

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,48 @@ class VecSpec extends ChiselPropSpec with Utils {
276276
}
277277
}
278278

279+
property("0-width vectors should be compilable and have strongly-typed connection semantics") {
280+
type ConnectOp = (Data, Data) => Unit
281+
282+
def test[T <: Data](gen: => T)(connect: ConnectOp) = {
283+
val chirrtl = emitCHIRRTL(new Module {
284+
val io = IO(new Bundle {
285+
val out = Vec(0, UInt(8.W))
286+
})
287+
288+
// Check if this is compilable, should pass
289+
val zeroWidthVec = VecInit.fill(0)(gen)
290+
291+
// Check for strong-typed connections. Passes if gen is UInt(8.W),
292+
// fails if gen is anything that isn't type equivalent
293+
connect(io.out, zeroWidthVec)
294+
})
295+
296+
// No need to check for SInt<8>[0] because the elaboration will fail for
297+
// those cases
298+
chirrtl should include(s"wire zeroWidthVec : UInt<8>[0]")
299+
}
300+
301+
val connections: Seq[ConnectOp] = Seq(
302+
(sink, source) => { sink := source },
303+
(sink, source) => { sink <> source },
304+
(sink, source) => { sink :#= source },
305+
(sink, source) => { sink :<= source },
306+
(sink, source) => { sink :>= source },
307+
(sink, source) => { sink :<>= source }
308+
)
309+
310+
for (connect <- connections) {
311+
// Connect a UInt<8>[0] to an UInt<8>[0].
312+
test(8.U(8.W))(connect)
313+
314+
// Attempt to connect a SInt<8>[0] to an UInt<8>[0].
315+
a[ChiselException] should be thrownBy extractCause[ChiselException] {
316+
test(8.S(8.W))(connect)
317+
}
318+
}
319+
}
320+
279321
property("Infering widths on huge Vecs should not cause a stack overflow") {
280322
ChiselStage.emitSystemVerilog(new HugeVecTester(10000))
281323
}

0 commit comments

Comments
 (0)