KJ,
Many systems require control of outputs and/or states even in the
absence of a clock; therefore an "asynchronous" reset is required.
The setup and hold of the "asynchronous" reset need only be with
respect to the deasserting edge (i.e. reset going away). That can be
accomplished by the following:
process (rstin, clk) is
variable rstreg : std_logic;
begin
if rstin = '1' then -- active high
rstout <= '1';
rstreg := '1';
elsif rising_edge(clk) then
rstout <= rst_reg; -- registered reference to rstreg
rstreg := '0';
end if;
end process;
In the above example, rstin is the asyncrhonous system reset input, and
rstout is the asynchonously asserted, synchronously deasserted reset
signal for the rest of the registers clocked by clk, and is tied to
their async reset inputs. This would need to be repeated for each
unrelated clock.
Another option is to use rstout from above to disable the clock, either
via individual clock enables on the flops, or via the enable feature of
the xilinx clock buffer, which does it "safely". Then send rstin to
the async rst inputs of all the flops. This has the advantage of one
net for all the async resets, and multiple versions of rstout for the
various clock buffers.
Finally, even your synchronous reset template does not meet the needs
of functioning registers even when reset is active. Because of the
elsif statement, those registers that were not reset will have their
clock enable inputs deasserted when reset is active, preventing them
from updating (because the elsif section does not execute if reset is
active). There really is no good way, in one process, to avoid the
separate "if reset" statement at the bottom of the process. On the
other hand, I kind of like the reset at the bottom, since when I'm
reading the code, I'm usually more interested in what happens while not
in reset, and that comes first. On the other other hand, you don't get
those warnings about feedback muxes when you forget to include a
register in the reset clause either.
Andy
KJ wrote:
> jens wrote:
> > Most of us are familiar with this synchronous process template...
> >
> > synchronous_process_template: process(clock, reset)
> > begin
> > if reset = '1' then
> > -- initialize registers here
> > elsif rising_edge(clock) then
> > -- assign registers here
> > end if;
> > end process synchronous_process_template;
> >
> > However one problem with it is if there are ...
> Actually there are several problems with this 'synchronous process
> template' starting with the fact that it is not synchronous....it has
> an asynchronous reset input therefore it is not synchronous. The other
> problem with using this as a general template is that 'most' of the
> time asynchronous resets should not be used in the design at all.
> People tend to forget that when the reset signal gets shut off and it
> violates the setup time of the clock that darn near anything can happen
> to any of the outputs of that process. Sometimes the symptoms are
> benign (something shows up one clock later), other times they are not
> (notably, state machines).
>
> The reason for the more serious symptoms is violating the basic design
> principle that no asynchronous input should ever go into computing the
> output of more than one storage element (generally flip flops) if the
> next state of those storage elements also depend on the current state.
>
> This template should never really be used unless you know for a fact
> that 'reset' is guaranteed to have a known and acceptable setup/hold
> time relationship to 'clock'. If that's not the case, or if you have a
> situation where 'reset' might be asserted at a time when 'clock' is not
> guaranteed to be running, then it's far better to design a shift
> register type of synchronizer to synchronize the reset signal before
> distributing it to reset any logic. That way only the shift register
> design needs the asynchronous reset 'template' and shift registers have
> no inherent problems with asynchronous inputs other than metastability.
>
> If you have multiple clock domains with things needing to be reset in
> each domain, than you need to generate individual resets that are each
> synchronized to the appropriate clock.
>
> >
> > Here's an alternate synchronous process template...
> >
> > alternate_synchronous_process_template: process(clock, reset)
> > begin
> > if rising_edge(clock) then
> > -- assign all registers here
> > end if;
> > if reset = '1' then
> > -- initialize some or all registers here
> > end if;
> end if; <-- Oops, you missed this one.
> > end process alternate_synchronous_process_template;
>
> Here's an equivalent (i.e. produces the exact same synthesis and
> simulation results) but doesn't require the reader to read from the
> 'bottom up'.
>
> alternate_synchronous_process_template: process(clock, reset)
> begin
> if rising_edge(clock) then
> if reset = '1' then
> -- initialize some or all registers here
> elsif;
> -- assign all registers here
> end if;
> end if;
> end process alternate_synchronous_process_template;
>
> Good points though.
>
> KJ
|