我使用状态机概念编写了一个用于展位乘数(基数2)的行为程序,使用modelsim在程序模拟期间正确获得结果,但是当我将其移植到fpga(斯巴达3)时,结果并不像预期的那样。 有人请帮帮我。我哪里出错了?
module booth_using_statemachine(Mul_A,Mul_B,Mul_Result,clk,reset);
input Mul_A,Mul_B,clk,reset;
output Mul_Result;
wire [7:0] Mul_A,Mul_B;
reg [7:0] Mul_Result;
reg [15:0] R_B;
reg [7:0] R_A;
reg prev;
reg [1:0] state;
reg [3:0] count;
parameter start=1 ,add=2 ,shift=3;
always @(state)
begin
case(state)
start:
begin
R_A <= Mul_A;
R_B <= {8'b00000000,Mul_B};
prev <= 1'b0;
count <= 3'b000;
Mul_Result <= R_B[7:0];
end
add:
begin
case({R_B[0],prev})
2'b00:
begin
prev <= 1'b0;
end
2'b01:
begin
R_B[15:8] <= R_B[15:8] + R_A;
prev <= 1'b0;
end
2'b10:
begin
R_B[15:8] <= R_B[15:8] - R_A;
prev <= 1'b1;
end
2'b11:
begin
prev <=1'b1;
end
endcase
end
shift:
begin
R_B <= {R_B[15],R_B[15:1]};
count <= count + 1;
end
endcase
end
always @(posedge clk or posedge reset)
begin
if(reset==1)
state <= start;
else
begin
case(state)
start:
state <= add;
add:
state <= shift;
shift:
begin
if(count>7)
state <= start;
else
state <=add;
end
endcase
end
end
endmodule
答案 0 :(得分:3)
您的组合always
区块中的敏感列表不完整。变化:
always @(state)
为:
always @*
这可能是合成锁存器。
在组合always
块中使用阻止分配。将<=
更改为=
。
良好的合成和linting工具应该警告你这些结构。
答案 1 :(得分:0)
如果某些内容在模拟中有效但实际上不起作用,请按照以下清单进行操作:
第二点的示例是here,您需要下一阶段逻辑,当前状态逻辑和输出逻辑。
有关如何正确编码FPGA的FSM的更多信息,请参阅here(转到HDL编码技术 - >基本HDL编码技术)
答案 2 :(得分:0)
你在这里遇到了各种各样的问题。
第一个始终阻止的敏感度列表不完整。你只看state
,但还有许多其他信号需要在那里。如果您的工具支持它,请使用always @*
,它会自动生成敏感度列表。改变这一点,你的代码将开始模拟它在FPGA上运行。
这隐藏了代码的其他问题,因为它导致信号在错误的时间更新。您已经设法让您的代码在模拟器中工作,但它基于谎言。谎言是R_A
,R_B
,prev
,count
&amp; Mul_Result
仅依赖于状态的变化,但是有更多的信号是该逻辑的输入。
你陷入了Verilog关键字reg
创建寄存器的陷阱。它没有。我知道这很愚蠢,但就是这样。 reg
的含义是它是一个可以从程序块中分配的变量。 wire
s不能分配到程序块内。
当您在时钟程序块(请参阅脚注)中指定某些内容时,会创建一个寄存器,就像您的state
变量一样。 R_A
,R_B
,prev
和count
似乎都在循环中保持值,因此需要注册。我会改变这样的代码:
首先,我创建了一组next_*
个变量。这些将包含我们在下一个时钟的每个寄存器中想要的值。
reg [15:0] next_R_B;
reg [7:0] next_R_A;
reg next_prev;
reg [3:0] next_count;
然后我会更改时钟进程以使用它们:
always @(posedge clk or posedge reset) begin
if(reset==1) begin
state <= start;
R_A <= '0;
R_B <= '0;
prev <= '0;
count <= '0;
end else begin
R_A <= next_R_A;
R_B <= next_R_B;
prev <= next_prev;
count <= next_count;
case (state)
.....
然后最后更改第一个进程以分配给next_*
变量:
always @* begin
next_R_A <= R_A;
next_R_B <= R_B;
next_prev <= prev;
next_count <= count;
case(state)
start: begin
next_R_A <= Mul_A;
next_R_B <= {8'b00000000,Mul_B};
next_prev <= 1'b0;
next_count <= 3'b000;
Mul_Result <= R_B[7:0];
end
add: begin
case({R_B[0],prev})
2'b00: begin
next_prev <= 1'b0;
end
.....
注意:
next_
值都默认为之前的值。next_
个值
除了在计时过程中,next_
值永远不会被写入。我还怀疑你希望Mul_Result
成为wire
并拥有assign Mul_Result = R_B[7:0];
而不是另一个仅在开始状态下更新的注册,但我不确定是什么你要去那儿。
reg
,但reg
不一定是注册。