1

在 ModelSim 中运行这段 Verilog 代码时遇到问题。我已经建立了一个应该计算毫秒的电路。电路(模块分子)由两部分组成:一个接收5MHz频率时钟信号的电路(模块计数器),每经过5000cct(相当于1ms)产生一个高逻辑,因此每毫秒产生输出高),另一个电路接收相同的时钟信号并计算经过的毫秒数(模块预设)。此外,第二个电路接收负载信号(当激活时,负载产生低逻辑)。我的问题是为什么电路的输出在每毫秒过去后增加两次(而且不仅仅是一次,正如预期的那样)。我发布了 Verilog 源代码和图表(图表)。

`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
4

1 回答 1

1

我相信这是由触发器(clk)和闩锁(en/st_nxt)之间的竞争引起的。我确实在计数器模块中观察到它。

-- vcs 倾向于在时钟边沿之前评估“en”,因此将“1”(st + 1)分配给 st_nxt。

-- questa 以不同的顺序进行。结果,在第一次“en”更改后,“st”的值被移动了“1”。

分子中也会发生类似的事情。那里的闩锁动作更加复杂。此外,由于比赛“出局”计数器的信号有故障。vcs 和 questa 中的 'st' 4999 都有一个故障。因此,分子中的锁存器会“意外”地改变这个故障的状态。

避免这种情况的方法是使用纯基于触发器的逻辑,不要使用锁存器。或者至少不要以这种方式将它们与触发器混合。

我试图重新编写您的模型以摆脱闩锁。这样,它似乎工作得更好:

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
于 2020-11-20T20:08:10.320 回答