引言:
有限状态机及其设计技术是实用数字系统设计中的重要组成部分,也是实现高效率、高可靠和高速控制逻辑系统的重要途径。
广义而论,只要是涉及触发器的电路,无论电路大小,都能归结为状态机。因此,对于数字系统设计工程师,面对的只要是时序电路设计,状态机的概念则是必须贯穿于整个设计始终的最基本的设计思想和设计方法。
基于现代数字系统设计技术的状态机的HDL表述形态和表述风格具有一定的典型性和规律化。只要把握了这些固定的语句表达部分,就能根据实际需要写出各种不同风格和面向不同实用目的的Verilog状态机了。
一般有限状态机的结构:
1 )说明部分(状态转换变量定义和所有可能状态的说明)
Verilog状态机程序说明部分中,各状态元素(如s0、s1)是用参数说明关键词parameter来定义的。其中各状态元素所取的具体数值或编码必须写上,而关键词旁的位宽说明[2:0]可写可不写。
parameter [2:0] s0=0, s1=1,s2=2,s3=3,s4=4;
reg[2:0] cuurent_srate,next_state;
语法:参数定义关键词parameter
用关键词parameter来定义常量,就是用parameter来定义一个标识符,用以代表某个常量,如时延、变量的宽度等。这种方法很容易改变整个设计。
格式:
parameter 标识符1=表达式或数值1,标识符2=表达式或数值2,…;
例如:
parameter A=15,B=4‘b1011,C=8’hAC
在模块中使用参数定义的常数只能被赋值一次。
2 ) 主控时序进程
所谓主控时序进程是指负责状态机运转和在时钟驱动下负责状态转换的进程。状态机是随外部时钟信号,以同步时序方式工作的。
3 )主控组合进程
如果将状态机比喻为一台机床,那么主控时序进程即为此机床的驱动电机,clk信号为此电机的功率导线,而主控组合进程则为机床的机械加工部分,它本身运转有赖于电机的驱动,它的具体工作方式则依赖于机床操作者的控制。
4 )辅助进程
辅助进程用于配合状态机工作的组合进程或时序进程。比如:
module FSM_EXP(clk,rst,sin,cout,cstout);
input clk; //状态机时钟
input rst; //复位信号
input [0:1] sin; //来自外部的状态机控制信号
output [4:0] cstout; //状态机对外部发出的控制信号信号输出
output [3:0] cout;
reg [3:0] cout;
assign cstout=cst;
parameter s0=0,s1=1,s2=2,s3=3,s4=4; //定义状态参数
reg[4:0] cst,nst; //当前状态、下一状态
always@(posedge clk or negedge rst) //主控时序进程
begin
if(!rst) cst<=s0; //复位有效时,下一状态进入s0
else cst<=nst;
end
always@(cst or sin)begin //主控组合进程
case(cst)
s0:begin cout<=5;
if(sin==2'b00) nst<=s0;
else nst<=s1;
end
s1:begin cout<=8;
if(sin==2'b01) nst<=s1;
else nst<=s2;
end
s2:begin cout<=12;
if(sin==2'b10) nst<=s2;
else nst<=s3;
end
s3:begin cout<=14;
if(sin==2'b11) nst<=s3;
else nst<=s4;
end
s4:begin cout<=9;
nst<=s0;
end
default:nst<=s0; //现太若未出现以上各太,返回初态s0
endcase
end
endmodule
实验内容:序列检测器的设计
设计要求:
用状态机实现序列检测器的设计,并对其进行仿真和硬件测试。
设计原理:
序列检测器可用于检测一组或多组由二进制码组成的脉冲序列信号,当序列检测器连续收到一组串行二进制码后,如果这组码与检测器中预先设置的码相同,则输出A,否则输出B。
提示1:序列检测器元件及状态值:
提示2:状态机各状态之间的转换关系
参考代码:
module FSM(clk,rst,DIN,DOUT);
input clk;
input rst;
input DIN;//输入一位二进制数
reg [7:0] D;//预置数?
output [3:0] DOUT;
reg [3:0] DOUT;
parameter s0=0,s1=1,s2=2,s3=3,s4=4,s5=5,s6=6,s7=7,s8=8;
reg[7:0] CST,NST;//当前状态、下一状态
always@(posedge clk or negedge rst)//主控时序进程
begin
if(!rst) CST<=s0;
else CST<=NST;
end
always@(CST or DIN)begin//主控组合进程
case(CST)
s0:begin DOUT<=4'b1011;
if(DIN==D[7]) NST<=s1;
else NST<=s0;
end
s1:begin DOUT<=4'b0001;
if(DIN==D[6]) NST<=s2;
else NST<=s0;
end
s2:begin DOUT<=4'b0010;
if(DIN==D[5]) NST<=s3;
else NST<=s0;
end
s3:begin DOUT<=4'b0011;
if(DIN==D[4]) NST<=s4;
else NST<=s0;
end
s4:begin DOUT<=4'b0100;
if(DIN==D[3]) NST<=s5;
else NST<=s0;
end
s5:begin DOUT<=4'b0101;
if(DIN==D[2]) NST<=s6;
else NST<=s0;
end
s6:begin DOUT<=4'b0110;
if(DIN==D[1]) NST<=s7;
else NST<=s0;
end
s7:begin DOUT<=4'b0111;
if(DIN==D[0]) NST<=s8;
else NST<=s0;
end
s8:begin DOUT<=4'b1010;
NST<=s0;
end
default:NST<=s0;
endcase
end
endmodule
注意:这里的D[7]--D[0]需要初始化,可以换成一串数字,比如11001100;
仿真波形:
提示3:状态的硬件验证模式选择
引脚锁定:
建议用键7(PIO11)控制复位信号CLR;键6(PIO9)控制状态机工作时钟CLK;待检测串行序列数输入DIN接PIO10(左移,最高位在前);指示输出AB接PIO39~PIO36(显示于数码管6)。下载后,1、按实验板“系统复位”键;2、用键2和键1输入2位十六进制待测序列数"11100101 ";3、按键7复位(平时数码6指示显“B”);4、按键6(CLK) 8次,这时若串行输入的8位二进制序列码(显示于数码2/1和发光管D8~D0)与预置码"11100101 "相同,则数码6应从原来的B变成A ,表示序列检测正确,否则仍为B。
总结与分析: