verilog 如何将输入值处理为 always_ff 块中的 if 语句
How does verilog treat input values to if statements in always_ff blocks
我目前正在使用 Icarus Verilog 开发流水线 MIPS cpu,并且在 always_ff
循环中使用 if
语句时遇到了一些非常奇怪的行为。我目前正在测试这个 PC 块的实现:
module PC (
input logic clk,
input logic rst,
input logic[31:0] PC_JVal,
input logic jump_en,
input logic branch_en,
input logic PC_Stall,
output logic [31:0] PC_Out,
output logic fetch_stall,
output logic active,
output logic [2:0] check
);
// Active is completely dependent on the value of the PC.
// JUMP_EN --> PC = JVAL
// BRANCH_EN --> PC = PC + JVAL
// PC_Stall --> PC = PC
reg [31:0] PC;
logic [31:0] branchSignExt = (PC_JVal[15] == 1) ? {16'hFFFF, PC_JVal[15:0]} : {16'h0000, PC_JVal[15:0]};
logic start;
assign fetch_stall = PC_Stall;
assign active = (PC != 0) ? 1 : 0;
assign PC_Out = (active == 0) ? 0 : ( (PC_Stall == 1) ? PC + 4 : ( (jump_en == 1) ? PC_JVal : ( (branch_en == 1) ? PC + branchSignExt : PC + 4 ) ) );
initial begin
PC = 0;
start = 0;
check = 0;
end
always_ff @ (posedge clk) begin
check[1] <= ~check[1];
if (rst) begin
start <= 1;
end
else if (active) begin
if (PC_Stall) begin
PC <= PC;
check[0] <= ~check[0];
end
else if (jump_en) begin
PC <= PC_JVal;
end
else if (branch_en) begin
PC <= PC + branchSignExt;
end
else begin
PC <= PC + 4;
end
end
end
always_ff @ (negedge rst) begin
if (start) begin
PC <= 32'hBFBFFFFC;
start <= 0;
end
end
endmodule
并且是 运行 以下测试台:
module PC_TB ();
logic clk;
logic rst;
logic[31:0] PC_JVal;
logic jump_en;
logic branch_en;
logic PC_Stall;
logic [31:0] PC_Out;
logic fetch_stall;
logic active;
logic [2:0] check;
initial begin
$dumpfile("PC_TB.vcd");
$dumpvars(0, PC_TB);
clk = 0;
jump_en = 0;
PC_Stall = 0;
branch_en = 0;
rst = 0;
repeat(100) begin
#50; clk = ~clk;
end
$fatal(1, "Timeout");
end
initial begin
@ (posedge clk);
@ (posedge clk);
@ (posedge clk);
rst = 1;
@ (posedge clk);
@ (posedge clk);
@ (posedge clk);
rst = 0;
@ (posedge clk);
@ (posedge clk);
@ (posedge clk);
PC_Stall = 1;
@ (posedge clk);
PC_Stall = 0;
@ (posedge clk);
@ (posedge clk);
end
PC PC(.clk(clk), .rst(rst), .PC_JVal(PC_JVal), .jump_en(jump_en), .branch_en(branch_en), .PC_Stall(PC_Stall), .PC_Out(PC_Out), .fetch_stall(fetch_stall), .active(active), .check(check));
endmodule
我遇到的问题是,如何评估检查 PC_Stall 的 if 语句似乎在时钟周期之间交替,我不知道为什么。
当运行它与测试台保持原样(不是期望的输出)时,我得到以下 VCD 输出,PC 停顿并没有真正发生(PC 值应该保持 2 个周期,但在这里只有一个。)
Stall lasts 1 Cycle
然后通过将 PC_Stall 断言的点向前移动一个周期,导致 Stall 持续 3 个周期,即使它只断言 1.
Stall lasts 3 cycles
我一直被困在这个问题上,真的不知道哪里出了问题,非常感谢您的帮助。
iverilog
还没有很好地支持 SystemVerilog 功能。如果你在其他模拟器上编译你的代码,比如 edaplayground 上的 VCS,你会得到编译错误。例如:
Error-[ICPD] Illegal combination of drivers
Illegal combination of procedural drivers
Variable "check" is driven by an invalid combination of procedural drivers.
Variables written on left-hand of "always_ff" cannot be written to by any
other processes, including other "always_ff" processes.
This variable is declared at : logic [2:0] check;
The first driver is at : always_ff @(posedge clk) begin
check[1] <= (~check[1]);
...
The second driver is at : check = 0;
您必须修复所有此类错误。
请注意,如果您注册一个免费帐户,edaplayground 上可以使用多个模拟器。
因此,当所述条件的两个输入都发生变化并且条件本身在正时钟边沿执行时,关于如何处理条件似乎是一个编译器问题。
问题已通过在所述条件之前添加一个小延迟来解决,以便为值提供更新时间或其他东西,不确定,这似乎是一个拙劣的解决方案,但它有效。
这可能不是一个完整的答案,但我有理由相信您在 PC_Stall 和 active 之间存在循环依赖。通常当我有奇怪的行为时,这是因为我有一个奇怪的循环依赖,如您的代码中所述。
我目前正在使用 Icarus Verilog 开发流水线 MIPS cpu,并且在 always_ff
循环中使用 if
语句时遇到了一些非常奇怪的行为。我目前正在测试这个 PC 块的实现:
module PC (
input logic clk,
input logic rst,
input logic[31:0] PC_JVal,
input logic jump_en,
input logic branch_en,
input logic PC_Stall,
output logic [31:0] PC_Out,
output logic fetch_stall,
output logic active,
output logic [2:0] check
);
// Active is completely dependent on the value of the PC.
// JUMP_EN --> PC = JVAL
// BRANCH_EN --> PC = PC + JVAL
// PC_Stall --> PC = PC
reg [31:0] PC;
logic [31:0] branchSignExt = (PC_JVal[15] == 1) ? {16'hFFFF, PC_JVal[15:0]} : {16'h0000, PC_JVal[15:0]};
logic start;
assign fetch_stall = PC_Stall;
assign active = (PC != 0) ? 1 : 0;
assign PC_Out = (active == 0) ? 0 : ( (PC_Stall == 1) ? PC + 4 : ( (jump_en == 1) ? PC_JVal : ( (branch_en == 1) ? PC + branchSignExt : PC + 4 ) ) );
initial begin
PC = 0;
start = 0;
check = 0;
end
always_ff @ (posedge clk) begin
check[1] <= ~check[1];
if (rst) begin
start <= 1;
end
else if (active) begin
if (PC_Stall) begin
PC <= PC;
check[0] <= ~check[0];
end
else if (jump_en) begin
PC <= PC_JVal;
end
else if (branch_en) begin
PC <= PC + branchSignExt;
end
else begin
PC <= PC + 4;
end
end
end
always_ff @ (negedge rst) begin
if (start) begin
PC <= 32'hBFBFFFFC;
start <= 0;
end
end
endmodule
并且是 运行 以下测试台:
module PC_TB ();
logic clk;
logic rst;
logic[31:0] PC_JVal;
logic jump_en;
logic branch_en;
logic PC_Stall;
logic [31:0] PC_Out;
logic fetch_stall;
logic active;
logic [2:0] check;
initial begin
$dumpfile("PC_TB.vcd");
$dumpvars(0, PC_TB);
clk = 0;
jump_en = 0;
PC_Stall = 0;
branch_en = 0;
rst = 0;
repeat(100) begin
#50; clk = ~clk;
end
$fatal(1, "Timeout");
end
initial begin
@ (posedge clk);
@ (posedge clk);
@ (posedge clk);
rst = 1;
@ (posedge clk);
@ (posedge clk);
@ (posedge clk);
rst = 0;
@ (posedge clk);
@ (posedge clk);
@ (posedge clk);
PC_Stall = 1;
@ (posedge clk);
PC_Stall = 0;
@ (posedge clk);
@ (posedge clk);
end
PC PC(.clk(clk), .rst(rst), .PC_JVal(PC_JVal), .jump_en(jump_en), .branch_en(branch_en), .PC_Stall(PC_Stall), .PC_Out(PC_Out), .fetch_stall(fetch_stall), .active(active), .check(check));
endmodule
我遇到的问题是,如何评估检查 PC_Stall 的 if 语句似乎在时钟周期之间交替,我不知道为什么。
当运行它与测试台保持原样(不是期望的输出)时,我得到以下 VCD 输出,PC 停顿并没有真正发生(PC 值应该保持 2 个周期,但在这里只有一个。)
Stall lasts 1 Cycle
然后通过将 PC_Stall 断言的点向前移动一个周期,导致 Stall 持续 3 个周期,即使它只断言 1.
Stall lasts 3 cycles
我一直被困在这个问题上,真的不知道哪里出了问题,非常感谢您的帮助。
iverilog
还没有很好地支持 SystemVerilog 功能。如果你在其他模拟器上编译你的代码,比如 edaplayground 上的 VCS,你会得到编译错误。例如:
Error-[ICPD] Illegal combination of drivers
Illegal combination of procedural drivers
Variable "check" is driven by an invalid combination of procedural drivers.
Variables written on left-hand of "always_ff" cannot be written to by any
other processes, including other "always_ff" processes.
This variable is declared at : logic [2:0] check;
The first driver is at : always_ff @(posedge clk) begin
check[1] <= (~check[1]);
...
The second driver is at : check = 0;
您必须修复所有此类错误。
请注意,如果您注册一个免费帐户,edaplayground 上可以使用多个模拟器。
因此,当所述条件的两个输入都发生变化并且条件本身在正时钟边沿执行时,关于如何处理条件似乎是一个编译器问题。
问题已通过在所述条件之前添加一个小延迟来解决,以便为值提供更新时间或其他东西,不确定,这似乎是一个拙劣的解决方案,但它有效。
这可能不是一个完整的答案,但我有理由相信您在 PC_Stall 和 active 之间存在循环依赖。通常当我有奇怪的行为时,这是因为我有一个奇怪的循环依赖,如您的代码中所述。