Place 30-574 IO 引脚和 BUFG 之间的路由放置不当
Place 30-574 Poor placement for routing between an IO pin and BUFG
`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
我正在尝试设计一个秒表,但我被增量问题困住了。目的是当我按下 increment
(一个按钮)时,reg_d3
将递增 1 并保持其状态直到按钮被释放。我可以在按下按钮时让时钟停止,但我无法更新 reg_d3
。我总是收到
[Place 30-574] Poor placement for routing between an IO pin and BUFG
我不知道为什么;我在刚刚找到的clkdivider中使用增量。
我认为问题与您的这部分代码有关:
always @ (posedge (increment))
begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
您基本上是将输入信号用作时钟,在为 FPGA 设计时完全不鼓励这样做。 P&R 尝试将 IO
引脚重新路由到 FPGA 内部的 BUFG
(全局缓冲区),以便它可以用作时钟。
对于 FPGA 设计,您应该为所有 always @(posedge...)
构造使用一个时钟信号,并使用输入信号有条件地 load/update 寄存器。
为此,您必须首先将 increment
信号与 clk
同步,从而避免亚稳态问题:
reg incr1=1'b0, incr2=1'b0;
always @(posedge clk) begin
incr1 <= increment;
incr2 <= incr1;
end
wire increment_synched = incr2;
然后,deglitch increment_synched
并检测其中的上升沿:
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
为了检测有效的上升沿,我们存储了 increment_synched
的最后 16 个值的历史记录。当产生从 0 到 1 的有效稳定变化时,历史模式将匹配模式 0011111111111111
。然后,只有在那时,我们通过将 incr_detected
提高到 1 来发出信号。下一个时钟周期,历史模式将与上述序列不匹配,并且 incr_detected
将再次下降到 0。
在此之前,连接到 increment
的按钮中的多次弹跳会导致许多转换,从而导致许多增量。使用这样的模式匹配可以消除由多次反弹引起的故障。使用您似乎使用的 1Khz 时钟,这种模式应该足够了。
现在您可以在原始代码中使用 incr_detected
,对于单个 clk
循环,incr_detected
将为 1。
always @ (posedge clk) begin
if (incr_detected) begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
end
您可以使用以下模拟来测试这些添加:
http://www.edaplayground.com/x/AQY
您将看到有一个模块从外部获取您的 increment
输入信号,并在输入信号最终从低电平转换为高电平时生成无毛刺单周期脉冲.
其实我写了两个版本。第二个尝试模仿单稳态的行为,因此在检测到第一个低到高转换后的特定时间段内不会对输入进行采样。
您会看到第二个版本比第一个版本更快地产生脉冲,但它也很容易将毛刺作为有效上升沿,如模拟所示。我会坚持使用第一个版本。
`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
我正在尝试设计一个秒表,但我被增量问题困住了。目的是当我按下 increment
(一个按钮)时,reg_d3
将递增 1 并保持其状态直到按钮被释放。我可以在按下按钮时让时钟停止,但我无法更新 reg_d3
。我总是收到
[Place 30-574] Poor placement for routing between an IO pin and BUFG
我不知道为什么;我在刚刚找到的clkdivider中使用增量。
我认为问题与您的这部分代码有关:
always @ (posedge (increment))
begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
您基本上是将输入信号用作时钟,在为 FPGA 设计时完全不鼓励这样做。 P&R 尝试将 IO
引脚重新路由到 FPGA 内部的 BUFG
(全局缓冲区),以便它可以用作时钟。
对于 FPGA 设计,您应该为所有 always @(posedge...)
构造使用一个时钟信号,并使用输入信号有条件地 load/update 寄存器。
为此,您必须首先将 increment
信号与 clk
同步,从而避免亚稳态问题:
reg incr1=1'b0, incr2=1'b0;
always @(posedge clk) begin
incr1 <= increment;
incr2 <= incr1;
end
wire increment_synched = incr2;
然后,deglitch increment_synched
并检测其中的上升沿:
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
为了检测有效的上升沿,我们存储了 increment_synched
的最后 16 个值的历史记录。当产生从 0 到 1 的有效稳定变化时,历史模式将匹配模式 0011111111111111
。然后,只有在那时,我们通过将 incr_detected
提高到 1 来发出信号。下一个时钟周期,历史模式将与上述序列不匹配,并且 incr_detected
将再次下降到 0。
在此之前,连接到 increment
的按钮中的多次弹跳会导致许多转换,从而导致许多增量。使用这样的模式匹配可以消除由多次反弹引起的故障。使用您似乎使用的 1Khz 时钟,这种模式应该足够了。
现在您可以在原始代码中使用 incr_detected
,对于单个 clk
循环,incr_detected
将为 1。
always @ (posedge clk) begin
if (incr_detected) begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
end
您可以使用以下模拟来测试这些添加: http://www.edaplayground.com/x/AQY
您将看到有一个模块从外部获取您的 increment
输入信号,并在输入信号最终从低电平转换为高电平时生成无毛刺单周期脉冲.
其实我写了两个版本。第二个尝试模仿单稳态的行为,因此在检测到第一个低到高转换后的特定时间段内不会对输入进行采样。
您会看到第二个版本比第一个版本更快地产生脉冲,但它也很容易将毛刺作为有效上升沿,如模拟所示。我会坚持使用第一个版本。