本随笔需要不断完善,姑且先写这一点点。。。。。。。
1、所谓同步有限状态机是是电路状态的变化只能在同一时钟跳变沿时刻发生的逻辑电路。
2、组合逻辑:组合逻辑是由与或非门组成的网络。
3、时序逻辑:时序逻辑是有多个触发器和多个组合逻辑块组成的网络。
同步有限状态机(FSM)被称作是FPGA的灵魂,所谓状态机就是能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。通过状态机的方法,可有效降低抽象难度,同时也能提高代码的可读性及维护性。
主要分为两大类:
米里(Mealy)状态机:输出不仅与状态有关,而且还与输入有关。
摩尔(moore)状态机:输出只和状态有关,与输入无关。
状态机通常包括组合逻辑和时序逻辑两部分,其中时序逻辑由一组触发器组成,用来记忆当前状态。组合逻辑又分为次态逻辑和输出逻辑两部分,次态逻辑的功能就是确定状态机的下一个状态,输出逻辑的功能就是确定状态机的输出。
一般设计步骤如下:
- 根据需求选择状态机结构,即摩尔型还是米里型(可省)。
- 根据实际情况列出状态机的状态,并对每个状态编码,一般采用独热码(one-hot),即一个状态用一位表示。
- 根据状态转移关系画出状态转移图。
- 根据状态转移图,用HDL语言对状态机进行描述。
状态机的代码描述风格有三种:一段式、两段式、三段式。
- 一段式状态机:将所有的逻辑写在一个always块中,它的可读性比较差,不利于维护。
- 两段式状态机:将组合逻辑和时序逻辑分开,具有较好的可读性,相对容易维护,不过其组合逻辑输出易出现毛刺、竞争冒险等问题。
- 三段式状态机:除具有两段式的优点外,它对状态输出进行了寄存,能有效消除毛刺,因此推荐使用三段式状态机。
下面的设计实例就是一个三段式状态机控制LED灯实现流水。module led_loop(
input wire sclk,
input wire reset_n,
output reg [7:0] led_state
);端口定义不多说。parameter count=4'd10;
reg [3:0] clk_cnt;
reg clk_out;
always@(posedge sclk or negedge reset_n)
begin
if(!reset_n)
begin
clk_cnt<=4'd0;
clk_out<=1'b0;
end
else
begin
if(clk_cnt == count-1'b1)
begin
clk_cnt<=4'd0;
clk_out<=1'b1;
end
else
begin
clk_cnt<=clk_cnt+1'b1;
clk_out<=1'b0;
end
end
end这就是一个10个时钟周期的计数器,来实现延时,不作赘述,由于我用的是modelsim做的仿真,所以延时不宜过长。parameter idle = 8'b0000_0000;
parameter state_1 = 8'b0000_0001;
parameter state_2 = 8'b0000_0010;
parameter state_3 = 8'b0000_0100;
parameter state_4 = 8'b0000_1000;
parameter state_5 = 8'b0001_0000;
parameter state_6 = 8'b0010_0000;
parameter state_7 = 8'b0100_0000;
parameter state_8 = 8'b1000_0000;
reg [7:0] current_state,next_state;
always@(posedge sclk or negedge reset_n) //state transition
begin
if(!reset_n)
current_state<=idle;
else if(clk_out)
current_state<=next_state;
else
current_state<=current_state;
end这就是状态机的第一段,是一个同步时序电路,来实现状态切换,即先声明当前状态和下一时刻状态,然后在10个时钟周期后把下一时刻的状态赋予当前状态,若没到时间,即保持当前状态。注意复位只清除当前状态。本段描述的是状态切换的条件。always@(current_state)
begin
case(current_state)
idle: next_state=state_1;
state_1: next_state=state_2;
state_2: next_state=state_3;
state_3: next_state=state_4;
state_4: next_state=state_5;
state_5: next_state=state_6;
state_6: next_state=state_7;
state_7: next_state=state_8;
state_8: next_state=idle;
default: next_state=idle;
endcase
end这是状态机的第二段,本段为组合逻辑电路,采用阻塞赋值。case语句的条件是当前状态,根据当前状态找到下一状态,此段描述的是状态切换的内容。always@(posedge sclk or negedge reset_n)
begin
if(!reset_n)
led_state<=idle;
else if(clk_out)
case(next_state)
idle: led_state<=state_1;
state_1: led_state<=state_2;
state_2: led_state<=state_3;
state_3: led_state<=state_4;
state_4: led_state<=state_5;
state_5: led_state<=state_6;
state_6: led_state<=state_7;
state_7: led_state<=state_8;
state_8: led_state<=idle;
default: led_state<=idle;
endcase
else
led_state<=led_state;
end
endmodule这是状态机的第三段,本段是同步时序逻辑,case语句的条件是下一时刻的状态,然后根据下一时刻的状态来确定输出。本段描述的是有下一时刻的状态来确定输出。至此我们的三段式状态机已经设计完成。下面我们就要做一个testbench来测试状态机是否能正常工作,并实现相应的功能。这是测试程序。`timescale 1ns/1ns
module tb_led_loop;
reg tb_sclk,tb_reset_n;
wire [7:0] tb_led_state;
initial
begin
tb_sclk=0;
tb_reset_n=0;
#100
tb_reset_n=1;
end
always #10 tb_sclk<=~tb_sclk; //crystal oscillator
led_loop led_loop_inst(
.sclk(tb_sclk),
.reset_n(tb_reset_n),
.led_state(tb_led_state)
);
endmodule启动仿真是用tcl语言写的脚本自动仿真,尾缀为.do文件(如sim.do),当然你也可以是用GUI的方式。quit -sim
.main clear
vlib work
vlog ../sim/*.v
vlog ../rtl/*.v
vsim -t ns -voptargs=+acc work.tb_led_loop
add wave tb_led_loop/led_loop_inst/sclk
add wave tb_led_loop/led_loop_inst/reset_n
add wave tb_led_loop/led_loop_inst/clk_out
add wave tb_led_loop/led_loop_inst/current_state
add wave tb_led_loop/led_loop_inst/next_state
add wave tb_led_loop/led_loop_inst/led_state
run 100us然后再写一个批量处理文件,可以使.bat文件也可以是.cmd文件(如modelsim_ran.bat),不过要确保你的电脑环境变量设置里有modelsim.exe的目录,否则没法启动。bat文件就一行内容 modelsim -do sim.do 。不过要确保sim.do与modelsim_ran.bat文件同一目录下。然后双击bat文件即可自动启动仿真了。好像有点小bug,因为上电current_state默认是0,next_state默认是1,所以clk_out为高时,next_state就成了2,输出就变成了2,所以这就是为啥第一个周期led_state的第一个状态为2的原因。从第二个周期开始就正常了。要是有什么不对的地方还请大家指正,谢谢……
September 21, 2016
作者:dengshuai_super
出处:http://blog.csdn.net/dengshuai_super/article/details/52571372
声明:转载请注明作者及出处。
同步有限状态机的设计
1. 什么是有限状态机(FSM)
在FPGA里面做有限状态机的原因:因为FPGA都是并行处理的,想要做一些有前后顺序的事件处理的时候,我们就引入这种状态的机制。因此状态机在FPGA里面应用这么广。
在软件里面也是有状态机的思想,但是软件它是一个顺序执行的方法,所以状态机的存在显得不是那么重要了。
有限状态机是由寄存器组和组合逻辑构成的硬件时序电路;
其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态;
究竟转向哪一状态不但取决于各个输入值,还取决于当前状态。
状态机可用于产生在时钟跳变沿时刻开关的复杂的控制逻辑,是数字逻辑的控制核心。
2. FSM的种类和不同点
Mealy状态机:

带流水线输出的Mealy状态机:

有限状态机框图如下:


3. 设计举例

根据上图代码实现:
//ex_fsm.v
module ex_fsm(
input wire sclk,
input wire rst_n,
output reg k1,//输出的时候可以作为寄存器,它相当于把输出寄存器的
output reg k2,//Q端直接连接到输出口了,就把中间那根线给省略了
input wire A//状态
);
parameter IDLE = 4'b0001;//4'h1十六进制,状态少的时候最好显示的写出状态表达式
parameter START = 4'b0010;
parameter STOP = 4'b0100;
parameter CLEAR = 4'b1000;
//reg [1:0] state;
//2'b00 2'b01 2'b10 2'b11,二进制编码的时候用的寄存器数量少,但是用的组合逻辑资源较多
//if(state == 2'b11)比较器是2比特的
reg [3:0] state;
//4'b0001 4'b0010 4'b0100 4'b1000 独热码占用寄存器数量多,但是组合逻辑资源消耗较少
//if(state == 4'b0001)---->if(state[0]==1'b1)综合后把4比特的比较器优化成1比特的比较器,所以占用的组合逻辑资源较少
//对于二进制编码(多个比特表示一个状态),比特线有可能不一样长,导致延迟,出现中间状态,本来应该是111,可能中间状态是110等,(两边交错不稳定,使得数据存在不稳定区)因此在跑高速的时候可能出现数据采样窗变小,使得建立时间、保持时间的余量减少
//而独热码就不会出现这个问题,因为它用一个比特表示一个状态,从出发到结束就是一根线,不会出现中间状态,可以跑高速。
//两段式描述状态机
//第一段描述状态机,(状态机是时序逻辑)
always @(posedge sclk or negedge rst_n)//只对状态进行处理,不会写入其他变量赋值
if(rst_n == 1'b0)
state<=IDLE;//非阻塞赋值
else
case(state)
IDLE:if(A==1'b1)
state <=START;//时序电路,不加else自动保持原状态,因此可以不写
//else
//state <=state;
START:if(A==1'b0)
state <= STOP;//复位的时候回到IDLE,最上边的if那有相关代码
STOP:if(A==1'b1)
state <= CLEAR;
CLEAR:if(A==1'b0)
state <= IDLE;
default:state <= IDLE;
endcase
//控制变量输出
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
k1 <= 1'b0;
else if(state == IDLE && A == 1'b1)
k1 <= 1'b0;
else if(state == CLEAR && A == 1'b0)
k1 <= 1'b1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
k2 <= 1'b0;
else if(state ==STOP && A == 1'b1)
k2 <= 1'b1;
else if(state ==CLEAR && A == 1'b0)
k2 <= 1'b0;
endmodule
//tb_ex3_fsm.v
`timescale 1ns/1ns
module tb_ex3_fsm;
reg sclk,rst_n;
reg in_A;
wire k1,k2;
initial begin
sclk <= 0;
rst_n <= 0;
#100;
rst_n <=1;
end
initial begin
#200;
in_data();
end
always #10 sclk <=~sclk;
ex_fsm ex_fsm_inst(
.sclk (sclk),
.rst_n (rst_n),
.k1 (k1),//k1我上边没声明,但是综合的时候自动声明一个wire变量,不推荐
.k2 (k2),//k1,k2是输出,芯片画PCB时,输出的管脚都用线连
.A (in_A)//状态
);
task in_data();
integer i;
begin
for(i=0;i<1024;i=i+1)
begin
@(posedge sclk);
if(i<50)
in_A<=0;
else if(i<200)
in_A<=1;
else if(i<700)
in_A<=0;
else if(i<800)
in_A<=1;
else if(i<900)
in_A<=0;
end
end
endtask
endmodule
在Quartus II里面进行仿真设置后,点击EDA Netlist Writer后
在ex3/quartus_prj 里面多了一个Simulation文件夹,文件夹下有modelsim文件夹
该文件夹下有:
ex_fsm.sft
ex_fsm.vo//标准网标
ex_fsm_7_1200mv_125c_slow.vo//”125”指的是125度,分析建立时间,因为只有在信号传输地太慢了
ex_fsm_7_1200mv_125c_slow.sdo//,路径延时太大了的时候,才会建立时间的违例
ex_fsm_min_1200mv_-40c_fast.vo//用于建立时间的检查,数据传输的太快,使得数据太快的到达
ex_fsm_min_1200mv_-40c_v_fast.sdo//当上升沿之后,数据很快的结束了,没有办法保持住,因此用它来检查保持时间
ex_fsm_modelsim.xrf
ex_fsm_v.sdo//标准延时文件
//ex_fsm.vo里面调用了ex_fsm_v.sdo文件(initial $sdf_annotate(“ex_fsm_sdo”);)
//将ex_fsm_v.sdo放到ex_3/sim下(.sdo文件一定放到根目录,要不然找不到,就没有延时信息)
//将ex_fsm.vo放到ex_3/design下
//仿真的时候,ex_fsm.vo里面调用了Altera FPGA里面的东西。因此需要加进来一些库文件。
//库文件在哪里找:打开Quartus II安装目录下:QuartusII13.1/quartus/eda/sim_lib下把alter_mf.v拷贝到ex_3/sim目录下的新建的文件夹altera_lib下。
打开modelsim,在Project标签页下把ex_fsm.v移除,加入ex_3/design/ex_fsm.vo文件
再加一个库文件ex_3/sim/altera_lib/altera_mf.v
共三个文件:altera_mf.v,ex_fsm.vo,tb_ex_fsm.v
修改编译顺序:compile—>compile order—>altera_mf.v(调到第一个)
出现错误是因为刚才把ex_3/sim/work(库) 删了
因此新建一个库,在最下方输入命令:
vilb work
在Library 标签页下,找到tb_ex_fsm—>右键Simulate without Optimization启动
有错误,需要加其它组件(cycloneive_io_obuf … not found…)
在QuartusII13.1/quartus/eda/sim_lib把cycloneive_atoms.v加到ex_3/sim/altera_lib下,
然后在modelsim的Project标签页下,加入cycloneive_atoms.v
编译
在Library标签页下,右键tb_ex_fsm启动仿真
出现错误:“dffeas …not found…”
然后在QuartusII13.1/quartus/eda/sim_lib把altera_primitives.v(原语)按同样方式加入到ex_3/sim/altera_lib下,然后在modelsim的Project标签页下,加入altera_primitives.v
编译,成功。
发现寄存的信号和时钟不同不了,事件都有延时了。(后仿里面的东西)
练习:检测10010这个序列作为练习,画出状态迁移图。
来源:
https://ke.qq.com/user/index/index.html#cid=66019&term_id=100056181
本随笔需要不断完善,姑且先写这一点点。。。。。。。
1、所谓同步有限状态机是是电路状态的变化只能在同一时钟跳变沿时刻发生的逻辑电路。
2、组合逻辑:组合逻辑是由与或非门组成的网络。
3、时序逻辑:时序逻辑是有多个触发器和多个组合逻辑块组成的网络。
转载于:https://www.cnblogs.com/qidaiymm/p/4889047.html
本系列主要针对有限状态机进行分析和设计,其中主要包括两部分:时钟同步状态机的分析和时钟同步状态机的设计,预计会有五篇文章进行展开,其中介绍一篇,分析和设计分别有两篇,每一部分都会有相应的实例。
文章目录
‘SHIT’上最全有限状态机设计研究(一)-状态机介绍
‘SHIT’上最全有限状态机设计研究(二)-时钟同步状态机分析1
‘SHIT’上最全有限状态机设计研究(三)-时钟同步状态机分析2
‘SHIT’上最全有限状态机设计研究(四)-时钟同步状态机设计1
‘SHIT’上最全有限状态机设计研究(五)-时钟同步状态机设计2
时钟同步状态机分析Clocked Synchronous State Machine Analysis
2.1时钟同步状态机的描述
图3 时钟同步状态机的组成框图
其中,
组合逻辑电路包括:
激励=F(当前状态,输入)<–激励方程
输出=G(当前状态,输入)<–输出方程
状态转移:从Q到Q*
图4 状态机举例
2.2时钟同步状态机的分析
分析大致遵从如下步骤:
1)进行电路描述,得到激励方程、输出方程、转移方程;
2)构建转移/输出表(或状态转移图),描述电路功能。
如下图所示的状态图:
第一步,写出激励方程:
D0 = EN·Q0’ + EN’ ·Q0
D1 = EN’ ·Q1 + EN·Q1’·Q0 + EN·Q1·Q0’
第二步,写出输出方程:MAX= EN·Q1·Q0
第三步,写出转移方程:MAX= EN·Q1·Q0
D触发器特征方程:Q0 = D0, Q1 = D1
将激励方程带入触发器的特征方程,得
Q0 = EN·Q0’ + EN’·Q0
Q1 = EN’·Q1 + EN·Q1’·Q0 + EN·Q1·Q0第四步,写出状态转移表:
转移表实质就是真值表,由转移表和状态表组成。
第4(1)步,转移表
由状态转移方程很好得到,从中可以看出:当EN=0保持原状态,当EN=1时表示当前变量+1操作,所以这是一个2 bit的加法计数器:
第4(2)步,状态表:
状态表和转移表的区别就是,转移表是利用状态变量的取值进行表示,状态表利用状态的变量名进行表示:
第4(3)步,状态转移表:状态表和转移表合成就是状态转移表。
带使能端的2-bit二进制计数器 ( mealy machine )
第五步,构建状态转移图:
状态转移图,圈圈表示状态,箭头表示状态转移,箭头上标注转移和输出信息。
MAX= EN·Q1·Q0
D触发器特征方程: Q0* = D0, Q1* = D1
将激励方程带入触发器的特征方程,得
Q0* = EN·Q0’ + EN’·Q0
Q1* = EN’·Q1 + EN·Q1’·Q0 + EN·Q1·Q
欢迎大家订阅我的公众号,关于FPGA相关资料和新闻我会第一时间更新到公众号中,谢谢大家!