Search code examples
verilogsynthesis

Xst:3002 in Verilog


I'm creating a downcounter on ISE 14.7. I set an asynchronous reset(rst_n), whenever it turns 0, the value of counter will be set to init_value.

But as I syntheize the code, there appears a warning: Xst3002

Code:

`timescale 1ns / 1ps

module downcounter(value, borrow, clk, rst_n, decrease, init_value, limit);
    output reg [3:0]value;              //value of counter
    output reg borrow;                  //borrow indicator
    input clk, rst_n, decrease;         //clock; active low reset; to decrease
    input [3:0]init_value, limit;       //initial value; counter limit

    reg [3:0]value_tmp, init_value_tmp; //for always block

    //Combinational logic
    always @(value or decrease or limit or borrow)begin
        if(~decrease) begin value_tmp = value; borrow = 0; end      //if decrease is 0, the counter stops counting down.
        else begin
            if(value == 0)begin value_tmp = limit; borrow = 1; end  //if the value is 0, the next value would be the limit.
            else begin value_tmp = value + 4'b1111; borrow = 0; end //Ex: limit = 9, so that value(now) = 0, then value(next) = 9 in decimal.
        end
    end
    //Sequentical logic
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n) value <= init_value_tmp;             //asynchronous reset. set the value to initial value
        else begin
            value <= value_tmp;
        end
    end
endmodule

and the message of warning:

WARNING:Xst:3002 - This design contains one or more registers/latches that are directly incompatible with the Spartan6 architecture. The two primary causes of this is either a register or latch described with both an asynchronous set and asynchronous reset, or a register or latch described with an asynchronous set or reset which however has an initialization value of the opposite polarity (i.e. asynchronous reset with an initialization value of 1). While this circuit can be built, it creates a sub-optimal implementation in terms of area, power and performance. For a more optimal implementation Xilinx highly recommends one of the following:

      1) Remove either the set or reset from all registers and latches
         if not needed for required functionality
      2) Modify the code in order to produce a synchronous set
         and/or reset (both is preferred)
      3) Ensure all registers have the same initialization value as the
         described asynchronous set or reset polarity
      4) Use the -async_to_sync option to transform the asynchronous
         set/reset to synchronous operation
         (timing simulation highly recommended when using this option)

Please refer to http://www.xilinx.com search string "Spartan6 asynchronous set/reset" for more details.

List of register instances with asynchronous set and reset: value_0 in unit value_1 in unit value_2 in unit value_3 in unit

it seems that the warning appears because of [3:0]value. But I have no idea about it. I've tried to change the asynchronous reset to 0, the warning disappeared. But that isn't what I want.


Solution

  • There are a few issues here with this design. First of all, init_value_tmp doesn't seem to have a value set. Second, as it is a non-constant, the Spartan-6 architecture may be unable to actually reset to that value using the built-in reset functionality. Change value <= init_value_tmp; so that it assigns some meaningful constant to value.

    As for the async reset, it appears to be valid, but as I do not own a Spartan-6 device, you'd have to synthesize it and try for yourself. My concern is that whatever constant value you use might run into the polarity warning you got before. It's likely that a synchronous reset would "just work" as it's simply a mux in the CLB going into the data input.

    Edit: In regard to your goal of using a non-constant reset value, you'd almost necessarily need a synchronous reset (which is more of an assignment than a reset):

    always @(posedge clk) begin
        if(~rst_n) value <= init_value_tmp;
        else begin
            value <= value_tmp;
        end
    end