Skip to content

Conversation

bgamari
Copy link
Contributor

@bgamari bgamari commented Aug 9, 2025

The pretty-printer previously failed to round-trip, resulting in invalid primitives due to the logic in Clash.Netlist.BlackBox.mkFunInput.

I have also included some clean-ups and error message improvements that I found useful while debugging this.

Fixes #2988.
Fixes #2809.

TODO

  • Add changelog entry
  • Add test

@bgamari
Copy link
Contributor Author

bgamari commented Aug 10, 2025

Sadly it appears that we now emit [\...\] in the produced Verilog, e.g.:

  // map begin
  genvar i;
  generate
  for (i=0; i < 3; i = i + 1) begin : map
    wire [43:0] map_in;
    assign map_in = a1[i*44+:44];
    wire [31:0] map_out;
    assign map_out = map_in[\0+:32\];


    assign c$ds2_app_arg_0[i*32+:32] = map_out;
  end
  endgenerate
  // map end

Unfortunately this doesn't manifest in the minimal reproducer above.

@bgamari
Copy link
Contributor Author

bgamari commented Aug 10, 2025

This program is sufficient to reproduce the bad behavior:

{-# LANGUAGE DataKinds #-}

module Hi where

import Clash.Prelude
import Prelude ()

topEntity
    :: Signal System (Vec 4 (BitVector 40))
    -> Signal System (Vec 4 (BitVector 32))
topEntity = f

f
    :: Signal System (Vec n (BitVector 40))
    -> Signal System (Vec n (BitVector 32))
f x = fmap (fmap truncateB) x
{-# OPAQUE f #-}

{-# ANN topEntity
  (Synthesize
    { t_name   = "repro"
    , t_inputs = [ PortName "inp" ]
    , t_output = PortName "outp"
    }) #-}

Resulting in:

module Hi_topEntity_f
    ( // Inputs
      input wire [159:0] x
      // Outputs
    , output wire [127:0] result
    );

  // map begin
  genvar i;
  generate
  for (i=0; i < 4; i = i + 1) begin : map
    wire [39:0] map_in;
    assign map_in = x[i*40+:40];
    wire [31:0] map_out;
    assign map_out = map_in[\0+:32\];
    assign result[i*32+:32] = map_out;
  end
  endgenerate
  // map end
endmodule

@bgamari
Copy link
Contributor Author

bgamari commented Aug 11, 2025

@christiaanb it would be great to hear your thoughts on the intended behavior here. I'm struggling to see how mkFunInput fits together and I'm still struggling to determine how the current patch is resulting in the errant escaping leaking into HDL output.

@bgamari
Copy link
Contributor Author

bgamari commented Aug 11, 2025

I have shamelessly stolen (with a bit of cleanup) the approach taken in https://github.com/clash-lang/clash-compiler/tree/fix-map-head. This indeed appears to solve the issue, as demonstrated by the added tests.

@martijnbastiaan
Copy link
Member

@kloonbot run_ci 88e6bb7

Copy link
Member

@martijnbastiaan martijnbastiaan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @bgamari, this LGTM. I'll add a changelog entry later and merge.

@martijnbastiaan
Copy link
Member

martijnbastiaan commented Aug 18, 2025

@kloonbot run_ci f2b20fd

I've added a changelog and a regression test.

The way that way that blackboxes of function arguments to higher order
blackboxes are handled is somewhat weird.

For historical reasons, they are parsed, pretty-printed, later re-parsed
again. However, the pretty-printer failed to correctly re-escape
previously escaped square brackets, resulting in the generation of
invalid HDL, as seen in clash-lang#2809.

Fixes clash-lang#2809.
Fixes clash-lang#2988.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error parsing blackbox: Clash.Sized.Vector.head Verilog and System Verilog code gen bug for map head
2 participants