Electronic – Quartus II ignoring synthesis attribute noprune

intel-fpgaquartus-iisynthesizer

There is a register in my design that I am using for debug purposes with zero fan-out. Since it isn't driving any logic, the synthesizer optimizes it away. However, as far as my knowledge goes, using the noprune attribute will direct the synthesizer to keep the register.

Unfortunately, even with this synthesis attribute the register is removed from the design in Quartus II. It was suggested to me that since the module has minimal other logic, that it may cause an issue. This doesn't seem quite right to me, though.

I've tried other similar attributes, like preserve – but this didn't work either.

Is this a quirk of Quartus? Would I be better off to try synthesizing the design in something like Synopsys Synplify and then porting that design to Quartus for fitting?

Any ideas what the problem could be?

Thanks in advance!

Here is the code for the module:

VERSION 1

module connector_test(button, txd)

input button;
output reg txd;
reg [2999:0] data /* synthesis noprune */;

always @(button) begin
if(button==1'b0) begin
    txd <= 1'b0;
    data <= {3000 {1'b1}};
end
else begin
    txd <= 1'b1;
    data <= 3000'b0;
end

end

endmodule

…and the synthesis summary:

+------------------------------------------------------------------------------------+
; Analysis & Synthesis Summary                                                       ;
+------------------------------------+-----------------------------------------------+
; Analysis & Synthesis Status        ; Successful - Tue Sep 18 18:20:36 2012         ;
; Quartus II 32-bit Version          ; 12.0 Build 232 07/05/2012 SP 1 SJ Web Edition ;
; Revision Name                      ; connector_test                                ;
; Top-level Entity Name              ; connector_test                                ;
; Family                             ; Cyclone III                                   ;
; Total logic elements               ; 0                                             ;
;     Total combinational functions  ; 0                                             ;
;     Dedicated logic registers      ; 0                                             ;
; Total registers                    ; 0                                             ;
; Total pins                         ; 2                                             ;
; Total virtual pins                 ; 0                                             ;
; Total memory bits                  ; 0                                             ;
; Embedded Multiplier 9-bit elements ; 0                                             ;
; Total PLLs                         ; 0                                             ;
+------------------------------------+-----------------------------------------------+

VERSION 2:

module trigger_test(trigger, reset, clk);

input clk;
input reset;
output reg trigger;
reg [2999:0] data = 3000'b0 /* synthesis noprune */;
reg [15:0] counter = 16'h32; //Trigger will be set every 1000ns (1us).

always @(posedge clk) begin

if(~reset) begin
    trigger <= 1'b0;
    data <= 3000'b0;
    counter <= 16'h32;
end 
else begin
    if(!counter) begin
        trigger <= 1'b1;    //Trigger and data will stay at these values for 20ns because they're synced with the clk.
        data <= {3000 {1'b1}};
        counter <= 16'h32;
    end
    else begin
        trigger <= 1'b0;
        data <= 3000'b0;
        counter <= counter - 1;
    end
end

end
endmodule

VERSION 3:

module toplevel(clk, reset, trigger, out);

input clk;
input reset;
output reg trigger;
output wire out;

reg d = 1'b1;
reg q;

shift shifter( .clk(clk),
       .si(q),
       .so(out));

toggle tff_inst ( .d(d),
          .clk(clk),
          .rst(reset),
          .q(q));

endmodule

TOGGLE:

module toggle(d, clk, rst, q);

input clk;
input d;
input rst;
output reg q;

always @(posedge clk or negedge rst) begin
if(~rst)
    q <= 1'b0;
else if (d) 
    q <= !q;
end

endmodule

The third version also does not synthesize any registers – and I believe this is because I'm receiving a warning that the signal out (the output of the shift register) is stuck at GND. This may be because I'm not initializing the toggling register that gives input to the shift register – but I'm not sure how to initialize this outside of simulation purposes. Any suggestions?

Best Answer

Despite the "reg" declaration in the source code, you have not in fact created any registers. The behavior of your 3000-bit "data" bus is simply that its value is a function of the current value of the "button" input; it doesn't depend on the past history of that or any other signal, so there's no actual memory behavior specified, and therefore no synthesizable flip-flops.

The only logic here is a simple inverter, the output of which is replicated 3000 times. Since nothing is connected to the "data" bus (and it isn't even specified as an output port of the module), there's no need to implement logic to support the fanout, and in fact, there's no need to implement the inverter at all. What is it you're actually trying to debug? By what mechanism were you hoping to observe the data bus?

I'm guessing that Xilinx took an ultra-conservative approach and actually implemented 3000 inverters. I have no idea why it would do that. The answer may have something to do with the actual debug mechanisms that each manufacturer builds into its chips.

If you're trying to measure things like power consumption for various levels of FPGA utilization, the usual technique for this is to create a long shift register. The register is clocked by common clock signal (usually a global clock) and the input of the first bit and the output of the last bit are brought out to pins (the latter is so that the synthesis software doesn't "prune" away the entire chain).

You control the amount of resouce utilization by varying the length of the shift register, and you control the amount of switching activity by the pattern that you shift into it. A pattern of all zeros or all ones eventually has the minimum activity, while a pattern of alternating ones and zeros eventually ramps up to the maximum level of activity.

module shift (clk, si, so);
  parameter SHIFT_LENGTH = 3000;
  input     clk, si;
  output    so;
  reg    [SHIFT_LENGTH-1:0] data;
  always @(posedge clk) begin
    data <= {data[SHIFT_LENGTH-2:0], si};
  end
  assign so = data[SHIFT_LENGTH-1];
endmodule