Verilog 在IO引脚和BUFG之间布线时放置30-574不良位置 `时间刻度为1ns/1ps 模块秒表( 输入时钟, 输入复位, 投入增量, 输入启动, 输出[6:0]分段, 输出dp, 输出[3:0]an ); reg[3:0]reg_d0、reg_d1、reg_d2、reg_d3//保存单个计数的寄存器 注册[22:0]股票代码; 线击; //mod 1kHz时钟以每0.001秒产生一次滴答声 始终@(posedge(时钟)或posedge(重置)) 开始 如果(重置) 开始 ticker

Verilog 在IO引脚和BUFG之间布线时放置30-574不良位置 `时间刻度为1ns/1ps 模块秒表( 输入时钟, 输入复位, 投入增量, 输入启动, 输出[6:0]分段, 输出dp, 输出[3:0]an ); reg[3:0]reg_d0、reg_d1、reg_d2、reg_d3//保存单个计数的寄存器 注册[22:0]股票代码; 线击; //mod 1kHz时钟以每0.001秒产生一次滴答声 始终@(posedge(时钟)或posedge(重置)) 开始 如果(重置) 开始 ticker,verilog,Verilog,我认为问题与代码的这一部分有关: `timescale 1ns / 1ps module stopwatch( input clock, input reset, input increment, input start, output [6:0] seg, output dp, output [3:0] an ); reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //regis

我认为问题与代码的这一部分有关:

`timescale 1ns / 1ps    
module stopwatch(
    input clock,
    input reset,
    input increment,
    input start,
    output [6:0] seg,
    output dp,
    output [3:0] an
    );

    reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //registers that will hold the individual counts
    reg [22:0] ticker;
    wire click;


    //the mod 1kHz clock to generate a tick ever 0.001 second

    always @ (posedge (clock) or posedge (reset))
    begin
        if(reset)
        begin
            ticker <= 0;
        end
        else 
        begin
            if (start)
            begin
                if(ticker == (100000 - 1)) //if it reaches the desired max value reset it
                    ticker <= 0;
                else if (increment)
                    ticker <= ticker;
                else
                    ticker <= ticker + 1;
            end 
        end
    end

    //increment a second everytime rising edge of down button
    reg [3:0] inc_temp;
    always @ (posedge (increment)) 
    begin
        if (reg_d3 == 9)
            inc_temp = 0;
        else
            inc_temp = reg_d3 + 1;
    end

    assign click = ((ticker == (100000 - 1))?1'b1:1'b0); //click to be assigned high every 0.001 second

    //update data start from here
    always @ (posedge (clock) or posedge (reset))
    begin
        if(reset)
        begin
            reg_d0 <= 0;
            reg_d1 <= 0;
            reg_d2 <= 0;
            reg_d3 <= 0;
        end

        else
        begin
            if (increment)
                begin
                    reg_d3 <= inc_temp;
                    reg_d0 <= reg_d0;
                    reg_d1 <= reg_d1;
                    reg_d2 <= reg_d2;    
                end
                else if (click) //increment at every click
                begin
                    if(reg_d0 == 9) //xxx9 - 1th milisecond
                    begin
                        reg_d0 <= 0;
                        if (reg_d1 == 9) //xx99 - 10th milisecond
                        begin
                            reg_d1 <= 0;
                            if (reg_d2 == 9) //x999 - 100th milisecond
                            begin
                                reg_d2 <= 0;
                                if(reg_d3 == 9) //9999 - The second digit
                                    reg_d3 <= 0;
                                else
                                    reg_d3 <= reg_d3 + 1;
                            end
                            else
                                reg_d2 <= reg_d2 + 1;
                        end

                        else
                            reg_d1 <= reg_d1 + 1;
                    end

                    else
                        reg_d0 <= reg_d0 + 1;
                end
                else
                begin
                    reg_d3 <= reg_d3;
                    reg_d0 <= reg_d0;
                    reg_d1 <= reg_d1;
                    reg_d2 <= reg_d2;
                end
        end

    end



    //Mux for display 4 7segs LEDs
    localparam N = 18; 
    reg [N-1:0]count;
    always @ (posedge clock or posedge reset)
    begin
        if (reset)
            count <= 0;
        else
            count <= count + 1;
    end

    reg [6:0]sseg;
    reg [3:0]an_temp;
    reg reg_dp;
    always @ (*)
        begin
            case(count[N-1:N-2])
                2'b00 :
                begin
                    sseg = reg_d0;
                    an_temp = 4'b1110;
                    reg_dp = 1'b1;
                end

                2'b01:
                begin
                    sseg = reg_d1;
                    an_temp = 4'b1101;
                    reg_dp = 1'b0;
                end

                2'b10:
                begin
                    sseg = reg_d2;
                    an_temp = 4'b1011;
                    reg_dp = 1'b1;
                end

                2'b11:
                begin
                    sseg = reg_d3;
                    an_temp = 4'b0111;
                    reg_dp = 1'b0;
                end
            endcase
        end
    assign an = an_temp;

    //update the data to display to LEDs
    reg [6:0] sseg_temp;
    always @ (*)
    begin
        case(sseg)
            4'd0 : sseg_temp = 7'b1000000;
            4'd1 : sseg_temp = 7'b1111001;
            4'd2 : sseg_temp = 7'b0100100;
            4'd3 : sseg_temp = 7'b0110000;
            4'd4 : sseg_temp = 7'b0011001;
            4'd5 : sseg_temp = 7'b0010010;
            4'd6 : sseg_temp = 7'b0000010;
            4'd7 : sseg_temp = 7'b1111000;
            4'd8 : sseg_temp = 7'b0000000;
            4'd9 : sseg_temp = 7'b0010000;
            default : sseg_temp = 7'b0111111; //dash
        endcase
    end
    assign seg = sseg_temp;
    assign dp = reg_dp;
endmodule
基本上,您使用的是一个输入信号作为时钟,在为FPGA设计时,这是完全不鼓励的。P&R尝试将
IO
引脚重新路由到FPGA内部的
BUFG
(全局缓冲区),以便将其用作时钟

对于FPGA设计,您应该为所有
always@(posedge…
构造使用一个时钟信号,并使用输入信号有条件地加载/更新寄存器

为此,您必须首先将
增量
信号与
时钟
同步,以避免亚稳态问题:

always @ (posedge (increment)) 
    begin
        if (reg_d3 == 9)
            inc_temp = 0;
        else
            inc_temp = reg_d3 + 1;
    end
为了检测有效的上升沿,我们存储了
increment\u synched
的最后16个值的历史记录。当产生从0到1的有效稳定变化时,历史模式将匹配模式
0011111111
。然后,也只有在那时,我们通过将
incr\u detected
提高到1来发出信号。在下一个时钟周期,历史模式将与上述序列不匹配,并且检测到的增量将再次降至0

在此之前,连接到的按钮
increment
中的多次反弹将导致许多转换,从而导致许多增量。使用这样的模式匹配可以消除由多次反弹引起的故障。使用1Khz时钟,这种模式应该足够了

现在,您可以在原始代码中使用
incr\u detected
incr\u detected
将在一个
clk
周期内为1

reg [15:0] incrhistory = 16'h0000;
reg incr_detected = 1'b0;
always @(posedge clk) begin
  incrhistory <= { incrhistory[14:0] , increment_synched };
  if (incrhistory == 16'b0011111111111111)
    incr_detected <= 1'b1;
  else
    incr_detected <= 1'b0;
end
可以使用以下模拟来测试这些添加:

您将看到有一个模块,它从外部接收
增量
输入信号,并在输入信号从低电平最终转换为高电平时生成一个无故障的单周期脉冲

事实上,我已经写了两个版本。第二种方法试图模仿单稳态的行为,因此在检测到第一次从低到高的转变后的特定时间段内不会对输入进行采样

您将看到,第二个版本比第一个版本产生脉冲快得多,但它也容易将小故障视为有效的上升沿,如模拟中所示。我会坚持第一个版本

reg [15:0] incrhistory = 16'h0000;
reg incr_detected = 1'b0;
always @(posedge clk) begin
  incrhistory <= { incrhistory[14:0] , increment_synched };
  if (incrhistory == 16'b0011111111111111)
    incr_detected <= 1'b1;
  else
    incr_detected <= 1'b0;
end
always @ (posedge clk) begin
  if (incr_detected) begin
    if (reg_d3 == 9)
      inc_temp = 0;
    else
      inc_temp = reg_d3 + 1;
  end
end