Summary
#447 ("Unsupported read-to-read connection" for vector elements >= 1 when the element width is a parameter) was closed as fixed, but the same error message still fires on DFHDL 0.22.0+63-477e737a-SNAPSHOT (newer build than #447's +25) for two shapes #447 explicitly said were unaffected:
- A plain scalar
Bit <> VAR (not a vector element at all).
- Index 0 of a
Bit X N <> VAR (single-bit element vector) — #447 states "index v(0) is accepted" and "A Bit X N vector is also unaffected (only multi-bit elements carry a width)". Neither holds for the repro below.
So either the underlying defect is broader than #447's fix covered, or this is a related-but-distinct bug that happens to produce an identical message. Filing separately per the "verify before filing" rule, since I could not get this to reproduce via #447's own repro shape (parametric multi-bit element width) — mine reproduces with only Bit values, no vector-element width involved for the first case.
Minimal reproduction (verified against DFHDL 0.22.0+63-477e737a-SNAPSHOT, Scala 3.8.4)
// Child.scala
import dfhdl.*
class Child extends EDDesign:
val a = Bit <> IN
val y = Bit <> OUT
y <> a
// Probe.scala
import dfhdl.*
class Probe extends EDDesign:
val a = Bit <> IN
val b = Bit <> OUT
val w = Bit <> VAR
val c = new Child
b <> w // read w (as producer) -- fine on its own
w <> c.y // drive w (as consumer, from child's output port)
c.a <> a
This 2-file, ~12-line case (isolated) actually compiles fine — I include it to show the minimal non-failing shape, since it rules out "any read-before-drive of a VAR" as the trigger and narrows the real trigger to a specific combination. The failing case needs the read side to be a bit-select of an ambiguous (non-port) Bits/Bit-vector VAR, established before its own whole-vector driver is written. Minimal failing repro:
// Kid.scala
import dfhdl.*
class Kid extends EDDesign:
val a = Bit <> IN
val y = Bit <> OUT
y <> a
// Probe2.scala
import dfhdl.*
class Probe2 extends EDDesign:
val extIn = Bit <> IN
val extOut = Bits(3) <> OUT
val k_out_ready = Bits(3) <> VAR // plain multi-bit VAR, bit-selected below
val k_to_f_ready = Bit <> VAR // plain scalar VAR — NOT a vector element
val kid = new Kid
k_out_ready(2) <> extIn
k_out_ready(0) <> k_to_f_ready // read k_to_f_ready (producer) — BEFORE its own drive
k_to_f_ready <> kid.y // drive k_to_f_ready (consumer) from a child's output port
kid.a <> extIn
extOut <> k_out_ready
DFiant HDL connectivity error!
Position: src/Probe2.scala:<line>:3 - <line>:<col>
Hierarchy: Probe2
LHS: k_to_f_ready
RHS: kid.y
Message: Unsupported read-to-read connection.
Swapping the order of the two k_to_f_ready connections does not fix it — the error simply moves to whichever of the two touches k_to_f_ready is written second:
k_to_f_ready <> kid.y // now first: drive
k_out_ready(0) <> k_to_f_ready // now second: read -- THIS one now errors instead
Directly connecting k_out_ready(0) <> kid.y (skipping the k_to_f_ready intermediate entirely) also fails the same way, with k_out_ready(0) itself now named as the conflicting LHS. So the trigger is not specific to the intermediate scalar VAR either; it is some property of k_out_ready (a multi-bit VAR whose bits are driven individually from ambiguous sources and which is read as a whole elsewhere, e.g. childInput <> k_out_ready) combined with a bit-select connection sourced from something not yet resolved as a definite producer.
This exact shape was found translating Mahmoud-geberty/HOG_fpga's lin_buff.v (same upstream source #447 mentions) — the real, non-minimized failure:
DFiant HDL connectivity error!
Position: src/lin_buff.scala:123:3 - 123:37
Hierarchy: lin_buff
LHS: k_to_f_ready
RHS: first_line.w_ready
Message: Unsupported read-to-read connection.
DFiant HDL connectivity error!
Position: src/lin_buff.scala:140:5 - 140:41
Hierarchy: lin_buff
LHS: k_to_b_ready(0)
RHS: line_buff.w_ready
Message: Unsupported read-to-read connection.
Both k_to_f_ready (a plain scalar Bit <> VAR) and k_to_b_ready(0) (index 0, contradicting #447's "index 0 is accepted") are affected. first_line.w_ready / line_buff.w_ready are ordinary child-design Bit <> OUT ports, no parametric multi-bit width involved anywhere in this chain.
Expected
k_to_f_ready <> first_line.w_ready (a VAR driven once by a child's output port, elsewhere read to build another signal) should compile — this is the completely ordinary "one driver, one or more readers" wire pattern shown in the docs' own IODesign1 example (tmp <> i; o <> tmp), just with the driving and reading connections written in the opposite relative order.
Workaround used
Build the multi-bit consumer (k_out_ready in the real design) via elaboration-time bit concatenation (the docs' LaneConcat idiom, (x, acc).toBits) instead of per-bit <> connections on a VAR, placed textually after the child instances that drive the individual ready signals. This avoids the construct entirely. Full context in dfhdl_by_agents gap ticket (learner run hog-fpga-buffers-1) and dfhdl_training timeout ticket for the same module.
Environment
- DFHDL
0.22.0+63-477e737a-SNAPSHOT
- Scala 3.8.4, JVM 21
- Backend: SystemVerilog (
-- commit)
Related
#447 (closed) — same error message, but for a different trigger shape (parametric multi-bit element width, index >= 1) that this repro explicitly does not require.
Summary
#447("Unsupported read-to-read connection" for vector elements >= 1 when the element width is a parameter) was closed as fixed, but the same error message still fires on DFHDL0.22.0+63-477e737a-SNAPSHOT(newer build than#447's+25) for two shapes#447explicitly said were unaffected:Bit <> VAR(not a vector element at all).Bit X N <> VAR(single-bit element vector) —#447states "indexv(0)is accepted" and "ABit X Nvector is also unaffected (only multi-bit elements carry a width)". Neither holds for the repro below.So either the underlying defect is broader than
#447's fix covered, or this is a related-but-distinct bug that happens to produce an identical message. Filing separately per the "verify before filing" rule, since I could not get this to reproduce via#447's own repro shape (parametric multi-bit element width) — mine reproduces with onlyBitvalues, no vector-element width involved for the first case.Minimal reproduction (verified against DFHDL
0.22.0+63-477e737a-SNAPSHOT, Scala 3.8.4)This 2-file, ~12-line case (isolated) actually compiles fine — I include it to show the minimal non-failing shape, since it rules out "any read-before-drive of a VAR" as the trigger and narrows the real trigger to a specific combination. The failing case needs the read side to be a bit-select of an ambiguous (non-port)
Bits/Bit-vector VAR, established before its own whole-vector driver is written. Minimal failing repro:Swapping the order of the two
k_to_f_readyconnections does not fix it — the error simply moves to whichever of the two touches k_to_f_ready is written second:Directly connecting
k_out_ready(0) <> kid.y(skipping thek_to_f_readyintermediate entirely) also fails the same way, withk_out_ready(0)itself now named as the conflicting LHS. So the trigger is not specific to the intermediate scalar VAR either; it is some property ofk_out_ready(a multi-bit VAR whose bits are driven individually from ambiguous sources and which is read as a whole elsewhere, e.g.childInput <> k_out_ready) combined with a bit-select connection sourced from something not yet resolved as a definite producer.This exact shape was found translating
Mahmoud-geberty/HOG_fpga'slin_buff.v(same upstream source#447mentions) — the real, non-minimized failure:Both
k_to_f_ready(a plain scalarBit <> VAR) andk_to_b_ready(0)(index 0, contradicting#447's "index 0 is accepted") are affected.first_line.w_ready/line_buff.w_readyare ordinary child-designBit <> OUTports, no parametric multi-bit width involved anywhere in this chain.Expected
k_to_f_ready <> first_line.w_ready(aVARdriven once by a child's output port, elsewhere read to build another signal) should compile — this is the completely ordinary "one driver, one or more readers" wire pattern shown in the docs' ownIODesign1example (tmp <> i; o <> tmp), just with the driving and reading connections written in the opposite relative order.Workaround used
Build the multi-bit consumer (
k_out_readyin the real design) via elaboration-time bit concatenation (the docs'LaneConcatidiom,(x, acc).toBits) instead of per-bit<>connections on a VAR, placed textually after the child instances that drive the individual ready signals. This avoids the construct entirely. Full context indfhdl_by_agentsgap ticket (learner runhog-fpga-buffers-1) anddfhdl_trainingtimeout ticket for the same module.Environment
0.22.0+63-477e737a-SNAPSHOT-- commit)Related
#447(closed) — same error message, but for a different trigger shape (parametric multi-bit element width, index >= 1) that this repro explicitly does not require.