状态机模型是FPGA设计三大支柱之一,明德扬把计数器设计,状态机设计和FIFO设计并称FPGA设计三大支柱。采用三段式设计的状态机具有结构清晰,逻辑清楚易于实现等特点,这也是明德扬推荐的设计方法。在照例抄写了一段状态机代码后,自己写了仿真的代码,国际惯例上代码:
//自动转换量程频率控制器
/*信号定义:
clk: 输入时钟
clr: 为整个频率计的异步复位信号
rst: 用来在量程转换开始时复位计数器
std_f_sel: 用来选择标准时基
cntover: 代表超量程
cntlow: 代表欠量程
状态A,B,C,D,E,F,采用一位热码编码
*/
module control(std_f_sel, rst, clk, clr, cntover, cntlow);
input clk, clr, cntover, cntlow;
output[1:0] std_f_sel;
output rst;
reg[1:0] std_f_sel;
reg rst;
reg[5:0] present, next; //用于保存当前状态和次态的中间变量
parameter start_f100k = 6'b000001, //状态A编码,采用1位热码
f100k_cnt = 6'b000010, //状态B
start_f10k = 6'b000100, //状态C
f10k_cnt = 6'b001000, //状态D
start_f1k = 6'b010000, //状态E
f1k_cnt = 6'b100000; //状态F
always @(posedge clk or posedge clr)
begin
if(clr)
present = start_f10k; //start_f10k 位起始状态
else
present = next;
end
always @(present or cntover or cntlow)
begin
case(present)
start_f100k: next <=start_f10k;
f100k_cnt:
begin
if(cntlow)
next <=start_f10k;
else
next <=f100k_cnt;
end
start_f10k: next <=start_f1k;
f10k_cnt:
begin
if(cntlow)
next <=start_f1k;
else if(cntover)
next <=start_f100k;
else
next <=f10k_cnt;
end
start_f1k: next <=f1k_cnt;
f1k_cnt:
begin
if(cntover)
next <= start_f10k;
else
next <= f1k_cnt;
end
default: next <= start_f10k; //缺省状态为起始状态
endcase
end
always @(present)
begin
case(present)
start_f100k:
begin
rst = 1;
std_f_sel = 2'b00;
end
f100k_cnt:
begin
rst = 0;
std_f_sel = 2'b00;
end
start_f10k:
begin
rst = 1;
std_f_sel = 2'b01;
end
f10k_cnt:
begin
rst = 0;
std_f_sel = 2'b01;
end
start_f1k:
begin
rst = 1;
std_f_sel = 2'b11;
end
f1k_cnt:
begin
rst = 0;
std_f_sel = 2'b11;
end
default:
begin
rst = 1;
std_f_sel = 2'b01;
end
endcase
end
endmodule
`timescale 1ns/1ps
module sim_stateMachine;
reg clk, clr, cntover,cntlow;
wire[1:0] std_f_sel;
wire rst;
control SM0(
.std_f_sel (std_f_sel),
.rst (rst),
.clk (clk),
.clr (clr),
.cntover (cntover),
.cntlow (cntlow)
);
initial
begin
clk = 0;
clr = 1;
cntover = 1;
cntlow = 0;
#20 clr = 0;
#2000 $finish;
end
always #20 clk = ~clk;
always #40 cntover = ~cntover;
always #20 cntlow = ~cntlow;
endmodule
测试代码从第109行看起,写的比较简单,无非定义时钟,设置初值,约定结束条件。在vivado 2018.3中进行行为仿真,如图:
从仿真结果中可以看出状态机输出结果只在1和3之间来回切换并没有覆盖所有可能的情况。看一下现态的值:
可以看出现态的值也没有覆盖所有可能的取值,一开始我以为是初值设计的不好,在尝试不同初值后发现情况依旧。我在仿真的时候为了图省事,直接用always 持续变换输入,但是结果看起来并不满意,至少这样的代码拿出去别人是不敢用的。没法了,老老实实把每一种情况的初值写出来,再进行仿真吧。这篇文章(我是直达车)讲解了仿真时应该注意的地方,可以看一下。