【问题标题】:My Verilog behavioral code getting simulated properly but not working as expected on FPGA我的 Verilog 行为代码得到了正确模拟,但在 FPGA 上没有按预期工作
【发布时间】:2013-04-05 12:28:30
【问题描述】:

我使用状态机概念为展位乘数(基数 2)编写了一个行为程序。在使用 modelsim 进行程序仿真期间,我得到了正确的结果,但是当我将它移植到 fpga (spartan 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

【问题讨论】:

    标签: verilog fpga xilinx modelsim


    【解决方案1】:

    您的组合 always 块中有一个不完整的敏感度列表。变化:

    always @(state)
    

    到:

    always @*
    

    这可能是合成锁存器。

    在您的组合 always 块中使用阻塞分配。将&lt;= 更改为=

    良好的综合和 linting 工具应该就这些结构向您发出警告。

    【讨论】:

      【解决方案2】:

      如果某些东西在模拟中有效但在现实中无效,请遵循以下清单:

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

      第二点的一个例子是here,你需要下一级逻辑,当前状态逻辑和输出逻辑。

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

      【讨论】:

      • 我确实有下一个状态逻辑(第二个案例语句块,@posedge clk),输出逻辑是第一个案例块。够了吧?
      【解决方案3】:

      你有各种各样的问题。

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

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

      2. 您陷入了 Verilog 关键字 reg 创建寄存器的陷阱。它没有。我知道这很愚蠢,但事实就是这样。 reg 的意思是它是一个可以从程序块分配给它的变量。 wires 不能分配到程序块内。

        当您在时钟程序块(见脚注)中分配某些内容时,会创建一个寄存器,例如您的 state 变量。 R_AR_Bprevcount 似乎都在跨周期保持值,因此需要是寄存器。我会像这样更改代码:

      首先我会创建一组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 不一定是寄存器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-12-25
        • 2018-09-11
        • 2019-08-08
        • 1970-01-01
        • 2020-11-10
        • 2021-12-11
        • 2022-10-06
        相关资源
        最近更新 更多