How to reset your FPGA design at start up without using an external pin or button
Let's say you have an FPGA design and you wish to reset it during the startup but do not want to sacrifice a precious user button or a GPIO for a one time startup reset. How would you go about doing it?
The need to reset your design at startup
The reset is a very important signal that needs to be connected and handled carefully in any FPGA design since errors caused due to incorrect reset can be very difficult to track down.
Most FPGAs usually reset every LUT to zeros and every IO pin to High Impedance on startup. Xilinx FPGAs for example, use signals like Global Write Enable (GWE) and Global 3-State (GTS) to ensure all the logic elements in the design are initialized at the same instant.
A lot about resets in Xilinx FPGAs is mentioned in a few documents like 7-Series FPGAs configuration user guide (Table 5-12) , a whitepaper on better resets and some design advisory by Xilinx .The overall consensus seems to be that its always a good practice to make sure that your design resets itself at startup every time. Doubly true when you have something like a State machine or control counters in your design that are highly sensitive to the initial state.
The overarching principle being "Don't depend on what you can't control"
One elegant solution is to use one of the SRL primitives (for Xilinx FPGAs) and its equivalent for other FPGAs. The description of the primitive is given by Xilinx in its Application Note for SRL16 and 7-Series User Guide for SRL32. The SRL primitives allow us to use LUTs as shift registers. But how do we use this primitive to generate a reset?
Here is a schematic image of the SRL primitive taken from the Xilinx application Note
Take a look at the following code:
wire global_reset; //Active high global_reset signal
SRL16 #(.INIT(16'hFFFF)) srl_rst ( //LUT as a shift-register initialized to All ones
.Q(global_reset),
.A0(1'b1), //Address pointing to the last element in LUT
.A1(1'b1),
.A2(1'b1),
.A3(1'b1),
.CLK(clk),
.D(1'b0)
);
The values in the INIT statements are downloaded to the FPGA as a part of the bitstream itself. So the value of global_reset is initially high and stays so for 16 clk cycles before the value at the D input reaches the output. From there on, global_reset remains low thus mimicking a reset signal meant for initialization. If your design uses and Active Low reset instead, you could initialize the SRL16 to 16'h0
and change the D input to 1'b1
.
Also, if you wish to have the reset asserted(/de-asserted for an active low one), you could use the SRL32 primitive in the 7-Series FPGAs.
For whatever reason if you do not find the above two options enough to reset your design and need a longer reset, you can always initialize a series of D flip-flops as a shift register and do the same thing. To initialize such a shift-register to the required value on Xilinx FPGAs, you can use the Initialization Guide from Xilinx.