首页 > 解决方案 > 在 Verilog 中测试有限状态机模块

问题描述

我在为智能家居系统(舒适模块)编写测试台时遇到问题。舒适模块是使用有限状态机设计的。我应该如何测试模块的周期。如果motion_sen 为1,则模块应不断检查temp_sen 和lume_sen。如果有人知道如何制作它,我将不胜感激。

 `define start 4'd0 
 `define temp_heat 4'd1 
 `define temp_cool 4'd2 
 `define light_bright 4'd3 
 `define light_dim 4'd4 
module comfort (clk,reset,motion_sen,temp_sen,lume_sen,light,heater,cooler,light_high,light_low); 

input  clk,reset,motion_sen;
input [7:0] temp_sen,lume_sen; 
output reg heater,cooler,light_high,light_low,light;

reg [3:0] current_state;
reg [3:0] next_state;
wire clk; 
initial begin 
      current_state=`start;
  next_state= `start;
     heater='b0;
     cooler='b0;
     light_high='b0; 
     light_low='b0; 
     light='b0; 
end 
  always @(posedge clk) 
 current_state=next_state; 
 always @(current_state) 
 begin 
     case(current_state)
     `start: 
     begin 
         heater='b0; 
         cooler='b0; 
         light_high='b0; 
         light_low='b0;light='b0; 
     end 
 `temp_heat: 
     begin 
         if(motion_sen==1)                   
             begin 
                 heater ='b1; 
                 cooler='b0;
                 light='b1;
                 end                    
         else                     
         heater ='b0;
         end 
 `temp_cool:
    begin 
 if(motion_sen==1)                    
      begin 
  cooler ='b1;
      heater ='b0;
  light='b1;
  end                     
 else 
 cooler ='b0;
 end 
 `light_bright:
 begin 
 if(motion_sen==1)                  
 begin 
 light_high ='b1;
 light_low='b0;
 light='b1;
 end           
 else 
     light_high ='b0;
 end       
  `light_dim:
  begin 
  if(motion_sen==1)                
   begin   
 light_low ='b1;
 light_high='b0;
 end             
 else  
 light_low ='b0;
 end 
 endcase 
 end 

always  @(current_state,temp_sen,lume_sen,reset)
 begin 
     if(reset=='b1) 
         next_state=`start;
     else  
         case(current_state)
             `start: 
                 begin 
                     if(temp_sen> 'b00011110)
                         next_state=`temp_cool; 
                     else if(temp_sen< 'b00001111) 
                         next_state=`temp_heat; 
                     else if(lume_sen > 'b00001111) 
                         next_state=`light_dim;
                     else if (lume_sen < 'b00001010)
                         next_state=`light_bright; 
                 end  
             `temp_cool: 
                 begin  
                     if(temp_sen< 'b00001111)
                         next_state=`temp_heat;
                     else if (lume_sen > 'b00001111)
                         next_state=`light_dim;
                     else if(lume_sen < 'b00001010)
                         next_state=`light_bright;
                 end 
             `temp_heat: 
                 begin   
                     if(temp_sen> 'b00011110) 
                         next_state=`temp_cool;
                     else if (lume_sen > 'b00001111)
                         next_state= `light_dim;
                     else if(lume_sen < 'b00001010)
                     next_state= `light_bright; 
                 end  
             `light_dim: 
                 begin 
                     if(lume_sen < 'b00001111)
                         next_state=`light_bright;
                 end 
             `light_bright:
                 begin
                     next_state=`start;
                 end 
             endcase  
         end 
     endmodule

标签: verilogfpgatest-bench

解决方案


测试,就像好的编码是一门艺术一样。这不是我能教/告诉你的东西

“熟能生巧”

一个过程是提供输入,使您的 FSM 处于状态 X,然后测试是否是这种情况。困难的部分是预测你必须编写 FSM 的等效代码,而不重复 FSM 代码。(这就是为什么理想情况下你有其他人,例如使用 UVM 来测试你的代码)。

尝试获得一个具有代码覆盖率的模拟器,它会告诉您是否已经测试了每个(角落)案例。


说了这么多,我认为你应该首先重新访问你当前的代码,因为风格相当不正统。以下是我对当前代码的一些问题:

  • 改进格式:修复缩进并在“始终”部分之间添加空行。
  • 使用 ANSI 风格的端口定义:( input clk, ... output reg heater... );
  • 尽量少用宏。将 localparam 用于常量。
  • 对常量使用全部大写。
  • 添加指标,例如所有状态常量都以 ST_ 开头
  • 不要使用二进制数作为值。8'd30 比 'b00011110 多说
  • 您的代码充满了闩锁。使用默认值或为每个状态中的每个变量分配一个值。
  • 不要使用,always @(current_state,temp_sen...而是使用always_combalways @ *

在 RTL 代码中使用“initial”有很大的问题,有人说这很好,其他人说使用 reset 代替(我在后一个阵营)。你有一个重置信号,所以我建议你使用它并删除该initial部分。

最后一句话:
您的 FSM 首先检查温度并忽略灯光状态。这些通常是两个独立变量,但是按照您编写它的方式,您的 FSM 无法处理所有组合。


推荐阅读