1

I have a problem when running this piece of Verilog code in ModelSim. I have built a circuit that is supposed to count the milliseconds. The circuit(module numarator) consists of two blocks: a circuit which receives a 5MHz frequency clock signal(module counter), and is supposed to produce a high-logic every 5000cct passed(the equivalent of 1ms, thus producing output high after every millisecond), and another circuit which receives the same clock signal and counts the number of elapsed milliseconds(module preset). Besides, the second circuit receives a load signal(when active, the load produces a low-logic). My question is why the output of the circuit is incremented twice after each millisecond elapsed(and not only once, as expected). I posted the Verilog source code and the diagram ( diagram ).

`timescale 1ns/1ns
//1ms pulse generator
module counter(
    input clk,rst,en,
    output reg out
);

reg [12:0] st,st_nxt;

always @(posedge clk) begin
    if(rst) st <= 13'd0;//requires rst
    else st <= st_nxt;//for initialization
end

always @ * begin
    out = 1'b0;
    if(en) begin
      st_nxt = st + 1;
      if(st == 13'd4999) begin
          st_nxt = 13'd0;
          out = 1'b1;
      end
    end
end

endmodule
//tb for the first circuit
module counter_tb(
    output reg clk,rst,en,
    output out
);

counter cut(.clk(clk),.rst(rst),.en(en),.out(out));

initial en = 1'd1;

initial begin
    rst = 1'd1;
    #50 rst = 1'd0;
end

initial begin
    clk = 1'd1;
    forever
    #100 clk = ~clk;
end

endmodule
//preset counter
module preset(
    input clk,rst,en,ld,
    output reg [12:0] out
);

reg [12:0] st,st_nxt;

always @(posedge clk) begin
    if(rst) st <= 13'd0;//requires rst
    else st <= st_nxt;//for initialization
end

always @ * begin
    if(ld) st_nxt = 13'd0;//the circuit is designed
    else if(en) st_nxt = st + 1;//to load only 0
    out = st;
end

endmodule
//tb preset counter
module preset_tb(
    output reg clk,rst,en,ld,
    output [12:0]out 
);

preset cut(.clk(clk),.rst(rst),.en(en),.ld(ld),.out(out));

initial begin
    rst = 1'd1;
    #50 rst = 1'd0;
end

initial begin
    clk = 1'd1;
    forever
    #100 clk = ~clk;
end

initial begin
    en = 1'd1;
    #1000 en = 1'd0;
    #200 en = 1'd1;
end

initial begin
    ld = 1'd0;
    #2000 ld = 1'd1;
    #400 ld = 1'd0;
end

endmodule
//ms couonter
module numarator(
    input clk,rst,en,ld,
    output [12:0] out
);

wire f;

counter i0(.clk(clk),.rst(rst),.en(en),.out(f));
preset i1(.clk(clk),.rst(rst),.en(f),.ld(ld),.out(out));

endmodule
//tb ms counter
module numarator_tb(
    output reg clk,rst,en,ld,
    output [12:0] out
);

numarator cut(.clk(clk),.rst(rst),.en(en),.ld(ld),.out(out));

initial begin
    rst = 1'd1;
    #50 rst = 1'd0;
end

initial begin
    clk = 1'd1;
    forever
    #100 clk = ~clk;
end

initial begin
    en = 1'd1;
    #2000000 en = 1'd0;
    #1000000 en = 1'd1;
end

initial begin
    ld = 1'd0;
    #4000000 ld = 1'd1;
    #1000000 ld = 1'd0;
end

endmodule
pauk
  • 350
  • 4
  • 15
  • I got a different behavior using another simulator. I guess it might be caused by the incomplete `if`-`else` chain you used in driving `st_nxt`. – Light Nov 20 '20 at 10:45
  • I tested the first two modules (the pulse generator and the preset counter) and I found that they were behaving as expected. The issue occurred when I tried to test the last module, , which behaves abnormally. – pauk Nov 20 '20 at 11:50
  • i do not see this behavior either. Nor can I find any source of races visually. Which tool did you use for testing? – Serge Nov 20 '20 at 12:09
  • @Serge OP is using modelsim. I can reproduce this behavior using modelsim 10.1d. But I don't get this in vcs 2016. – Light Nov 20 '20 at 12:17
  • I use ModelSim Altera starter edition 6.5b. – pauk Nov 20 '20 at 12:47
  • Could you tell me what simulator are you using, please? Or, could you post a capture of the simulation? – pauk Nov 20 '20 at 12:53
  • yeah, there are discrepancies between different simulators. So, it is a race or a glitch somewhere. – Serge Nov 20 '20 at 14:05

1 Answers1

1

I believe that this is caused by the race between flop (clk) and a latch(en/st_nxt). I do observe it in the counter module.

-- vcs tends to evaluate 'en' before the clock edge and as a result assigns '1' (st + 1) to the st_nxt.

-- questa does it in a different order. As a result after first 'en' change the values of the 'st' become shifted by '1'.

Something similar happens in numerator. The latch action there is even more complicated. Also, due to the races 'out' signal of the counter is glitchy. There is a glitch at 'st' 4999 in both, vcs and questa. So, the latch in the numerator will change the state at this glitch 'unexpectedly'.

The way to avoid this situation is to use pure flop-based logic, do not use latches. Or at least do not mix them with flops this way.

I tried to re-write your model to get rid of latches. This way and it seems to work better:

module counter(
           input      clk,rst,en,
           output reg out
           );
   reg [12:0]         st;

   always @(posedge clk) begin
     if(rst) begin
        st <= 13'd0;//requires rst
        out <= 0;
     end
     else if (en) begin
        if (st == 13'd4999) begin
            st <= 13'd0;
            out <= 1'b1;
        end
        else
           st <= st + 1;     
      end
   end
endmodule // counter

//preset counter
module preset(
          input         clk,rst,en,ld,
          output reg [12:0] out
          );

   reg [12:0]           st;

   always @(posedge clk) begin
      if(rst)
        st <= 13'd0;//requires rst
      else if (ld)
        st = 13'd0;
      else if (en)  
        st <= st + 1;//for initialization
   end

   always @ * begin
      out = st;
   end

endmodule // preset
Serge
  • 11,616
  • 3
  • 18
  • 28