verilogdigitaldigital-design

Register increments twice within a non blocking always


I want to do an up-counter which has an output enable (when high the up-counter is supposed to count up at each clock cycle, otherwise it keeps its previous value). In order to achieve visible results on my Altera TerASIC board I used its on-board clock generator and I built in Verilog a clock divider module in order to feed my up-counter with a clock which has a much more suitable frequency. In addition, I created a hex module which I connected to my up-counters output in order to be able to see the output values as digits. The problem is that I don't know why the output is incremented by 2 every clock cycle (instead of 1, as expected) when running the design on the TeraASIC board. I provide the entire code below since idk where does the issue stem from. Although, I believe that the hex module is totally fine. The problem occurs either within the counter block or within the divider block. In addition, I made a little testbench whose results are peculiar since they confirm that the circuit works fine. I detailed at the bottom of this post about the testbench. Nevertheless, it is interesting that if I replace the else if from the counter with a simple else which does not take into consideration the en and d signals I get a completely functional design, a simple up-counter which increments its value after each clock edge. I don't know why is this happening. Perhaps the real problem is hidden there. I put a comment in that code region in order to be more visible.

module counter(
    input clk,
    input rst_b,
    input en,
    input [2:0] d,
    output [6:0] digit
);

wire clk_d;
reg [2:0] q;

divider i0(.clk(clk),.rst_b(rst_b),.clk_d(clk_d));
decoder i1(.binary(q),.digit(digit));

always @(posedge clk_d, negedge rst_b) begin
    if(rst_b == 1'b0)
        q <= 3'b000;
    else if(en)//when it was only else q<=q+en; it went fine...why???
        if(q == d)
            q <= 3'b000;
        else
            q <= q + en;//increment by 2 instead of 1
end

endmodule


module divider(
    input clk,
    input rst_b,
    output clk_d
);

reg [24:0] q;

always @(posedge clk) begin
    if(rst_b == 1'b0)
        q <= 25'b0;
    else
        q <= q-1;
end

assign clk_d = (q == 25'b0);

endmodule


module decoder(
    input [2:0] binary,
    output reg [6:0] digit
);

always @ * begin
    case (binary)
        4'h0: digit = ~7'b0111111;
        4'h1: digit = ~7'b0000110;
        4'h2: digit = ~7'b1011011;
        4'h3: digit = ~7'b1001111;
        4'h4: digit = ~7'b1100110;
        4'h5: digit = ~7'b1101101;
        4'h6: digit = ~7'b1111101;
        4'h7: digit = ~7'b0000111;
        default : digit = ~7'b1110001;
    endcase
end

endmodule

I got a little testbench which astonishingly proofs that at least in theory my module works fine:

module counter_tb;

reg clk, rst_b, en;
reg [2:0] d;
wire [6:0] digit;

counter i0( .clk(clk),
            .rst_b(rst_b),
            .en(en),
            .d(d),
            .digit(digit)
);

always begin
    #1 clk = ~clk;
end

initial begin
    clk = 1'b0;
    en = 1'b1;
    d = 3'b111;
    rst_b = 1'b0;
    #3 rst_b = 1'b1;
end
    
endmodule

Solution

  • I don't know exactly what your issue is or what the fix is, however you are using a design practice that is generally not going to work in synthesis flow (targeting hardware) for creating a clock. If it works one build it may not work the next. A little bit of extra delay (like adding an enable) will produce completely different results in hardware.

    This practice is deceiving, because you can write something that behaves as you want it to in simulation, but does not behave as expected in the synthesis/hardware workflow. The Verilog simulator generally does not model delays (delay based simulation is possible, but still does not solve the problems), so certain good design practices must be used to make hardware results agree with simulation.

    You generally can not create clocks and use them as clocks for other flip flops using simple flip flop dividers in a physical FPGA. There are two reliable options for obtaining the behavior associated with generating a slower clock.

    1. Create slow clock enables using a counter as a divider, then use them as enables.
    2. Use the parts built in MMCM/PLL clock divider IP blocks to create a slower clock.

    This link explains more and is nicely written, I could not explain it much better
    Clock Dividers using Flip-Flops in RTL on FPGAs – a Big NO!
    without writing a paper.

    This would be a separate and new question & answer
    "How do I create a clock divider in FPGA which can target hardware in synthesis workflows"

    I would get rid if the flip flop divider assign clk_d = (q == 25'b0); and its associated logic and use one of the two solutions I mentioned and are mentioned at the provided link.


    Also, if you deploy RTL code to the lab without simulating with a testbench, then you will often be looking a a black box saying 'it doesn't work'