Question

I have a CPLD with a digital input representing a reset button. When the reset button is pressed, the signal goes high. What I need to do is have a register whose value tells if the button has ever been pressed. Basically a latch. When the button goes high, a latch register goes high and stays high forever.

I thought this would be straightforward, but I got a bunch of warnings when I tried to code it up. A little Googling showed "Don't make latches in HDL! Bad practice!", but I don't really see the alternative here.

Here's my attempt. clk_10m is a fast free-running clock, pwr_off_req is the button input.

reg pwr_off_req_latched = 0;

always @ (clk_10m or pwr_off_req) begin

   if (pwr_off_req == 1'b1)
      pwr_off_req_latched <= 1'b1;   
   else
      pwr_off_req_latched <= pwr_off_req_latched;
      // I tried this to make sure it's always set to something          
end
Was it helpful?

Solution

Can you assume that the pulse length of the button press is much longer than the clock frequency of your device? If it's a physical button I think that is a very safe assumption. In that case I think this would work perfectly fine:

always @(clk_10m) 
   pwr_off_req_latched <= power_off_req_latched | power_off_req;

OTHER TIPS

Latches are not bad in HDL they just require some consideration, implied latches from forgetting to specify else clauses in combinatorial sections are bad because you do not end up with the hardware you expect, and can create timing problems.

If you are applying a reset you might need to specify a 'pragma' so that the synthesis tool correctly identifies it.

Also latches should use = not <=, when they are enabled they are combinatorial (open) and will not break feedback loops.

This is typical way to create a latch with an asynchronous reset:

//synopsys async_set_reset "rst_an"
always @* begin
  if (~rst_an) begin
    // Reset 
    x = 1'b0;
  end
  else if (latch_open) begin
    //next datavalue
    x = y ;
  end
end

In your case you might want something like :

//synopsys async_set_reset "rst_an"
always @* begin
  if (~rst_an) begin
    pwr_off_req_latched = 1'b0;
  end
  else if ( pwr_off_req ) begin
    pwr_off_req_latched = 1'b1 ;
  end
end

Latches can create problems for timing analysis tools. They also don't map to certain (FPGA) architectures directly, so are much harder for the place-and-route tools. Hence the warnings.

However, what you are asking for is not a latch as I understand the digital logic sense - merely a flipflop which doesn't ever get reset.

So, it can be simplified to a simple d-type flipflop with the D input tied to 1 and the clk input connected to your pwr_off_req signal:

reg pwr_off_req_latched = 0;

always @ (posedge pwr_off_req) begin
      pwr_off_req_latched <= 1'b1;   
end

You'll have no noise rejection on that at all - any positive going edge will latch the flipflop to 1.

If I were doing this, I would run the input into a double-flip-flop synchroniser and then count a few clock pulses of the synchronised signal to make sure it's not noise before setting the latched signal. Unless you are expecting real events shorter than a few clock pulses that'd the way to do it.


Aside:

A "latch" in the digital logic world usually means either

  • a circuit whose output holds whichever of the two inputs was last high (a Set/Reset or SR latch)
  • a circuit whose output holds the input value while a control signal is inactive, but follows the input when the control signal is low - a transparent latch

This is in comparison to a flipflop, whose output holds some aspect related to the input(s) when the control signal changes (usually) from low to high, and ignores the inputs except for a tiny time window around that rising edge. These are D-type, T-type and JK-type flipflops, depending on how the output behaves relative to the input.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top