0
\$\begingroup\$

I'm trying to synthesize the following hardware in Vivado, which contains an array of my_struct_t. To reach timing closure, it's important that this array is implemented with LUT RAM and not with FF RAM. This is just a toy example and the actual code instantiates a much larger array.

// A very simple struct typedef struct packed { logic [15:0] x; logic [15:0] y; } my_struct_t; module mydut #( parameter NUM_STRUCTS=128 ) ( input clk, input reset, input [31:0] update_addr, input [31:0] update_data, input update_strobe, input update_table, input [$clog2(NUM_STRUCTS)-1:0] update_id, input [$clog2(NUM_STRUCTS)-1:0] read_id, output my_struct_t read_struct ); (* ram_style = "distributed" *) my_struct_t pending_data [NUM_STRUCTS]; (* ram_style = "distributed" *) my_struct_t actual_data [NUM_STRUCTS]; always_ff @(posedge clk) begin automatic logic wen = (update_strobe && (update_addr[24 +: 8] == 8'ha5)); automatic int table_write_index = update_addr[0 +: 16]; if (wen && (update_addr[15 +: 8] == 0)) begin pending_data[table_write_index].x <= update_data; if (reset) actual_data[table_write_index].x <= update_data; end if (wen && (update_addr[15 +: 8] == 1)) begin pending_data[table_write_index].y <= update_data; if (reset) actual_data[table_write_index].y <= update_data; end if (update_table) begin actual_data[active_write_idx] <= pending_data[update_id]; end end // read attribute // combinationally driven; responsibility of containing module to latch result. always_comb begin if (update_table && (read_id == update_id)) begin read_struct = pending_data[read_id]; end else begin read_struct = actual_data[read_id]; end end endmodule 

If you have Vivado installed, you can play along at home by running

vivado -mode tcl -source synth.tcl 

With the following synth.tcl

read_verilog -sv top.sv auto_detect_xpm # synth synth_design -top mydut -part xc7k160tffg676-1 \ -flatten_hierarchy rebuilt \ -verbose -debug_log write_checkpoint -force post_synth.dcp 

For each element in my arrays, Vivado tells me

WARNING: [Synth 8-7186] Applying attribute ram_style = "distributed" is ignored, object 'pending_data[0][x]' is not inferred as ram due to incorrect usage 

It's not a usage issue. Even if I don't do anything with them:

module mydut #( parameter NUM_STRUCTS=128 ) ( input clk, input reset, input [31:0] update_addr, input [31:0] update_data, input update_strobe, input update_table, input [$clog2(NUM_STRUCTS)-1:0] update_id, input [$clog2(NUM_STRUCTS)-1:0] read_id, output my_struct_t read_struct ); (* ram_style = "distributed" *) my_struct_t pending_data [NUM_STRUCTS]; (* ram_style = "distributed" *) my_struct_t actual_data [NUM_STRUCTS]; endmodule 

Vivado makes sure to tell me Warning: [Synth 8-7186] before optimizing away the unused signals.

If I break out the struct elements into individual arrays like this:

 (* ram_style = "distributed" *) logic [15:0] pending_data_x [NUM_STRUCTS]; (* ram_style = "distributed" *) logic [15:0] actual_data_x [NUM_STRUCTS]; (* ram_style = "distributed" *) logic [15:0] pending_data_y [NUM_STRUCTS]; (* ram_style = "distributed" *) logic [15:0] actual_data_y [NUM_STRUCTS]; 

I have no issues. The code is functionally identical but harder to write and maintain.

Does anyone know a way to get Vivado to handle this correctly, or is this really the state of FPGA tooling in 2025? This feels like a C compiler bug from 1975... The mapping from struct items to separate arrays is super obvious. I feel like there has to be a way around this.

Could the synthesis tool maybe flatten the struct out and then during a later post-synthesis optimization stage the FDRE be remapped to LUT?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ (I take it for granted Vivado has an active user forum-?) \$\endgroup\$ Commented Aug 29 at 7:17
  • \$\begingroup\$ They do, but electronics.se was the first place that came to mind. Anyways, in the past there have been plenty of Vivado experts on here. \$\endgroup\$ Commented Aug 29 at 16:45

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.