Search code examples
verilogsystem-verilogfpgahdlvivado

Is the array part select +: with variable start synthesizable by Vivado?


If I have a vector and I want to read a part of it starting somewhere. Can I use the syntax vector[staring_point +: output_length] with starting_point being an integer? Is it synthesizable?

If I write a code like this:

module my_mod(
    input logic din,
    input logic clk,
    input logic[2:0] start_ptr,
    output logic[3:0] dout);

logic[10:0] vector = 0;

always_ff@(posedge clk) vector <= {vector[9:0], din}; --shift register

always_comb dout <= vector[start_ptr +: 4];  

endmodule

The design is just this and the input and output are bounded to GPIOs. I'm expecting a mux for each output bit. Surprisingly Vivado will synthesize 1FF and 1LUTRAM that is an SRL16 so a shift register with integrated mux, but the primitive has only one output and the "dout" signal is driven only with the first bit.

The other 3bits are buffered to 0.

Is the syntax +: correct? Is that consistent or it's a bug of Vivado?


Solution

  • I cleaned code and built in Vivado 2020.2 As pointed out some outputs are inappropriately tied off in synthesis.
    Cleaned up code:

    module my_mod(
      input  logic din,
      input  logic clk,
      input  logic[2:0] start_ptr,
      output logic[3:0] dout);
    
    logic[10:0] vector;
    
    always_ff@(posedge clk)
      vector <= {vector[9:0], din}; //shift register
    
    always_comb
      dout = vector[start_ptr +: 4];
    
    endmodule    
    

    And the RTL that the code infers:
    enter image description here

    Vivado is not doing the right thing (its a bug). This is worth reporting to Xilinx. The +: operator is capable of generating a mux/barrel shifter. How: Change the code to infer regs instead of SRL's (added a RTL reset) then it infers the design intent.

    module my_mod(
        input logic din,
        input logic clk,
        input logic[2:0] start_ptr,
        input logic rst,
        output logic[3:0] dout);
    
    logic[10:0] vector;
    
    always_ff@(posedge clk)
      if(rst)
        vector <= 0;
      else
        vector <= {vector[9:0], din}; //shift register
    
    always_comb
      dout = vector[start_ptr +: 4];
    
    endmodule
    

    enter image description here

    To stay closer to what you posted (no reset) you can use the right shift operator. This also infers the mux as intended. This does not give an initial value of 0, in the reg, so you need to add the reset if you need an initial value.

    module my_mod(
      input  logic din,
      input  logic clk,
      input  logic[2:0] start_ptr,
      output logic[3:0] dout);
    
    logic[10:0] vector;
    
    always_ff@(posedge clk)
      vector <= {vector[9:0], din}; //shift register
    
    always_comb
      dout = vector >> start_ptr ;
    
    endmodule
    

    Here is the RTL view of the design using the shift operator (>>).
    enter image description here

    At one point I was thinking Xilinx intended for the +: and -: operators to be used at elaboration time only, for example in a generate loop. If that were the case then Xilinx should state that in the synthesis guide UG901 (they do not). Also Vivado infers the combinational logic for a design with registers, why should it not work with SRL's?
    To me its a bug.
    Good catch.