async reset model too optimistic?

M

mag

Guest
We model our async resets like this:

module AsyncResetFlop(flopout, flopin, clr_bar, clock);

output [WIDTH-1:0] flopout;
   input [WIDTH-1:0]  flopin;
   input             clr_bar;
   input           clock;
   reg [WIDTH-1:0]    temp;

  // synopsys async_set_reset "clr_bar"
   // cadence async_set_reset "clr_bar"

   assign flopout = temp;
   always @(posedge clock or negedge clr_bar) begin
      if (!clr_bar) temp <= #1 {WIDTH{1'b0}};
      else temp <= #1 flopin;
   end
endmodule

The thing that bugs me is that we qualify reset with 'if (!clr_bar)'
and not 'if (clr_bar == 1'b0)' which I have observed results in this
flop reseting when clr_bar == 1'bx and the clock is running.

Can someone tell me what are some of the dangers besides gate-to-RTL
modeling mismatches? Has anyone ever observed bugs escaping to silicon
or other problems from modeling flops like this? I know it's a widely
proffered modeling pattern.
 
mag wrote:
We model our async resets like this:


module AsyncResetFlop(flopout, flopin, clr_bar, clock);


output [WIDTH-1:0] flopout;

input [WIDTH-1:0] flopin;

input clr_bar;

input clock;

reg [WIDTH-1:0] temp;


// synopsys async_set_reset "clr_bar"

// cadence async_set_reset "clr_bar"


assign flopout = temp;

always @(posedge clock or negedge clr_bar) begin

if (!clr_bar) temp <= #1 {WIDTH{1'b0}};

else temp <= #1 flopin;

end

endmodule


The thing that bugs me is that we qualify reset with 'if (!clr_bar)' and
not 'if (clr_bar == 1'b0)' which I have observed results in this flop
reseting when clr_bar == 1'bx and the clock is running.
Are you sure you have this correct? If clr_bar is undefined then "!" of
an undefined value should return 1'bx which is false and the reset
should not execute. Using "==" should also return 1'bx or false. Using
"===" will also return false (1'b0). To switch the pessimism you could
use "!== 1'b1". Synthesis tools do not support the "===" or "!=="
functionality, but may convert then to "==" or "!=" respectively.

If I had the possibility of an undefined asynchronous reset I'd want the
output to be undefined if the current output was high or was going to be
set high. You can easily do that with a UDP or by adding something like
the following which only works for a single bit. Making it work with
multiple bits is left as an exercise for the user:

// cadence synthesis_off
always @(clr_bar or out)
if (clr_bar === 1'bx || clr_bar === 1'bz) begin
if (out == 1'b1) force out = 1'bx;
end else release out;
// cadence synthesis_on

This may not work at T0 if clr_bar is set to an undefined value before
the always block is activated so make sure it is defined correctly at
the start of the simulation.

I hope this helps.

Cary
 
On 2010-01-30 21:05:36 -0800, Cary R. said:

mag wrote:
We model our async resets like this:


module AsyncResetFlop(flopout, flopin, clr_bar, clock);


output [WIDTH-1:0] flopout;

input [WIDTH-1:0] flopin;

input clr_bar;

input clock;

reg [WIDTH-1:0] temp;


// synopsys async_set_reset "clr_bar"

// cadence async_set_reset "clr_bar"


assign flopout = temp;

always @(posedge clock or negedge clr_bar) begin

if (!clr_bar) temp <= #1 {WIDTH{1'b0}};

else temp <= #1 flopin;

end

endmodule > > > The thing that bugs me is that we qualify reset with
'if (!clr_bar)' and > not 'if (clr_bar == 1'b0)' which I have observed
results in this flop > reseting when clr_bar == 1'bx and the clock is
running.

Are you sure you have this correct? If clr_bar is undefined then "!" of
an undefined value should return 1'bx which is false and the reset
should not execute. Using "==" should also return 1'bx or false. Using
"===" will also return false (1'b0). To switch the pessimism you could
use "!== 1'b1". Synthesis tools do not support the "===" or "!=="
functionality, but may convert then to "==" or "!=" respectively.

If I had the possibility of an undefined asynchronous reset I'd want
the output to be undefined if the current output was high or was going
to be set high. You can easily do that with a UDP or by adding
something like the following which only works for a single bit. Making
it work with multiple bits is left as an exercise for the user:

// cadence synthesis_off
always @(clr_bar or out)
if (clr_bar === 1'bx || clr_bar === 1'bz) begin
if (out == 1'b1) force out = 1'bx;
end else release out;
// cadence synthesis_on

This may not work at T0 if clr_bar is set to an undefined value before
the always block is activated so make sure it is defined correctly at
the start of the simulation.

I hope this helps.

Cary
Yeah, I tried it on qsim and it modeled correctly. I'll try another
simulator to see if the modeling is consistent.
 
On Sat, 30 Jan 2010 21:05:36 -0800, "Cary R." wrote:

mag wrote:
We model our async resets like this:

module AsyncResetFlop(flopout, flopin, clr_bar, clock);
output [WIDTH-1:0] flopout;
input [WIDTH-1:0] flopin;
input clr_bar;
input clock;
reg [WIDTH-1:0] temp;

// synopsys async_set_reset "clr_bar"
// cadence async_set_reset "clr_bar"

assign flopout = temp;

always @(posedge clock or negedge clr_bar) begin
if (!clr_bar) temp <= #1 {WIDTH{1'b0}};
else temp <= #1 flopin;
end

endmodule

The thing that bugs me is that we qualify reset with 'if (!clr_bar)' and
not 'if (clr_bar == 1'b0)' which I have observed results in this flop
reseting when clr_bar == 1'bx and the clock is running.

Are you sure you have this correct? If clr_bar is undefined then "!" of
an undefined value should return 1'bx which is false and the reset
should not execute.
But the 'else' (clocked) branch WILL execute, just as if there
were an active clock edge at that moment. Don't you love it?
Presumably the OP saw a "reset" because the D inputs to the
flops were zero at that moment.

Rather than futzing around with force, how about...

always @(posedge clock or negedge clr_bar)
if (!clr_bar) // Reset is reliably on, do reset
temp <= #1 {WIDTH{1'b0}};
else if (clr_bar) // Reset is reliably off, do clock
temp <= #1 flopin;
// synthesis translate_off
else
temp <= {WIDTH{1'bx}};
// synthesis translate_on

It's just possible that you might need to enclose
the "if (clr_bar)" in translate_off/on as well, to
keep synthesis template matchers happy, but I doubt it.

Obviously, adjust the translate_on/off directive names
to match the perversions of your chosen synth tool(s).

By the way, what's the deal with "assign flopout=temp"?
Why not just push the reg out through the output port?
--
Jonathan Bromley
 
Jonathan Bromley wrote:
On Sat, 30 Jan 2010 21:05:36 -0800, "Cary R." wrote:

mag wrote:
We model our async resets like this:

module AsyncResetFlop(flopout, flopin, clr_bar, clock);
output [WIDTH-1:0] flopout;
input [WIDTH-1:0] flopin;
input clr_bar;
input clock;
reg [WIDTH-1:0] temp;

// synopsys async_set_reset "clr_bar"
// cadence async_set_reset "clr_bar"

assign flopout = temp;

always @(posedge clock or negedge clr_bar) begin
if (!clr_bar) temp <= #1 {WIDTH{1'b0}};
else temp <= #1 flopin;
end
endmodule

The thing that bugs me is that we qualify reset with 'if (!clr_bar)' and
not 'if (clr_bar == 1'b0)' which I have observed results in this flop
reseting when clr_bar == 1'bx and the clock is running.
Are you sure you have this correct? If clr_bar is undefined then "!" of
an undefined value should return 1'bx which is false and the reset
should not execute.

But the 'else' (clocked) branch WILL execute, just as if there
were an active clock edge at that moment. Don't you love it?
Actually I'm counting on it! After a bit more thought last night my
example is a bit overly pessimistic. More on that shortly.

Rather than futzing around with force, how about...

always @(posedge clock or negedge clr_bar)
if (!clr_bar) // Reset is reliably on, do reset
temp <= #1 {WIDTH{1'b0}};
else if (clr_bar) // Reset is reliably off, do clock
temp <= #1 flopin;
// synthesis translate_off
else
temp <= {WIDTH{1'bx}};
// synthesis translate_on
This doesn't work like my example. Here is what I think is a fully
working example with the correct pessimism.

always @(clr_bar or out)
if (clr_bar === 1'bx) temp = temp & {WIDTH{1'bx}};
else if (clr_bar === 1'bz) temp = {WIDTH{1'bz}};

The first line sets only the bits that are high to 1'x if the reset is
undefined. If it is high-Z (unlikely) we set the whole vector to 'bx.
Now the other block needs some tweaking.

always @(posedge clock or negedge clr_bar)
if (~clr_bar) temp <= {WIDTH{1'b0}};
else if (clock) temp <= flopin;

The clock test is needed so that an undefined clr_bar does not latch new
data. The clock test should be removed as redundant, but it may need to
be hidden from the synthesizer. We don't want to block the clock
latching since if clr_bar is undefined and we get a clock event that
loads a zero value we want that to happen since that is the correct
pessimism. In reality we load on all clock when clr_bar is undefined and
then let the other block fix any problems. Now we'll but the superfluous
assign to good use.

assign #1 flopout = temp;

This filters the time zero glitches that can be created by the two
always blocks. Notice I removed the delays from the original always block.

This is very extreme and needs to be tailored to the individual users
exact expectation. In general don't let your clock or asynchronous
clear/set signals become undefined and you can use the normal pattern
and everything will work as expected.

Cary
 
A proper language would treat X as "either 0 or 1", and the simulator
would have to consider both paths, which is what formal verification
tools do. You couldn't do this dynamically, of course - it would be
too slow.

Mike Turpin's written a good paper on X's
(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.arp0009a/index.html).
He recommends not using if statements at all ("avoid using if
statements, as they optimistically interpret X's. Instead use ternary
(ie conditional ?) operators or priority-encoded case statements)."

I personally am not keen on ?: either; it's optimistic compared to a
gate-level description (if you have a metaval on the control input,
and apply 11 to an AND-OR mux, you get X; if you apply 11 to ?:, you
get 1). This leads to the strange conclusion that a mux is best
implemented behaviourally, as an array lookup, as this is fully
pessimistic.

-Evan
 
On Mon, 01 Feb 2010 14:07:57 +0000, Evan Lavelle <nospam@nospam.com>
wrote:

I personally am not keen on ?: either; it's optimistic compared to a
gate-level description (if you have a metaval on the control input,
and apply 11 to an AND-OR mux, you get X; if you apply 11 to ?:, you
get 1).
Not in actual hardware though. If you treat X as unknown as opposed to
to a meta level where the voltage is fleetingly between logic levels
then an and-or mux will work the same was as ?: does.

This leads to the strange conclusion that a mux is best
implemented behaviourally, as an array lookup, as this is fully
pessimistic.
Actually too pessimistic to use. For that reason almost every standard
cell library implements muxes with a primitive which removes that
pessimism. Here is an example:

primitive udp_mux2 (out, in0, in1, sel);
output out;
input in0, in1, sel;

table

// in0 in1 sel : out
//
1 ? 0 : 1 ;
0 ? 0 : 0 ;
? 1 1 : 1 ;
? 0 1 : 0 ;
0 0 x : 0 ;
1 1 x : 1 ;

endtable
endprimitive // udp_mux2

This shows how the actual physical gate behaves (for that library).
--
Muzaffer Kal

DSPIA INC.
ASIC/FPGA Design Services

http://www.dspia.com
 
On Mon, 01 Feb 2010 08:14:37 -0800, Muzaffer Kal <kal@dspia.com>
wrote:

On Mon, 01 Feb 2010 14:07:57 +0000, Evan Lavelle <nospam@nospam.com
wrote:

I personally am not keen on ?: either; it's optimistic compared to a
gate-level description (if you have a metaval on the control input,
and apply 11 to an AND-OR mux, you get X; if you apply 11 to ?:, you
get 1).

Not in actual hardware though. If you treat X as unknown as opposed to
to a meta level where the voltage is fleetingly between logic levels
then an and-or mux will work the same was as ?: does.
I'm just talking about 4-state simulation, not 2-state hardware. In
simulation, ?: has different behaviour to an and/or mux; it's more
optimistic, in that there's an input X condition that doesn't result
in X propagation to the output. In other words, exactly the same
problem that the OP was talking about and that Cary was trying to
model.

This leads to the strange conclusion that a mux is best
implemented behaviourally, as an array lookup, as this is fully
pessimistic.

Actually too pessimistic to use.
How so? It makes no difference if there are no X's in your simulation.
And, if there are X's, then you *must* find them. Having code that
blocks X's at certain constructs is intrinsically dangerous: it makes
it much more likely that you won't spot a real logic error, simply
because you didn't manage to specify a set of conditions that would
propagate the X to somewhere observable. This has to be one of the #1
problems in/with Verilog. The more pessimistic your X handling, the
more likely it is that X's will propagate to somewhere observable. I
can't think of any reasons at all to have optimistic X handling.
Pessimistic handling has absolutely no effect on designs which have no
X's, and on 2-state simulations (ie. "hardware"). In my experience,
pretty much the only thing that persuades people to move from Verilog
to VHDL is having a bad time with unobservable X's in Verilog.

-E
 
Unfortunately I don't have time for a more thorough reply, but here are
a few things. Given how an if works (it's procedural) you can't just mix
the two paths. The ternary operator satisfies your requirement, but will
all the various tools recognize

always@(posedge clk or posedge rst)
out <= rst ? 1'b0 : in;

as a flip flop? The synthesis tool I'm using at the moment does. The
problem with this is that it's a bit optimistic in generating an X when
"rst" goes from 1'b1 to 1'bx. For this case the result should not depend
on "in" until we get a positive clock edge. It also incorrectly samples
"in" for a 1'bx to 1'b0 transition on "rst". I personally think it is
better to use the standard FF format and then add the appropriate code
to catch/model this or add a monitor routine to flag an asynchronous
reset/set/clock/etc. going undefined.

Cary
 
Cary R. wrote:
The problem with this is that it's a bit optimistic in generating an
X when "rst" goes from 1'b1 to 1'bx. For this case the result should
not depend on "in" until we get a positive clock edge. It also
incorrectly samples "in" for a 1'bx to 1'b0 transition on "rst".
Ack, I just realized this is wrong! Only positive edges on rst activate
the block. I've been doing too much latch work lately! This may work
exactly as Evan wanted.

Cary
 

Welcome to EDABoard.com

Sponsor

Back
Top