Can SystemVerilog represent a flip-flop with asynchronous set and reset without adding unsynthesizable code?

6.4k views Asked by At

I'm coming from a Verilog-95 background, and I'm trying to figure out what Verilog-95 hoops I don't have to jump through anymore.

The obvious way to write a flip flop with async set and reset in Verilog-95 is:

always @(posedge clk or negedge resetb or negedge setb) begin
  if (!resetb)      q <= 0;
  else if (!setb)   q <= 1;
  else              q <= d;
end

This works in synthesis. But, this doesn't work in simulation if we ever assert both resetb and setb, and then de-assert resetb before de-asserting setb, since there's no posedge trigger for either of those signals. We need to add the following (which varies depending on your synthesis tool), to get simulation to match synthesis:

// synopsys translate_off
always @(resetb or setb)
  if (resetb && !setb) force q = 1;
  else               release q;
// synopsys translate_on

Is there a SystemVerilog construct that will let you do this without this extra junk? Better yet, is there a straightforward way to do it in Verilog-95?

5

There are 5 answers

0
Andy On BEST ANSWER

Flip-flops with multiple asynchronous controls are best avoided. The timing checks necessary to ensure they function properly are complex and easy to mess up. If you really need to use them, then it's probably best to instantiate them by hand where needed. If you let your synthesis tool infer them, it may use them in places you don't intend, which increases the risk that the timing checks don't get done properly.

One final aside, there is a similar simulation-synthesis mismatch issue with all asynchronous flops, if the active edge of reset is at time zero and is simulated before the flop is initialized to x, and the clock isn't running in reset. I believe some simulators have special cases to ensure the logic is not initialized in this order.

That said, I had luck moving the priority logic outside the sequential always block. Note I'm using active-high signals for simplicity.

assign s_int = s && !c;

always @(posedge clk or posedge s_int or posedge c) begin
        if (c)
                q <= 1'b0;
        else if (s_int)
                q <= 1'b1;
        else
                q <= d;
end
1
DOS On

Try this: always_ff @(posedge clk or negedge resetb or negedge setb)

systemverilog uses always_ff for clock triggered logic and always_comb for combo logic

0
Greg On

This is something I wish SystemVerilog had improved. If you want to allow both being low at the same time, then stick with the current method.

The other option is to create a design rule stating the asynchronous signals can not be active at the same time and enforce the rule with an assertion. Assertions are suppose to be ignored by synthesizers, so translate_off/on should not be be necessary.

Here is an example using an inline assertion:

always_ff @(posedge clk, negedge resetb, negedge setb) begin : dff_asyncRbSb
  if (!resetb)      q <= 0;
  else if (!setb)   q <= 1;
  else              q <= d;
  asrt_setrst : assert(resetb||setb)
     else $error("resetb and setb can not be low at the same time.");
end : dff_asyncRbSb
0
EML On

I don't know any SV, so this isn't an answer, but the issue here is that Verilog (and, I think, SV) event expressions are basically broken. The problem is that, when you have multiple conditions in an event expression:

event_expression ::=
  expression 
  | hierarchical_identifier
  | posedge expression
  | negedge expression
  | event_expression or event_expression
  | event_expression , event_expression

then there's no bullet-proof way to determine which expression caused the event, since the only thing you can do is to check the current state of the expression. So, if you've got @(posedge clk, posedge rst), for example, you look at the current levels of clk and rst and hope this is sufficient to do the job. In general, it isn't, but your example is the only practical case (I think) that causes a problem.

VHDL handles this by having signal attributes, which let you determine whether a signal has caused an event. In VHDL, you get an event when any signal in your sensitivity list changes, and you then check their 'event attribute to determine whether they fired the process. No confusion, no posedge or negedge, and it all works.

I've just had a quick look at the SV LRM, and SV attributes appear to be the same as Verilog attributes, so I think you're out of luck.

0
Sourabh On

with no edge defined, the assertion and de-assertion of reset and set signals should be able to trigger this code in simulation.

always_ff should be able to create a flop at synthesis.

Below code is compilation clean using synopsys VCS tool.

always_ff @(posedge clk, resetb,  setb) begin 
  if (!resetb)      q <= 0;
  else if (!setb)   q <= 1;
  else              q <= d;
end