谈 verilog 有限状态机设计——FPGA的灵魂

总结来自 《搭建你的数字积木 数字电路与逻辑设计 》 一书 有空大家可以去看看原书

简介

有限状态机(FSM)是fpga的灵魂,能够使得FPGA并行处理的基础上实现和CPU一样的串行处理效果,一样的灵活。同时相比CPU有一下的特性:
(1)高效的顺序控制模型
(2)容易利用现成的EDA工具进行优化设计
(3)性能稳定,解决大规模集成电路的竞争和冒险,可以消除电路毛刺,强化系统功能
(4)高速性能,结合和FPGA的高速优势
(5)高可靠性,和CPU相比不需要繁杂的取指、译码、执行等过程

理论基础

FSM中有两类状态机需要理解,一种叫做Mealy状态机、一种叫做Moore状态机。
经典的FSM是由组合逻辑状态寄存器构成,组合逻辑负责逻辑计算,状态寄存器负责状态的转换。
经典状态机图

Mealy和Moore的区别在于输出和输入的关系不同
Mealy的输出是由当前的状态和输入决定的。

Mealy状态机框图0
Moore的输出只是由当前的状态决定的,与输入无关

Moore状态机框图
简单的来说Moore输出直接由状态来决定,Mealy输出还需要由输入决定。

有限状态机表示图
上图a为状态转移图,b为具体的ASM内部转换图,可以看出a和b为输入,y0和y1为输出,S0、S1、S2为对应状态。读图可以看到y1只和当前的状态有关,所以y1为Moore输出,而y0和b的值有关,所以y0为Mealy输出。

代码实现

每种状态机首先需要使用一个符号常量来表示有限状态机的状态
符号常量的赋值编码也是有一定讲究的,详细参考这篇博客
二进制码、格雷码、独热码 等编码方式在状态机中的运用
该代码实现了上面ASM转换(代码手打的可能有错误)

module fsm(
    input   clk,
    input   reset,
    input   a,
    input   b,
    output  y0,
    output  y1 
);
//符号常量表示有限状态机的状态
localparam [1:0]s0 = 2'b00;
localparam [1:0]s1 = 2'b01;
localparam [1:0]s2 = 2'b10; 
reg[1:0]state_reg,state_next;
//一个always模块采用组合逻辑判断状态转移
always @(posedge clk or negedge reset) begin
    if(reset)
    state_reg<=s0;
    else
    state_reg<=state_next;
end
//一个always模块采用组个逻辑判断转移条件,描述状态转移规律
always @ (*)
case (state_reg)
    s0:if(a)
            if(b)
                state_next = s2;
            else
                state_next = s1;
        else
            state_next=s0;
    s1:if(a)
            stste_next = s0;
        else
            stste_next = s1;
    s2: stste_next=s0;

    default:stste_next=s0;
endcase
//一个always模块描述状态输出
// Moore 型逻辑输出
assign y1 = (state_reg == s0)||(state_reg == s1);
// Mealy 型逻辑输出
assign y0 = (stste_reg == s0)&a&b;
endmodule 

状态机的类型

状态机的代码一般可以使用一段式状态机、两段式状态机、三段式状态机来表示。
(1)一段式:
一个always模块里面,既有描述状态转移,又有描述状态输入和输出
(2)二段式:
一个always模块采用同步时序描述状态转移
一个always模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出
(3)三段式:
一个always模块采用组合逻辑判断状态转移
一个always模块采用组个逻辑判断转移条件,描述状态转移规律
一个always模块描述状态输出(可以用组合逻辑电路输出,也可以用时序电路输出)

注意:不是通过数always来判断是几段式状态机,比如上面的代码是两组always和一组assign,后面一组assign表示输出规律,所以仍然属于三段式状态机

使用一段式状态机修改上面的三段式状态机代码(代码手打的可能有错误):

module fsm (
    input   clk,
    input   reset,
    input   a,b,
    output reg y0,y1 

);

localparam [1:0]s0 = 2'b00,s1 = 2'b01,s2 = 2'b10; //符号常量表示有限状态机的状态\
reg[1:0]state_reg;


//一个always模块里面,既有描述状态转移,又有描述状态输入和输出
always @(posedge clk or negedge reset) begin
    if(!reset)begin
        state_reg<=s0;
        y0<=0;
        y1<=0;
    end
    else begin
        y0<=0;
        y1<=0;
        case(state_reg)
        s0:begin
            y1<=1;
            if(a)
                if(b)begin
                    y0<=1;
                    state_reg<=s2;
                end
                else begin
                    state_reg<=s1;
                end
            else
                state_reg<=s0;
        end
        s1:begin
            y1<=1;
            if(a)
                state_reg<=s0;
            else
                state_reg<=s1;
        end
        s2:begin
            state_reg<=s0;
        end
        
        default:stste_next=s0;
        endcase
    end
end
endmodule 

再使用两段式状态机修改最上面的三段式状态机代码(代码手打的可能有错误):

module fsm(
    input   clk,
    input   reset,
    input   a,b,
    output reg y0,y1 
);

localparam [1:0]s0 = 2'b00,s1 = 2'b01,s2 = 2'b10; //符号常量表示有限状态机的状态\
reg[1:0]state_reg,state_next;

//一个always模块采用同步时序描述状态转移
always @(posedge clk or negedge reset) begin
    if(!reset)
        state_reg <= s0;
    else
        state_reg <= state_next;
end

//一个always模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出
always @(*) begin
    case(state_reg)
    state_next = state_reg;
    y0 = 0;
    y1 = 0;
    s0:begin
        y1 = 1;
        if(a)
            if(b)begin
                state_next = s2;
                y0 = 1;
            end
            else
                stste_next = s1;       
    end
    s1:begin
        y1 = 1;
        if(a)
            state_next = s0;
    end
    s2:state_next = s0;

    default : state_next = s0;
        
    endcase
end
endmodule 

上面完整的展示了一段 二段 三段状态机,接着评价这三种状态机的优缺点:

一段式状态机:
只有一个always块,结构简单,看起来简洁,直白,但是这种适用于状态简单的有限状态机,主要状态复杂了,逻辑部分就有可能出错,而且不易维护。
两段式状态机:
不利于阅读、理解、维护代码,在第二个组合逻辑输出时,可能存在竞争和冒险,因而产生毛刺。
三段式状态机:
代码容易维护,用时序逻辑输出可以解决两段式组合逻辑产生的毛刺问题,但是从资源消耗的角度来说,三段式资源消耗多。综合与布局布线效果也更佳。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值