Demonstration of how NOT to implement edge detection and asynchronous inputs to a state machine

I will demonstrate how NOT to implement edge detection and asynchronous inputs to a state machine (e.g. 'FDPORT' in the code snippet from post #3 in this thread), with three examples written in (pseudo) Verilog.  The fourth example is a design which successfullyaddresses the problem.

Example #1:  Straight input to a state machine using states for edge detection.

input   clock, async_in;

reg   [3..0]  state = idle;
reg           in_dly1, in_dly2, in_dly3, edge_flag;
reg           edge_flag;

wire          edge_detected;

always @(posedge clock)
  case (state)


    idle:  begin   // wait for a low level on asynchronous input async_in
       edge_flag <= 0;
       if (async_in == 0)  state <= found_zero;
       end
        
     found_zero:  if (async_in == 1)  state <= found_edge;

     found_edge:  begin   // rising edge found, set a flag, loop back to idle state
       edge_flag <= 1;
       state <= idle;
       end

    endcase

In example #1, the async_in input signal will propagate through to the inputs of the 4 bits of state registers at different times.  This is because the interconnect delays are not matched -- and they cannot be matched.  The delay mis-match can be more than a nano-second.  If a transition of async_in occurs as the signal is being sampled, the odds are very very good that the various state machine bits will sample different values of async_in.  If at least one state bit will see a '0' and at least one state bit sees a '1', then the state machine will fail.  The normal symptom is 'lockup'.

我: 检测 if (async_in == 0) 时出现 async_in 的跳变, 导致state赋奇怪的值.

Example #2:  Single-register logic for edge detection.

input   clock, async_in;

reg   [3..0]  state = idle;
reg           in_dly1, in_dly2, in_dly3, edge_flag;
reg           edge_flag;

wire          edge_detected;
 

always @(posedge clock)  in_dly1  <= async_in;  // delay input one clock cycle

assign  edge_detected = async_in && !in_dly1;   // async_in was '0', now '1', rising edge detected

always @(posedge clock)
  case (state)


    idle:  begin   // wait for a low level on asynchronous input async_in
       edge_flag <= 0;
       if (edge_detected == 1)  state <= found_edge;  // edge found!
       end
        
     found_edge:  begin   // rising edge found, set a flag, loop back to idle state
       edge_flag <= 1;
       state <= idle;
       end

    endcase

In example #2, the async_in input signal has the same problem as in example #1.  It will still propagate through to the inputs of the 4 bits of state registers at different times, through the signal edge_detected.  The single delay register for async_in is not sufficient.

Example #3:  Two-register logic for edge detection.

input   clock, async_in;

reg   [3..0]  state = idle;
reg           in_dly1, in_dly2, in_dly3, edge_flag;
reg           edge_flag;

reg           edge_detected;
 

always @(posedge clock)  in_dly1  <= async_in;  // delay input one clock cycle

always @(posedge clock)  edge_detected = async_in && !in_dly1;   // async_in was '0', now '1', rising edge detected



always @(posedge clock)
  case (state)


    idle:  begin   // wait for a low level on asynchronous input async_in
       edge_flag <= 0;
       if (edge_detected == 1)  state <= found_edge;  // edge found!
       end
        
     found_edge:  begin   // rising edge found, set a flag, loop back to idle state
       edge_flag <= 1;
       state <= idle;
       end

    endcase

In example #3, it looks like the input to the state machine is properly registered and problem-free.  Yes, but a slightly different problem has been created.  async_in is still sampled at two different registers.  As before, the propagation delay mismatch to these two registers will inevitably result in either missed edges (register in_dly1 sees async_in transition a cycle earlier than registeredge_detected) or double  triggers (register edge_detected sees async_in transition a cycle earlier than register in_dly1).  This two-register solution for async_in is not sufficient.

Example #4:  Another two-register logic solution for edge detection.

input   clock, async_in;

reg   [3..0]  state = idle;
reg           in_dly1, in_dly2, in_dly3, edge_flag;
reg           edge_flag;

wire          edge_detected;
 

always @(posedge clock)  in_dly1  <= async_in;  // delay input one clock cycle

always @(posedge clock)  in_dly2  <= in_dly1;   // delay input a second clock cycle

assign  edge_detected = in_dly1 && !in_dly2;    // async_in was '0', now '1', rising edge detected



always @(posedge clock)
  case (state)


    idle:  begin   // wait for a low level on asynchronous input async_in
       edge_flag <= 0;
       if (edge_detected == 1)  state <= found_edge;  // edge found!
       end
        
     found_edge:  begin   // rising edge found, set a flag, loop back to idle state
       edge_flag <= 1;
       state <= idle;
       end

    endcase

In example #4, async_in is sampled at a single register: in_dly1, eliminating the problem of mismatched delays and disagreement between multiple sampling points.  The output of in_dly1 is aligned to the clock, and is safe for distribution to clocked logic in the design -- including the multi-bit state machine. The standard static timing analysis tools apply for the output of register in_dly1. This two-register solution for async_in is sufficient for aligning this asynchronous input to the synchronous system.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值