4

I have a fast clock and a switch called 'ready'. When the switch is flipped (ready goes HIGH), I would like the output pcEn to produce a pulse that lasts only for one clock cycle. pcEn will only output another pulse the next time ready goes HIGH again.

The following code simulates correctly, but is unfortunately not synthesizable. Note that space is an important consideration, so I was wondering if it's possible to implement it without using a state machine (which uses a lot of logic elements).

module control
(
    output logic pcEn,
    input clock, ready
);

always_ff @(negedge clock)
    pcEn <= 1'b0;

always_ff @(posedge ready)
    pcEn <= 1'b1;

endmodule
geft
  • 425
  • 7
  • 15
  • 2
    It is not generally true that 'a state machine... uses a lot of logic elements'. Tools mostly encode them to one-hot and use one register per reachable state. Control logic tends to be dwarfed by data path multiplexers, adders etc. – shuckc Mar 12 '14 at 12:02
  • I guess so. At the moment my adder is consuming tons of logic elements. Is there a away to divert these resources to the RAM or embedded multipliers (they are cheap in my case)? – geft Mar 12 '14 at 12:06
  • there's no adder above, so it's hard to say – shuckc Mar 12 '14 at 12:08
  • Ah, I don't think it's appropriate to post my adder code here as well since it's not relevant to the question. However, it's just a simple adder with no carry in or out. Basically a bunch of XOR gates. – geft Mar 12 '14 at 12:18
  • 1
    @geft: I'd suggest posting a question about reducing the size of the adder separately (although if you've just done y <= a+b, there's probably not much to be done about it unless you have other special circumstances!) – Martin Thompson Mar 12 '14 at 19:38

3 Answers3

6

My usual technique is to implement a 2-stage synchronizer to bring the asynchronous input in to the clock's timing domain, and then use one more flip-flop as the edge detector. Depending on the logic you use in the last statement, you can detect rising edges, falling edges or both.

module control
(
    output logic pcEn,
    input clock, ready
);
    reg r1, r2, r3;

    always @(posedge clock) begin
        r1 <= ready;    // first stage of 2-stage synchronizer
        r2 <= r1;       // second stage of 2-stage synchronizer
        r3 <= r2;       // edge detector memory
    end

    pcEn <= r2 && !r3;   // pulse on rising edge
endmodule
Dave Tweed
  • 168,369
  • 17
  • 228
  • 393
  • Thank you. How does this compare to shuckc's modified answer above? It seems to use more logic elements than necessary. – geft Mar 12 '14 at 13:12
  • 3
    It uses 3 FFs and one LUT. This is the minimum required to deal correctly with an asynchronous input. – Dave Tweed Mar 12 '14 at 13:15
  • Ah, I see. I've never used one before. I'll see how it goes. – geft Mar 12 '14 at 13:53
  • Thanks for the above answer. Here's a good [reference](http://courses.csail.mit.edu/6.111/f2007/handouts/L07.pdf) on level to pulse converter which also explains other implementations for the above logic. – Rajesh Shashi Kumar Apr 25 '19 at 03:29
1

The usual formation for toggle-to-pulse is along the lines of

module flip (output logic pcEn, input clock, input ready);
reg state;
always_ff @(posedge clock)
      state <= ready;
assign pcEn = state != ready;
endmodule

If ready is externally driven it's worth cleaning it up to align with a clock edge with a single register stage first. There's no need for the reset. If you are going to count the output, you also need to address switch bounce.

To address Daves's comment: modified to have to registered output pcEn and to trigger on rising edge.

module flip (output reg pcEn, input clock, input ready);
reg state;
always_ff @(posedge clock) begin
      state <= ready;
      pcEn  <= state != ready && ready;
end
endmodule

enter image description here

shuckc
  • 3,012
  • 14
  • 19
  • Doesn't seem to work as state is equal to ready. When simulated pcEn just toggles HIGH and LOW simultaneously during edge trigger. – geft Mar 12 '14 at 12:37
  • 1
    This is an incorrect answer; it will produce a pulse on both rising and falling edges of the input signal. Also, the output pulse will be *less than* one clock wide. – Dave Tweed Mar 12 '14 at 12:39
  • 1
    Even with the edit, you're still not handling the asynchronous input `ready` correctly; there's a possibility of setup/hold time violations on the last flip-flop, putting it into a metastable state. – Dave Tweed Mar 12 '14 at 13:13
  • @DaveTweed Thanks, I didn't realize it could be a problem. – geft Mar 12 '14 at 13:54
0

This is what Xilinx seems to recommend, which isn't too far from Dave Tweed's:

(* ASYNC_REG = "TRUE" *) reg     state;
(* ASYNC_REG = "TRUE" *) reg     statemeta;
reg                              reloadRegmeta  = 1'b0;

# -> for negative edge    assign pcEn = state | (~reloadRegmeta);
assign pcEn = state && (~reloadRegmeta);
always @(posedge S_AXI_ACLK) begin
    statemeta     <= ready;
    state         <= statemeta;
    reloadRegmeta <= state;
end