将有限状态机图转换为 Verilog 代码
Converting finite state machine diagram to Verilog code
我需要将下面的有限状态图转换成Verilog代码。
我已经在下面包含了我到目前为止编写的代码。在我看来,我已经正确地实现了所有逻辑,并且代码适用于前几个输入组合。然而它最终失败了,我似乎无法弄清楚为什么。
module FiniteStateMachine(output reg out_z, input in_x, in_y, clk, reset_b);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
reg state;
always @(posedge clk, negedge reset_b) begin
// set state
if (reset_b || !in_x) state <= S0;
else
case (state)
S0: state <= (in_y == 1) ? S1 : S3;
S1: state <= S2;
S2: state <= S3;
S3: state <= S3;
endcase
// set output
out_z <= (state == S2 || state == S3) ? 1 : 0;
end
endmodule
您似乎试图通过将 in_x
视为二次重置来简化 FSM。我认为这种简化是不正确的,而且无论如何你都想变得太聪明了。只需写出每个案例的所有转换,作为嵌套的 case
语句或作为每个状态下的一系列 if
。例如:
case (state)
S0: case ({in_x, in_y})
2'b00: state <= S0;
2'b01: state <= S0;
2'b10: state <= S3;
2'b11: state <= S1;
endcase
S2: case ({in_x, in_y})
…
您现在的实施实际上存在许多问题:
- 你的
state
变量只有一位宽,而它需要是两位:reg state
-> reg [1:0] state
- 您可能实际上并不想让
out_z
成为一个寄存器,因为它应该遵循同一时钟的状态,而不是之后的一个时钟周期。
- 你的
reset_b
逻辑是倒退的,对于negedge重置,你需要通过!reset_b
或~reset_b
检查断言。
- 如前所述,您真的不应该像
reset_b
和 in_x
那样将异步重置与任何同步输入结合使用,即使是同步重置也是如此。虽然这在仿真中会很好地工作,但大多数综合工具可能无法正确处理它。在学习Verilog时,我也犯过同样的错误,花了几天时间才发现并改正。
这是您的代码的更简洁版本,其中实施并评论了此修复,因此您可以看到以下 4 点:
module FiniteStateMachine(output reg out_z, input in_x, in_y, clk, reset_b);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
reg [1:0] state; // Fix state variable
// Set output combinationally (no need for turning operator)
always @(*) begin
out_z = (state == S2 || state == S3);
end
always @(posedge clk, negedge reset_b) begin
// Invert the logic for reset and keep it separate
if (!reset_b) begin
state <= S0;
end
else begin
// You can case on inputs as was suggested, but I think casing on state is fine
// I include only logic for changing state
case (state)
S0: begin
if (in_x && in_y) begin
state <= S1;
end
else if (in_x && !in_y) begin
state <= S3;
end
end
S1: begin
if (in_x) begin
state <= S2;
end
else begin
state <= S0;
end
end
S2: begin
if (in_x) begin
state <= S3;
end
else begin
state <= S0;
end
end
S3: begin
if (!in_x) begin
state <= S0;
end
end
endcase
end
end
endmodule
我需要将下面的有限状态图转换成Verilog代码。
我已经在下面包含了我到目前为止编写的代码。在我看来,我已经正确地实现了所有逻辑,并且代码适用于前几个输入组合。然而它最终失败了,我似乎无法弄清楚为什么。
module FiniteStateMachine(output reg out_z, input in_x, in_y, clk, reset_b);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
reg state;
always @(posedge clk, negedge reset_b) begin
// set state
if (reset_b || !in_x) state <= S0;
else
case (state)
S0: state <= (in_y == 1) ? S1 : S3;
S1: state <= S2;
S2: state <= S3;
S3: state <= S3;
endcase
// set output
out_z <= (state == S2 || state == S3) ? 1 : 0;
end
endmodule
您似乎试图通过将 in_x
视为二次重置来简化 FSM。我认为这种简化是不正确的,而且无论如何你都想变得太聪明了。只需写出每个案例的所有转换,作为嵌套的 case
语句或作为每个状态下的一系列 if
。例如:
case (state)
S0: case ({in_x, in_y})
2'b00: state <= S0;
2'b01: state <= S0;
2'b10: state <= S3;
2'b11: state <= S1;
endcase
S2: case ({in_x, in_y})
…
您现在的实施实际上存在许多问题:
- 你的
state
变量只有一位宽,而它需要是两位:reg state
->reg [1:0] state
- 您可能实际上并不想让
out_z
成为一个寄存器,因为它应该遵循同一时钟的状态,而不是之后的一个时钟周期。 - 你的
reset_b
逻辑是倒退的,对于negedge重置,你需要通过!reset_b
或~reset_b
检查断言。 - 如前所述,您真的不应该像
reset_b
和in_x
那样将异步重置与任何同步输入结合使用,即使是同步重置也是如此。虽然这在仿真中会很好地工作,但大多数综合工具可能无法正确处理它。在学习Verilog时,我也犯过同样的错误,花了几天时间才发现并改正。
这是您的代码的更简洁版本,其中实施并评论了此修复,因此您可以看到以下 4 点:
module FiniteStateMachine(output reg out_z, input in_x, in_y, clk, reset_b);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
reg [1:0] state; // Fix state variable
// Set output combinationally (no need for turning operator)
always @(*) begin
out_z = (state == S2 || state == S3);
end
always @(posedge clk, negedge reset_b) begin
// Invert the logic for reset and keep it separate
if (!reset_b) begin
state <= S0;
end
else begin
// You can case on inputs as was suggested, but I think casing on state is fine
// I include only logic for changing state
case (state)
S0: begin
if (in_x && in_y) begin
state <= S1;
end
else if (in_x && !in_y) begin
state <= S3;
end
end
S1: begin
if (in_x) begin
state <= S2;
end
else begin
state <= S0;
end
end
S2: begin
if (in_x) begin
state <= S3;
end
else begin
state <= S0;
end
end
S3: begin
if (!in_x) begin
state <= S0;
end
end
endcase
end
end
endmodule