0
\$\begingroup\$

I have a problem with an "always" block in Verilog. First let me present the code:

module syncRX(clk, signal, detect, output clk_1khz);
    input clk, signal;
    output reg [7:0] detect = 0;

    //wire clk_1khz;
    freq_div div(.clk(clk), .clk_1khz(clk_1khz));
    
    always @(posedge signal, posedge clk_1khz)
     begin
        detect <= detect + 1;
     end

endmodule // top

module freq_div(input clk, output reg clk_1khz);
    reg [12:0] count = 0;
    always @(posedge clk)
     begin
        if(count == 6000)
            begin
                clk_1khz <= ~clk_1khz;
                count <= 0;
            end
        else
            count <= count + 1;
     end
    
endmodule

I got this error message (using Icestorm):

Executing PROC_DFF pass (convert process syncs to FFs).
Creating register for signal \freq_div.\clk_1khz' using process \freq_div.$proc$syncRX.v:22$4'.
 created $dff cell $procdff$15' with positive edge clock.
 Creating register for signal \freq_div.\count' using process \freq_div.$proc$syncRX.v:22$4'.
   created $dff cell $procdff$16' with positive edge clock.
 Creating register for signal \syncRX.\detect' using process \syncRX.$proc$syncRX.v:8$1'.
 ERROR: Multiple edge sensitive events found for this signal!
 make: *** [Makefile:44: syncRX.bin] Error 1

I could detect that the "always" block involved is:

always @(posedge signal, posedge clk_1khz)
     begin
        detect <= detect + 1;
     end

becaise if change "always @(posedge signal, posedge clk_1khz)" for "always @(posedge signal)" works.

Also fails in that same way:

always @(posedge signal)
     begin
        detect <= detect + 1;
     end
    
    always @(posedge clk_1khz)
     begin
        detect <= detect + 1;
     end

And the error disappears when comment the line "detect <= detect + 1;" in bought of cases. Then the error is related to the access to the "detect" counter register. I have not idea why I can not trigger this counter from two different signals, but in fact, I have to increase the counter in bought post edge signals (and I can figure out in my mind a very simple digital circuit doing this), I know that HDL dont allow synthesis of multiple driven register (handle register from many different always block), but in fact I can draw a OR Gate in my mind for do it, also there is many features can not be implemented without this practice, then should be a way to do in Verilog. I add a schematic about that I have in mind: enter image description here

\$\endgroup\$
2
  • 1
    \$\begingroup\$ "I can figure out in my mind a very simple digital circuit doing this" You are probably mistaken. Show us a counter that can take two independent edge-triggered clocks. \$\endgroup\$
    – Dave Tweed
    Commented Aug 23, 2020 at 12:00
  • 2
    \$\begingroup\$ That doesn’t have the same behavior. In your schematic, if ‘signal’ is high, then ‘clock’ edges don’t affect the logic and vice versa. Your code calls for responding to ‘clock’ edges even when ‘signal’ is high. \$\endgroup\$
    – The Photon
    Commented Aug 23, 2020 at 15:16

1 Answer 1

2
\$\begingroup\$

I'm not sure why you need this functionality — there's almost certainly a better approach — but here's how I'd go about it. I hope the comments make it self-explanatory. I'm assuming that signal is slower than your 12 MHz clock.

module syncRX (
  input                 clk,
  input                 signal,
  output reg      [7:0] detect,
  output                clk_1khz
);

  freq_div div (
    .clk        (clk),
    .clk_1khz   (clk_1khz)
  );

  /* Bring "signal" into the 12 MHz clock domain and do positive edge detection.
   */
  reg signal_delay_a;
  reg signal_delay_b;
  always @(posedge clk) begin
    signal_delay_a <= signal;
    signal_delay_b <= signal_delay_a;
  end
  wire signal_posedge = signal_delay_a & !signal_delay_b;

  /* "clk_1khz" is already in the 12 MHz clock domain; do positive edge
   * detection.
   */
  reg reference_delay;
  always @(posedge clk) reference_delay <= clk_1khz;
  wire reference_posedge = clk_1khz & !reference_delay;

  /* Increment the counter if either or both posedges occur.
   */
  always @(posedge clk) detect <= detect + signal_posedge + reference_posedge;

  /* For simulation
   */
  initial detect <= 0;

endmodule

The key concept is that FPGAs are highly optimized for synchronous logic, and you constantly need to keep in mind which "clock domain" each signal is associated with — or whether a signal is asynchronous altogether. If you want to combine signals from multiple clock domains, you need to pick one and bring the other signals into it via suitable mechanisms, such as synchronizers or FIFOs.

\$\endgroup\$
5
  • \$\begingroup\$ Dave, again thanks for answer, I know that the functionality of the propose circuit is wear, I am just trying to understand how FPGA works. Your answer is really nice and complete, and I really gon new and interesting information from that, but, before close, lets me get a bit more. I underestar that FPGA is optimized for synchronous logic, and the importance of clock domain, but I still thinking that the circuit propose in the image can be syntthetize some how. \$\endgroup\$
    – Carlos J.
    Commented Aug 23, 2020 at 13:09
  • \$\begingroup\$ @CarlosJ.The only way to do what you suggest is to make an explicit or of the clocks and use that as a trigger in a module with a single clock input (clk_combined = clk | clk_1khz;). Just to check, in Dave's solution (much the better approach), so you want detect to increment +2 if both the signal and reference go high simultaneously? If not, should be an OR. \$\endgroup\$
    – awjlogan
    Commented Aug 23, 2020 at 15:10
  • \$\begingroup\$ See what The Photon said in a comment on your question. You can't simply OR the clocks together and get the behavior that your Verilog code is attempting to describe. \$\endgroup\$
    – Dave Tweed
    Commented Aug 23, 2020 at 15:35
  • \$\begingroup\$ And also to be clear, do not combine the clocks in an OR ever! Your timing analysis will go bonkers, and in an FPGA, it's unlikely to even work as the flop clock inputs are probably hardwired to set routings. \$\endgroup\$
    – awjlogan
    Commented Aug 23, 2020 at 16:01
  • \$\begingroup\$ Thanks a lot to all! I understood! \$\endgroup\$
    – Carlos J.
    Commented Aug 24, 2020 at 12:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.