reg 的多个冲突驱动程序仅在一个 always 块中分配
Multiple conflicting drivers for reg assigned in only one always block
作为一个学习项目,我正在使用 Verilog 开发一个简单的视频信号时序模块。我从早期的研究中了解到,每个 reg
应该只从一个 always
块分配,所以我将我的系统安排成两个状态机块,然后是一个用于填充输出寄存器的块,如下所示:
module video_timing
(
input wire reset,
input wire clk,
output reg [15:0] x,
output reg [15:0] y,
output reg hsync,
output reg vsync,
output reg visible
);
// State constants for our two timing state machines (one horizontal, one vertical)
`define VIDEO_SYNC 2'd0
`define VIDEO_BACKPORCH 2'd1
`define VIDEO_ACTIVE 2'd2
`define VIDEO_FRONTPORCH 2'd3
// These settings are for 720p, assuming clk is running at 74.25 MHz
`define VIDEO_H_SYNC_PIXELS 16'd40
`define VIDEO_H_BP_PIXELS 16'd220
`define VIDEO_H_ACTIVE_PIXELS 16'd1280
`define VIDEO_H_FP_PIXELS 16'd110
`define VIDEO_H_SYNC_ACTIVE 1'b1
`define VIDEO_V_SYNC_LINES 16'd5
`define VIDEO_V_BP_LINES 16'd20
`define VIDEO_V_ACTIVE_LINES 16'd720
`define VIDEO_V_FP_LINES 16'd5
`define VIDEO_V_SYNC_ACTIVE 1'b1
reg [1:0] state_h;
reg [15:0] count_h; // 1-based so we will stop when count_h is the total pixels for the current state
reg inc_v = 1'b0;
reg [1:0] state_v;
reg [15:0] count_v; // 1-based so we will stop when count_v is the total lines for the current state
// Change outputs on clock.
// (These update one clock step behind everything else below, but that's
// okay because the lengths of all the periods are still correct.)
always @(posedge clk) begin
if (reset == 1'b1) begin
hsync <= ~`VIDEO_H_SYNC_ACTIVE;
vsync <= ~`VIDEO_V_SYNC_ACTIVE;
visible <= 1'b0;
x <= 16'd0;
y <= 16'd0;
end else begin
hsync <= (state_h == `VIDEO_SYNC) ^ (~`VIDEO_H_SYNC_ACTIVE);
vsync <= (state_v == `VIDEO_SYNC) ^ (~`VIDEO_V_SYNC_ACTIVE);
visible <= (state_h == `VIDEO_ACTIVE) && (state_v == `VIDEO_ACTIVE);
x <= count_h - 1;
y <= count_v - 1;
end
end
// Horizontal state machine
always @(posedge clk) begin
if (reset == 1'b1) begin
count_h <= 16'b1;
state_h <= `VIDEO_FRONTPORCH;
end else begin
inc_v <= 0;
count_h <= count_h + 16'd1;
case (state_h)
`VIDEO_SYNC: begin
if (count_h == `VIDEO_H_SYNC_PIXELS) begin
state_h <= `VIDEO_BACKPORCH;
count_h <= 16'b1;
end
end
`VIDEO_BACKPORCH: begin
if (count_h == `VIDEO_H_BP_PIXELS) begin
state_h <= `VIDEO_ACTIVE;
count_h <= 16'b1;
end
end
`VIDEO_ACTIVE: begin
if (count_h == `VIDEO_H_ACTIVE_PIXELS) begin
state_h <= `VIDEO_FRONTPORCH;
count_h <= 16'b1;
end
end
`VIDEO_FRONTPORCH: begin
if (count_h == `VIDEO_H_FP_PIXELS) begin
state_h <= `VIDEO_SYNC;
count_h <= 16'b1;
inc_v <= 1;
end
end
endcase
end
end
// Vertical state machine
always @(posedge clk) begin
if (reset == 1'b1) begin
count_v <= 16'b1;
state_v <= `VIDEO_FRONTPORCH;
end else begin
if (inc_v) begin
count_v <= count_v + 16'd1;
case (state_v)
`VIDEO_SYNC: begin
if (count_v == `VIDEO_V_SYNC_LINES) begin
state_v <= `VIDEO_BACKPORCH;
count_v <= 16'b1;
end
end
`VIDEO_BACKPORCH: begin
if (count_v == `VIDEO_V_BP_LINES) begin
state_v <= `VIDEO_ACTIVE;
count_v <= 16'b1;
end
end
`VIDEO_ACTIVE: begin
if (count_v == `VIDEO_V_ACTIVE_LINES) begin
state_v <= `VIDEO_FRONTPORCH;
count_v <= 16'b1;
end
end
`VIDEO_FRONTPORCH: begin
if (count_v == `VIDEO_V_FP_LINES) begin
state_v <= `VIDEO_SYNC;
count_v <= 16'b1;
end
end
endcase
end
end
end
endmodule
当尝试使用 IceStorm 工具链对此进行综合时,yosys
警告说 hsync
有多个驱动程序:
Warning: multiple conflicting drivers for top.\timing.hsync:
port Q[0] of cell $techmap\timing.$procdff9 ($adff)
port Q[0] of cell $techmap\timing.$procdff0 ($adff)
nextpnr-ice40
随后在同一问题上失败:
ERROR: multiple drivers on net 'P1B4' ($auto$simplemap.cc:496:simplemap_adff5.Q and $auto$simplemap.cc:496:simplemap_adff6.Q)
ERROR: Loading design failed.
我尝试了几种不同的排列来尝试解决这个问题,并做了一些观察:
- 如果我将
case (reset)
0:
块中的赋值(总是在第一个)更改为 hsync <= 'VIDEO_H_SYNC_ACTIVE
那么结果是可综合的,并且确实断言 hsync
在进行更改后没有像我预期的那样重置时不断。
- 如果我完全删除
hsync <= (state_h == 'VIDEO_SYNC) ^ (~'VIDEO_H_SYNC_ACTIVE)
行但在重置期间保留 hsync <= ~'VIDEO_H_SYNC_ACTIVE
则结果也是可合成的,并且 hsync
始终未断言。
(我在上面用 '
替换了反引号,因为反引号是内联逐字文本的 Markdown 元字符。我在实际程序中使用反引号作为常量。)
这让我得出结论,hsync <=
右侧的表达式就是问题所在。但是我很困惑为什么非常相似的 vsync <=
行不会产生类似的错误:
hsync <= (state_h == `VIDEO_SYNC) ^ (~`VIDEO_H_SYNC_ACTIVE);
vsync <= (state_v == `VIDEO_SYNC) ^ (~`VIDEO_V_SYNC_ACTIVE);
该模块在 iverilog
.
模拟下的表现与我预期的一样
我正在使用 Yosys 0.8 和从 git sha1 a6a4349 构建的 nextpnr。我也尝试升级到 Yosys 0.9 并得到相同的结果,但我怀疑是我的错,而不是在工具链中。
IEEE 综合标准 (1364.1) 不允许这种异步复位模式。因此只能使用 if
语句:
此处的其他答案是重要的垫脚石:
- 我的重置实现最初是异步的,并且是以不符合 Verilog 综合标准的方式编写的。
- 我的条件重置逻辑是使用
switch
而不是 if
编写的(由于我在其他地方看到的一些令人困惑的建议)。
不幸的是,这条路在那儿变干了,因为在那之后 timing.v
合成得很好。原来问题其实出在top.v
而不是:
video_timing timing(
.reset(reset_loc),
.clk(vga_ck),
.hsync(vga_hs),
.vsync(vga_hs),
.visible(vga_de)
);
我不小心将 vga_hs
分配给了 hsync
和 vsync
。 ♂️
将 vsync
行更改为引用 vga_vs
后,设计现在可以按预期进行综合和运行。
经验教训:问题并不总是出在编译器认为的地方!
作为一个学习项目,我正在使用 Verilog 开发一个简单的视频信号时序模块。我从早期的研究中了解到,每个 reg
应该只从一个 always
块分配,所以我将我的系统安排成两个状态机块,然后是一个用于填充输出寄存器的块,如下所示:
module video_timing
(
input wire reset,
input wire clk,
output reg [15:0] x,
output reg [15:0] y,
output reg hsync,
output reg vsync,
output reg visible
);
// State constants for our two timing state machines (one horizontal, one vertical)
`define VIDEO_SYNC 2'd0
`define VIDEO_BACKPORCH 2'd1
`define VIDEO_ACTIVE 2'd2
`define VIDEO_FRONTPORCH 2'd3
// These settings are for 720p, assuming clk is running at 74.25 MHz
`define VIDEO_H_SYNC_PIXELS 16'd40
`define VIDEO_H_BP_PIXELS 16'd220
`define VIDEO_H_ACTIVE_PIXELS 16'd1280
`define VIDEO_H_FP_PIXELS 16'd110
`define VIDEO_H_SYNC_ACTIVE 1'b1
`define VIDEO_V_SYNC_LINES 16'd5
`define VIDEO_V_BP_LINES 16'd20
`define VIDEO_V_ACTIVE_LINES 16'd720
`define VIDEO_V_FP_LINES 16'd5
`define VIDEO_V_SYNC_ACTIVE 1'b1
reg [1:0] state_h;
reg [15:0] count_h; // 1-based so we will stop when count_h is the total pixels for the current state
reg inc_v = 1'b0;
reg [1:0] state_v;
reg [15:0] count_v; // 1-based so we will stop when count_v is the total lines for the current state
// Change outputs on clock.
// (These update one clock step behind everything else below, but that's
// okay because the lengths of all the periods are still correct.)
always @(posedge clk) begin
if (reset == 1'b1) begin
hsync <= ~`VIDEO_H_SYNC_ACTIVE;
vsync <= ~`VIDEO_V_SYNC_ACTIVE;
visible <= 1'b0;
x <= 16'd0;
y <= 16'd0;
end else begin
hsync <= (state_h == `VIDEO_SYNC) ^ (~`VIDEO_H_SYNC_ACTIVE);
vsync <= (state_v == `VIDEO_SYNC) ^ (~`VIDEO_V_SYNC_ACTIVE);
visible <= (state_h == `VIDEO_ACTIVE) && (state_v == `VIDEO_ACTIVE);
x <= count_h - 1;
y <= count_v - 1;
end
end
// Horizontal state machine
always @(posedge clk) begin
if (reset == 1'b1) begin
count_h <= 16'b1;
state_h <= `VIDEO_FRONTPORCH;
end else begin
inc_v <= 0;
count_h <= count_h + 16'd1;
case (state_h)
`VIDEO_SYNC: begin
if (count_h == `VIDEO_H_SYNC_PIXELS) begin
state_h <= `VIDEO_BACKPORCH;
count_h <= 16'b1;
end
end
`VIDEO_BACKPORCH: begin
if (count_h == `VIDEO_H_BP_PIXELS) begin
state_h <= `VIDEO_ACTIVE;
count_h <= 16'b1;
end
end
`VIDEO_ACTIVE: begin
if (count_h == `VIDEO_H_ACTIVE_PIXELS) begin
state_h <= `VIDEO_FRONTPORCH;
count_h <= 16'b1;
end
end
`VIDEO_FRONTPORCH: begin
if (count_h == `VIDEO_H_FP_PIXELS) begin
state_h <= `VIDEO_SYNC;
count_h <= 16'b1;
inc_v <= 1;
end
end
endcase
end
end
// Vertical state machine
always @(posedge clk) begin
if (reset == 1'b1) begin
count_v <= 16'b1;
state_v <= `VIDEO_FRONTPORCH;
end else begin
if (inc_v) begin
count_v <= count_v + 16'd1;
case (state_v)
`VIDEO_SYNC: begin
if (count_v == `VIDEO_V_SYNC_LINES) begin
state_v <= `VIDEO_BACKPORCH;
count_v <= 16'b1;
end
end
`VIDEO_BACKPORCH: begin
if (count_v == `VIDEO_V_BP_LINES) begin
state_v <= `VIDEO_ACTIVE;
count_v <= 16'b1;
end
end
`VIDEO_ACTIVE: begin
if (count_v == `VIDEO_V_ACTIVE_LINES) begin
state_v <= `VIDEO_FRONTPORCH;
count_v <= 16'b1;
end
end
`VIDEO_FRONTPORCH: begin
if (count_v == `VIDEO_V_FP_LINES) begin
state_v <= `VIDEO_SYNC;
count_v <= 16'b1;
end
end
endcase
end
end
end
endmodule
当尝试使用 IceStorm 工具链对此进行综合时,yosys
警告说 hsync
有多个驱动程序:
Warning: multiple conflicting drivers for top.\timing.hsync:
port Q[0] of cell $techmap\timing.$procdff9 ($adff)
port Q[0] of cell $techmap\timing.$procdff0 ($adff)
nextpnr-ice40
随后在同一问题上失败:
ERROR: multiple drivers on net 'P1B4' ($auto$simplemap.cc:496:simplemap_adff5.Q and $auto$simplemap.cc:496:simplemap_adff6.Q)
ERROR: Loading design failed.
我尝试了几种不同的排列来尝试解决这个问题,并做了一些观察:
- 如果我将
case (reset)
0:
块中的赋值(总是在第一个)更改为hsync <= 'VIDEO_H_SYNC_ACTIVE
那么结果是可综合的,并且确实断言hsync
在进行更改后没有像我预期的那样重置时不断。 - 如果我完全删除
hsync <= (state_h == 'VIDEO_SYNC) ^ (~'VIDEO_H_SYNC_ACTIVE)
行但在重置期间保留hsync <= ~'VIDEO_H_SYNC_ACTIVE
则结果也是可合成的,并且hsync
始终未断言。
(我在上面用 '
替换了反引号,因为反引号是内联逐字文本的 Markdown 元字符。我在实际程序中使用反引号作为常量。)
这让我得出结论,hsync <=
右侧的表达式就是问题所在。但是我很困惑为什么非常相似的 vsync <=
行不会产生类似的错误:
hsync <= (state_h == `VIDEO_SYNC) ^ (~`VIDEO_H_SYNC_ACTIVE);
vsync <= (state_v == `VIDEO_SYNC) ^ (~`VIDEO_V_SYNC_ACTIVE);
该模块在 iverilog
.
我正在使用 Yosys 0.8 和从 git sha1 a6a4349 构建的 nextpnr。我也尝试升级到 Yosys 0.9 并得到相同的结果,但我怀疑是我的错,而不是在工具链中。
IEEE 综合标准 (1364.1) 不允许这种异步复位模式。因此只能使用 if
语句:
此处的其他答案是重要的垫脚石:
- 我的重置实现最初是异步的,并且是以不符合 Verilog 综合标准的方式编写的。
- 我的条件重置逻辑是使用
switch
而不是if
编写的(由于我在其他地方看到的一些令人困惑的建议)。
不幸的是,这条路在那儿变干了,因为在那之后 timing.v
合成得很好。原来问题其实出在top.v
而不是:
video_timing timing(
.reset(reset_loc),
.clk(vga_ck),
.hsync(vga_hs),
.vsync(vga_hs),
.visible(vga_de)
);
我不小心将 vga_hs
分配给了 hsync
和 vsync
。 ♂️
将 vsync
行更改为引用 vga_vs
后,设计现在可以按预期进行综合和运行。
经验教训:问题并不总是出在编译器认为的地方!