Skip to content

[Bug] "Unsupported read-to-read connection" for a plain scalar VAR and for index-0 of a Bit-vector, contradicting #447's fix #467

Description

@soronpo

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:

  1. A plain scalar Bit <> VAR (not a vector element at all).
  2. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions