Tuesday 3 June 2014

Reseting my Nios II

In this blog post I will look at the reset design in the Nios II system I am designing. I will consider the pros and cons of using synchronous and asynchronous reset. My conclusion is its best to have a bit of both and use a synchronising reset circuit.

Asynchronous Reset

proc_dtype:process(in_clk,in_reset)
begin
  if (in_reset = '1') then
    out_q <= '0';
  elsif (rising_edge(in_clk)) then
    out_q <= in_d;
  end if;
end process;

The VHDL above will generate a d-type shown in the RTL view below. It creates a reset that is independent on the clock or asynchronous.


The asynchronous reset is the simplest to implement and is probably the most common type of reset used in an FPGA design. The advantage of this kind of reset is it does not need to insert any extra logic in the data path and therefore will not inadvertently increase the logic layers between d-types in an RTL stage. This mean that asynchronous reset will not impact on the data arrival time to a register input. The other big advantage of an asynchronous reset is that the reset will take effect immediately i.e. it is not dependent on the clock.

But there is a very big disadvantage to using asynchronous resets! You cannot guarantee that the resets for all the d-types will be released in the same clock cycle. This create the small possibility of you design not coming out of reset in the way that was predicted. This could cause an intermittent fault that is tricky to track down.

Would a synchronous reset be any better?

Synchronous Reset

  proc_dtype:process(in_clk)
  begin
    if (rising_edge(in_clk)) then
      if (in_reset = '1') then
        out_q <= '0';
      else
out_q <= in_d;
      end if;
    end if;
  end process;

The VHDL above will generate a d-type shown in the RTL view below. It creates a reset that is dependent on the clock or synchronous.


This reset design is fully synchronous and is therefore predictable and we can use static timing analysis such as TimeQuest to test the timing of the circuit. This kind of reset can also be easier to use when you do circuit simulation. However there is a down side to synchronous resets. Your design will be more complex and you create the risk of adding additional gate delays to accommodate the reset signal. This will produce a negative impact on the d-types set-up slack time.

However it turns out that it is possible to use an asynchronous reset, but with a synchronous release.

A bit of both Asynchronous and Synchronous 

proc_dtype:process(in_clk,reset)
begin
  if (reset = '1') then
    out_q <= '0';
  elsif (rising_edge(in_clk)) then
    out_q <= in_d;
  end if; 
end process;
  
proc_reset:process(in_clk,in_reset)
begin
  if (in_reset = '1') then
    rst_reg  <= '1';
    reset <= '1';
  elsif (rising_edge(in_clk)) then
    rst_reg  <= '0';
    reset    <= rst_reg;
  end if;
end process;

The the VHDL above contains two processes. The top process is a d-type that we want to reset and the bottom process is a reset synchronization circuit. It produces the following RTL.


This design avoids the potential problems associated with synchronous reset and purely asynchronous reset. The reset is applied asynchronously and immediately. It also does not create the additional logic we have seen with the synchronous design. However the one big advantage is that when the reset is released, it is synchronous to the clock. This mean that all the registers will be reset in the same clock cycle. You can also use static timing analysis to prove your timings. 

My Nios II reset

In my post Using a PLL to correct the SDRAM clock when using a Nios II on the DE0-Nano the Nios was connected directly to the reset pin and the pll used the reset pin via a NOT gate. Based on the above discussion this has now been replaced with a reset synchronization circuit shown below:


The VHDL for this reset circuit is as follows:

library ieee;use
ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity reset_synchronization is   
  port  
  (  
  in_clk      : in  std_logic;  
  in_reset_n  : in  std_logic;  
  out_reset   : out std_logic;  
  out_reset_n : out std_logic  
  );
end entity;  

architecture arch_reset_synchronization of reset_synchronization is

signal rst_reg: std_logic;
signal reset  : std_logic;  

begin
  proc_reset:process(in_clk,in_reset_n)  

  begin    
    if (in_reset_n = '0') then      
      rst_reg  <= '1';      
      reset <= '1';    
    elsif (rising_edge(in_clk)) then      
      rst_reg  <= '0';      
      reset    <= rst_reg;    
    end if;  
   end process;

  out_reset   <= reset;  

  out_reset_n <= not reset;

 end architecture;


 And that it! We now has a DE0-nano design with a more robust reset!. Feel free to post comments to let me know what you think.

References

Altera - Recommended Design Practices
How do I reset my FPGA?
Synchronizing Asynchronous Resets / Reset Design


No comments:

Post a Comment