veriloginfinite-loopprogram-countericarus

Infinite loop when simulating a Program Counter design with Icarus Verilog


I am implementing a simple Program Counter adder with the following prototype:

module program_counter(input        enable_count,
                       input        enable_overwrite,
                       input[31:0]  overwrite_value,
                       output[31:0] out);

When simulating with Icarus Verilog, I get an infinite loop at the first tick on which overwriting is disabled and count is enabled, the internal register being therefore feeded by the output of the PC adder (PC + 4).

I simplified the issue to a basic piece of code with a D flip flop used as a 1-bit register:

module register(input in, input set, output out);

    wire not_in;
    wire q0;
    wire not_q0;
    wire not_q;

    nand (q0, in, set);

    not  (not_in, in);
    nand (not_q0, not_in, set);

    nand (out, q0, not_q);
    nand (not_q, not_q0, out);

endmodule

module test;

    reg  clock;
    reg  in;
    wire out;
    wire not_out;

    xor (x_out, out, 1);                // add
    or  (muxed_out, x_out, in);         // mux

    register r(muxed_out, clock, out);

    initial
    begin
        $dumpfile("test.vcd");
        $dumpvars(0, test);

        $display("\tclock,\tin,\tout");
        $monitor("\t%b,\t%x,\t%b",
                 clock, in, out);

        #0 assign in = 1;               // erase register
        #0 assign clock = 1;

        #1 assign in = 0;
        #1 assign clock = 0;

        #2 assign clock = 1;
        #3 assign clock = 0;
        #4 assign clock = 1;
    end

endmodule

The VCD output does not show any state change after the simulation gets stuck.

My guess is that, at a particular tick, the adder is constantly feeding a different value (continuously adding), so as it is not stable, the simulator is waiting the value to be fixed and gets stuck.

Is this design correct (i.e. can be synthesized and supposed to work) ?


Solution

  • There's a combinational loop: The output of 'register' feeds back into its input through the xor/or gates in test. You've essentially created a ring oscillator.

    If you add the following code inside register, you can see this happening:

      always @(in) $display("@%d: in = %d", $time, in);
    

    You'll see a bunch of these when you run the interpreter:

    @                   1: in = 1
    @                   1: in = 0
    @                   1: in = 1
    @                   1: in = 0
    

    It looks like you're trying to make an enabled latch in 'register'. Is that what you intended? An edge triggered flip flop is the normal practice in synchronous design. You'd need two latches back-to-back to do that, but the standard (and much easier) way to do this in Verilog is like this:

    reg my_flop;
    
    always @(posedge clk)
       my_flop <= input;
    

    If you really want a latch, it can be inferred like this (but these tend to be error prone and are generally discouraged):

    always @(clk, input)
    begin
        if (clk)
            my_flop = input;
    end
    

    Is there a reason you're trying to create these manually with gates?