我的Verilog行为代码被正确模拟但在FPGA上没有按预期工作

时间:2013-04-05 12:28:30

标签: verilog fpga xilinx modelsim

我使用状态机概念编写了一个用于展位乘数(基数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

3 个答案:

答案 0 :(得分:3)

您的组合always区块中的敏感列表不完整。变化:

always @(state)

为:

always @*

这可能是合成锁存器。

在组合always块中使用阻止分配。将<=更改为=

良好的合成和linting工具应该警告你这些结构。

答案 1 :(得分:0)

如果某些内容在模拟中有效但实际上不起作用,请按照以下清单进行操作:

  • 您是否已初始化每个注册表? (是)
  • 您是否将2个寄存器用于每个时钟后传输的一个工作变量(否) (用于状态2信号/线路,例如state和state_next,并在每个时钟state_next到状态后传输)

第二点的示例是here,您需要下一阶段逻辑,当前状态逻辑和输出逻辑。

有关如何正确编码FPGA的FSM的更多信息,请参阅here(转到HDL编码技术 - >基本HDL编码技术)

答案 2 :(得分:0)

你在这里遇到了各种各样的问题。

  1. 第一个始终阻止的敏感度列表不完整。你只看state,但还有许多其他信号需要在那里。如果您的工具支持它,请使用always @*,它会自动生成敏感度列表。改变这一点,你的代码将开始模拟它在FPGA上运行。

    这隐藏了代码的其他问题,因为它导致信号在错误的时间更新。您已经设法让您的代码在模拟器中工作,但它基于谎言。谎言是R_AR_Bprevcount&amp; Mul_Result 依赖于状态的变化,但是有更多的信号是该逻辑的输入。

  2. 你陷入了Verilog关键字reg创建寄存器的陷阱。它没有。我知道这很愚蠢,但就是这样。 reg的含义是它是一个可以从程序块中分配的变量。 wire s不能分配到程序块内。

    当您在时钟程序块(请参阅脚注)中指定某些内容时,会创建一个寄存器,就像您的state变量一样。 R_AR_Bprevcount似乎都在循环中保持值,因此需要注册。我会改变这样的代码:

  3. 首先,我创建了一组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不一定是注册。