【转】一道verilog的小题

Question: 
The example below models a flip-flop with asynchronous set/reset logic (active low).   
The model synthesizes correctly, but there is a corner case where simulation results are incorrect. What is the corner case? 

always_ff @( posedge clk or negedge rst_n or negedge set_n) begin
    if(!rst_n)            q_out   <=  '0;
    else if(!set_n)     q_out   <=  '1;
    else                    q_out   <=  data_in;
end

Answer


This model synthesizes as intended.  However, the model does not work correctly for all simulation conditions.  Consider rst_n going low, which correctly asynchronously resets the flip-flop.  While rst_n is low, set_n goes low.  With both rst_n and set_n low at the same time, the flip-flop will correctly remain in reset, because of the priority coding of reset over set in the model.  Everything is OK so far.  Next, rst_n goes high and set_n stays low.  Since the sensitivity list is only sensitive to leading edges (the negedge of rst_n and set_n), the release of rst_n will not trigger the sensitivity list.  This means that the flip-flop will be in a reset state when only the set signal is active.

Gotcha!

This gotcha only exists with synthesizable asynchronous set/reset flip-flops, and will only be evident until the next clock.  The next clock will cause the if...else decisions to be re-evaluated and transition the flip-flop to its set state. The problem is that actual asynchronous set/reset inputs are level sensitive, so when the reset is removed, the active set takes over and drives the flip-flop to its set level.  In the model, however, synthesis rules require the sensitivity list trigger on the leading edges of the set/reset inputs, causing the simulation to differ from actual hardware behavior.

This gotcha is a result of the synthesis-imposed coding style for a set/reset flip-flop.  This style requires that all signals in a sequential-logic sensitivity list be specified with an edge (posedge or negedge).  In order to model accurate simulation behavior, the asynchronous set/reset signals need to be sensitive to all changes on those signals, not just one edge (the leading edge) of those signals.

To avoid this gotcha, a recommended coding style (created by Don Mills of LCDM Engineering) is to:
1) Add a level-sensitive condition to the sensitivity list that triggers on the trailing edge of reset when set is active.
2) Use conditional compilation (`ifdef/`endif) or synthesis pragmas (translate_off/translate_on) to hide the additional sensitivity list condition from synthesis compilers.

Here's the recommended way to code the previous example:

always_ff @(   posedge clk
            or negedge rst_n                  // active-low reset
            or negedge set_n                  // active-low set
  `ifndef SYNTHESIS                           // non-synthesizable simulation code
            or posedge (rst_n & ~set_n)       // trailing edge of reset when set is low
  `endif
           )
  if (!rst_n)                 q_out <= '0;
  else if (!set_n)            q_out <= '1;
  else                        q_out <= data_in;


An alternative coding style (invented by Cliff Cummings many years ago) to avoid this gotcha is to use the verification force/release commands to override the simulation behavior of the synthesizable model. This method requires adding an additional always block to the model, that is hidden from synthesis using conditional compilation. Note that this alternate solution must use Verilog's general_purpose "always" procedural block. It cannot take advantage of SystemVerilog's always_comb procedural block, because always_comb does not allow multiple procedural blocks to write to the same variables.

`ifndef SYNTHESIS           // start non-synthesizable simulation code
always @*
   if (rst_n && !set_n)  force   q_out = 1'b1;
   else                  release q_out;
`endif                      // start synthesizable and simulatable code
always_ff @(posedge clk, negedge rst_n, negedge set_n)
  if (!rst_n)       q_out <= '0;
  else if (!set_n)  q_out <= '1;
  else              q_out <= data_in;

 

posted @ 2012-05-08 23:02  poiu_elab  阅读(448)  评论(0编辑  收藏  举报