4
\$\begingroup\$

In a number of sources I've come across, it's mentioned that for sensitivity lists which include an "edge", you cannot include other signals in the sensitivity list if you want synthesis to work.

Thus, for example, consider the code below for an active-low asynchronous-reset DFF:

always @(posedge clk or rstN)
  if (!rstN) q <= 0;
  else q <= d;

This is legal syntactically and will simulate, but synthesis compilers will not accept it. Instead, one needs to use negedge rstN. The simulation will be the same, but now it will synthesize as expected.

Why the prohibition by synthesis compilers against things like the snippet I gave above? Is there some fundamental aspect or ambiguity which makes parsing such a snippet hard for compilers?

I follow that this is outside of what is a synthesizable construct but I am hoping to understand why that is. That is, I'm hoping to understand why the compiler would struggle with synthesizing this?


Edit: After reading further, I should note that Sutherland does discuss exactly this case on page 289. Thus, we should emphasize two things: (1) As Tom says in the accepted answer, my snippet above does not even simulate correctly. (2) Even if it did simulate correctly (or, rather, even if we considered an analogous snippet which mixed signal levels with signal edges in the sensitivity list) we would not get the snippet to synthesize because it is a synthesis requirement that if posedge or negedge is used for one signal in a sensitivity list, then an edge must be specified for all signals in said sensitivity list.

\$\endgroup\$
4
  • \$\begingroup\$ It means different things for simulation and for synthesis. For simulation level signal sensitivity means that the process needs to be re-evaluated whenever this signal is changing. For synthesis sensitivity to edge signals mean that the process is describing clocked/sequential logic, as opposed to combinatorial logic described by process sensitive to level signals. \$\endgroup\$
    – Eugene Sh.
    Commented Feb 8 at 17:28
  • \$\begingroup\$ Totally agreed, but the asynchronous reset is not really part of the clocked logic right? I guess I'm wondering what would be so hard about a compiler reading the snippet I gave and noticing that it's meant as an async reset DFF? @EugeneSh. \$\endgroup\$
    – EE18
    Commented Feb 8 at 17:34
  • \$\begingroup\$ When you add a posedge reset to the sensitivity list, it will synthesize as asynchronous reset, as it will "trigger" the process on either the clock or the reset going high. If you don't, it will be synchronous, as the reset signal will only be "probed" on clock edge. \$\endgroup\$
    – Eugene Sh.
    Commented Feb 8 at 17:39
  • \$\begingroup\$ See my comments below too if possible @EugeneSh. I follow why omitting the reset wouldn't give correct behavior, but not why just using a level of the reset rather than an edge wouldn't work. \$\endgroup\$
    – EE18
    Commented Feb 8 at 18:02

2 Answers 2

8
\$\begingroup\$

Your example, and the standard negedge rstN do not have the same behaviour. Let's see why.


I assume we are trying to make a positive edge clocked D-FF with an asynchronous active-low reset. So lets start building up the desired behaviour. The first thing we need is to have an output, q, change whenever there is a positive clock edge:

always @(posedge clk)
    q <= d;

As I'm sure you know, this simply states, at the positive edge of a clk, q is updated to equal d. Great, that's the expected behaviour of a D-FF.

Now we want to add in a reset:

always @(posedge clk)
    if (!rstN) q <= 0;
    else q <= d;

When the block is executed, which at the moment is posedge of clk, then if rstN is low, the output q will be set to 0, otherwise it will still set d. Great, we have a reset behaviour. However this only happens at the positive edge of the clock, it's a synchronous reset.

To make it asynchronous, we need to trigger the block when the reset signal needs to be handled. We have two ways of triggering an always block, level sensitivity and edge sensitivity.

Let's look at what level sensitivity implies, your example:

always @(posedge clk or rstN)
    if (!rstN) q <= 0;
    else q <= d;

When rstN goes low, the block executes, regardless of whether there is a clock edge (hurray, async reset). q is set to 0, because rstN is low.

Now what happens if rstN goes high? The block executes again! q is now set to d because rstN is high. Argh! This is not the behaviour we want, the D-FF has just changed its output in response to the reset being released!

Instead we will try edge sensitivity:

always @(posedge clk or negedge rstN)
    if (!rstN) q <= 0;
    else q <= d;

When rstN goes low, the block executes, regardless of whether there is a clock edge (hurray, async reset). q is set to 0, because rstN is low.

Now what happens if rstN goes high? Absolutely nothing. q retains its reset value. Problem solved, de-assertion of the reset no longer causes the D-FF to change its output state.

So to get an async reset, we must use edge sensitivity for both clock and reset.


Perhaps though, you want the behaviour of clock on release of the reset. This is not the usual behaviour for our standard circuit elements. To implement this in hardware would require a more complicated circuit than a simple DFF. Something like:

reg qsel;
reg qclk;
reg qrst;

// Detect first posedge-clock after reset
always @ (posedge clk or negedge rstN)
    if (!rstN) qsel <= 0;
    else qsel <= 1;

// Normal D-FF
always @ (posedge clk or negedge rstN)
    if (!rstN) qclk <= 0;
    else qclk <= d;
    
// Shadow D-FF used to load d when exiting reset
always @ (posedge rstN)
    qrst <= d;

// When reset is released, but before first clock 
// occurs, output the value clocked by reset release,
// otherwise use normal D-FF output.
assign q = (rstN && !qsel) ? qrst : qclk;

I haven't simulated it, and would make for a terrible circuit implementation, but that is in essence what would have to be inferred from your design.

The question is, is that a construct which would be of much general use? Probably not. In which case there is little point in the synthesis tools being able to directly infer it.

\$\endgroup\$
2
  • \$\begingroup\$ Wow, thank you so much for this answer! You are right, I was naive to assume that I got correct operation from my little snippet. Thanks for pointing that out. I guess my error wasn't the crux of my question because I could, I assume, come up with an example which would simulate correctly and include a mixed sensitivity list but, as you and toolic point out, that is not the point. Thanks again! \$\endgroup\$
    – EE18
    Commented Feb 8 at 19:21
  • \$\begingroup\$ Just made an edit to the effect of my comment too. Let me know what you think if you get the chance, and thanks again for your help! \$\endgroup\$
    – EE18
    Commented Feb 12 at 20:17
2
\$\begingroup\$

Synthesis software relies on your Verilog code to follow specific synthesizable construct patterns. Although your code simulates as you desire, this pattern is not recognized by synthesis tools as matching some know intended hardware.

Limiting the types of patterns simplifies the synthesis software design. It would be practically impossible to map any arbitrary legal Verilog code to some inferred hardware. The synthesis documentation should outline the coding style which is allowed for the given tool.

In this particular case, since you intend to infer a flop with an asynchronous active-low reset, the synthesis tool expects to see two things:

  1. A sensitivity list which includes the negedge nrst expression.
  2. The first if condition to check that the reset signal is low.

The synthesis tool needs to match negedge to !, for example.

\$\endgroup\$
4
  • \$\begingroup\$ I see. I guess my question is about why this particular construct would be so hard to infer, but I guess I'd need to know a lot more about hardware language compilation in order to answer that? \$\endgroup\$
    – EE18
    Commented Feb 8 at 17:29
  • \$\begingroup\$ @EE18: It's hard in the sense that there are too many ways to write Verilog code to do the same thing in simulation. See my updated answer. \$\endgroup\$
    – toolic
    Commented Feb 8 at 17:38
  • \$\begingroup\$ I see I think. So you're saying it's not an in principle objection to the particular snippet I wrote (i.e. you could write a compiler that would also synthesize correctly with this) but rather that we make an in practice decision to simplify and only allow certain constructs as synthesizable? \$\endgroup\$
    – EE18
    Commented Feb 8 at 17:40
  • \$\begingroup\$ @EE18: Yes, that is my understanding of it. \$\endgroup\$
    – toolic
    Commented Feb 8 at 17:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.