verilog - 在 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
解决方案
测试,就像好的编码是一门艺术一样。这不是我能教/告诉你的东西
“熟能生巧”。
一个过程是提供输入,使您的 FSM 处于状态 X,然后测试是否是这种情况。困难的部分是预测你必须编写 FSM 的等效代码,而不重复 FSM 代码。(这就是为什么理想情况下你有其他人,例如使用 UVM 来测试你的代码)。
尝试获得一个具有代码覆盖率的模拟器,它会告诉您是否已经测试了每个(角落)案例。
说了这么多,我认为你应该首先重新访问你当前的代码,因为风格相当不正统。以下是我对当前代码的一些问题:
- 改进格式:修复缩进并在“始终”部分之间添加空行。
- 使用 ANSI 风格的端口定义:
( input clk, ... output reg heater... );
- 尽量少用宏。将 localparam 用于常量。
- 对常量使用全部大写。
- 添加指标,例如所有状态常量都以 ST_ 开头
- 不要使用二进制数作为值。8'd30 比 'b00011110 多说
- 您的代码充满了闩锁。使用默认值或为每个状态中的每个变量分配一个值。
- 不要使用,
always @(current_state,temp_sen...
而是使用always_comb
或always @ *
在 RTL 代码中使用“initial”有很大的问题,有人说这很好,其他人说使用 reset 代替(我在后一个阵营)。你有一个重置信号,所以我建议你使用它并删除该initial
部分。
最后一句话:
您的 FSM 首先检查温度并忽略灯光状态。这些通常是两个独立变量,但是按照您编写它的方式,您的 FSM 无法处理所有组合。
推荐阅读
- java - For循环在java中不起作用的条件
- typescript - 带有 TypeScript + Imports 的 VS Code 调试器
- spring-boot - 为 Spring boot 2.5.3 配置管理 HTTP、Server HTTPS 使用相同的动态端口
- asp.net - 为什么 Microsoft WebForms ReportViewer 在查看期间支持 PageBreakAtStart,但在导出期间不支持?
- post - HTTP 请求返回 400,但不能抛出错误
- python - 一个随机的维基百科文章生成器
- mysql - MySQL如何创建一个用字符、日期和数字格式化的自定义id列
- css - 如何实现一个简单的反应多步控制
- c++ - 生产者/消费者,生产者比消费者快,我应该使用双缓冲区还是 spsc_queue?(C++)
- flutter - 在颤动中返回小部件的最佳方法是什么