由于寄存器传输级(RTL)描述的是以时序逻辑抽象所得到的有限状态机为依据,因此,把一个时序逻辑抽象成一个同步有限状态机是设计可综合风格的Verilog HDL模块的关键。
在本章节中,在了解状态机结构的基础上通过各种实例,由浅入深地介绍各种可综合风格的Verilog HDL模块,并把重点放在时序逻辑的可综合有限状态机的Verilog设计要点上。
1,介绍Mealy型状态机和Moore型状态机的两种结构
Mealy型状态机和Moore型状态机的区别:
1,Mealy型状态机的输出,与当前状态和输入函数有关;
2,Moore型状态机的输出,只与当前状态有关;
这两种电路结构除了在输出电路部分有些不同外,其他地方都是相同的。在实际设计工作中,其实大部分状态机都属于Mealy状态机,因为状态机的输出中或多或少有几个属于Mealy型输出,输出不但与当前状态有关还与输入有关;还有几个输出属于Moore型状态机,即只与当前状态有关。
2,设计高速电路的方法
在设计高速电路时,常常有必要使状态机的输出与时钟几乎完全同步。
1,有一个办法是把状态变量直接用作输出,为此在指定状态编码时需要多费一些脑力,也可能会多用几个寄存器。
这种设计思路,在高速状态机电路时常常使用,这称为输出编码的状态指定。
这种状态机属于 图2 的Moore型状态机
2,另一个办法,是如图3所示,在输出逻辑G后面再加一组与时钟同步的寄存器输出流水线寄存器,让G所有的输出信号在下一个时钟跳变沿同时存入寄存器组,即完全同步地输出,把这种输出称为流水线化的输出。
这种状态属于 图3 的带流水线输出的Mealy状态机
其实,在这几种状态机之间,只要做一些改变,便可以从一种形式转变为另一种形式。比如可以将图3所示的状态机中产生流水输出的寄存器省去,把这些寄存器用在状态记忆上,就可以很容易地得到一个把状态机变量用作输出信号的Moore型状态机。
状态机的分类不重要,重要的是设计者如何把握输出的结构能满足设计的整体目标,包括定时的准确性和灵活性。
3,用Verilog来描述可综合的状态机
在Verilog HDL中可以用许多种方法来描述有限状态机,最常用的方法是用
always语句
和case语句
。如3.1节所示的状态转移图表示了一个简单的有限状态机。
3.1,状态转移图
3.2,用可综合Verilog模块设计、用gray码表示状态机
3.2.1,RTL代码设计
// 用有限状态机编写可综合Verilog模块设计状态机,gray码
module fsm1(
input i_clk,
input i_rst,
input i_a,
output reg [1:0] state,
output reg k2,
output reg k1
);
parameter idle = 2'b00;
parameter start = 2'b01;
parameter stop = 2'b10;
parameter clear = 2'b11;
always@(posedge i_clk)
if(!i_rst) begin
state <= idle;
k2 <= 0;
k1 <= 0;
end
else
case(state)
idle: if(i_a) begin
state <= start;
k2 <= 0;
k1 <= 0;
end
else begin
state <= idle;
k2 <= 0;
k1 <= 0;
end
start: if(!i_a) begin
state <= stop;
k2 <= 0;
k1 <= 0;
end
else begin
state <= start;
k2 <= 0;
k1 <= 0;
end
stop:
if(i_a) begin
state <= clear;
k2 <= 1;
k1 <= 0;
end
else begin
state <= stop;
k2 <= 0;
k1 <= 0;
end
clear:
if(!i_a) begin
state <= idle;
k2 <= 0;
k1 <= 1;
end
else begin
state <= clear;
k2 <= 1;
k1 <= 0;
end
default:
state <= 2'bxx;
endcase
endmodule
3.2.2,tb、测试代码(下方所有测试代码tb都是这个tb)
// 测试信号
module tb_fsm;
reg i_a;
reg i_clk;
reg i_rst;
wire [1:0] state;
wire k2;
wire k1;
initial begin // initial 常用于仿真时信号的给出
i_a = 0;
i_rst = 1; // 给复位信号变量赋初始值
i_clk = 0; // 给时钟变量赋初始值
#22
i_rst = 0; // 使复位信号有效
#133
i_rst = 1; // 经过一个多周期后使复位信号无效
end
always #50 i_clk = ~i_clk; // 产生周期性的时钟
always@(posedge i_clk) begin // 在每次时钟正跳变沿时刻产生不同的 i_a
#30 i_a = {$random}%2; // 每次 i_a 是 0 还是 1 是随机的
#(3 * 50 + 12); // i_a 的值维持一段时间
end
initial begin
#100000
$stop;
end
fsm1 u1_fsm1(
.i_clk (i_clk ),
.i_rst (i_rst ),
.i_a (i_a ),
.k2 (k2 ),
.k1 (k1 ),
.state (state )
);
endmodule
3.2.3,原理图
3.2.4,综合后的结果
3.2.5,SIM输出波形
3.3,用可综合的Verilog模块设计、用独热码表示状态的状态机
比较gray码和独热码的区别:
对于FPGA实现的有限状态机建议采用独热码
,虽然独热码多用了两个触发器,但所用组合电路可省一些,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。
采用独热码后,有了多余的状态,就有些不可到达的状态。为此,在case语句的最后需要增加default分支项。这可以用默认项表示该项,也可以用确定项表示,以确保回到idle状态。一般综合器都可以通过综合指令的控制来合理地处理默认项。
3.3.1,RTL代码设计
// 用可综合的Verilog模块设计、用独热码表示状态的状态机
module fsm2(
input i_clk,
input i_rst,
input i_a,
output reg k1,
output reg k2,
output reg [3:0] state
);
parameter idle = 4'b1000;
parameter start = 4'b0100;
parameter stop = 4'b0010;
parameter clear = 4'b0001;
always@(posedge i_clk)
if(!i_rst) begin
state <= idle;
k2 <= 0;
k1 <= 0;
end
else
case(state)
idle: if(i_a) begin // 1
state <= start;
k2 <= 0;
k1 <= 0;
end
else begin
state <= idle;
k2 <= 0;
k1 <= 0;
end
start: if(!i_a) state <= stop; // 0
else state <= start;
stop: if(i_a) begin // 1
state <= clear;
k2 <= 1;
k1 <= 0;
end
else begin
state <= stop;
k2 <= 0;
k1 <= 0;
end
clear: if(!i_a) begin // 0
state <= idle;
k2 <= 0;
k1 <= 1;
end
else begin
state <= clear;
k2 <= 1;
k1 <= 0;
end
default:
state <= idle;
endcase
endmodule
3.3.2,原理图生成
3.3.3,综合后结果
3.3.4,SIM输出波形图
3.4,用可综合的Verilog模块设计、由输出指定码表示状态机,图3
在前面状态机结构部分讲过的,把输出直接指定为状态码,也就是把状态码的指定与状态机控制的输出联系起来,把状态的变化直接用作输出,这样就可以提高输出信号的开关速度并节省电路器件。
但这种方法的缺点是开关的维持时间必须与状态维持的时间一致,如果要完全实现
3.2小节
和3.3小节
的开关输出波形,需要增加状态才能实现。这种设计方法常用作在高速状态机中,建议在设计高速状态机时采用3.4小节
的编写风格。
3.4.1,RTL代码设计
// 用可综合的Verilog模块设计、由输出指定的码表示状态的状态机
module fsm3(
input i_clk,
input i_rst,
input i_a,
output k2,
output k1,
output reg [4:0] state
);
assign k2 = state[4]; // 把状态变量的最高位用作输出 k2
assign k1 = state[0]; // 把状态变量的最低位用作输出 k1
parameter idle = 5'b0_0000;
parameter start = 5'b0_0010;
parameter stop = 5'b0_0100;
parameter stop2clear = 5'b1_1000;
parameter clear = 5'b0_1010;
parameter clear2idle = 5'b0_0111;
always@(posedge i_clk) begin
if(!i_rst)
state <= 0;
else begin
case(state)
idle: if(i_a)
state <= start;
else
state <= idle;
start: if(!i_a)
state <= stop;
else
state <= start;
stop: if(i_a)
state <= stop2clear;
else
state <= stop;
stop2clear: state <= clear;
clear: if(!i_a)
state <= clear2idle;
else
state <= clear;
clear2idle:
state <= idle;
default:
state <= idle;
endcase
end
end
endmodule
3.4.2,原理图生成
3.4.3,综合后结果
3.4.4,SIM输出波形图
3.5,用可综合的Verilog模块设计复杂的多输出状态机时常用方法
在比较复杂的状态机设计过程中,往往把状态的变化与输出开关的控制分成两部分来考虑
,就像前面讲过的Mealy状态机输出部分的组合逻辑。为了调试方便,还常常把每一个输出开关写成一个个独立的always组合块。在调试多输出状态时,这样做比较容易发现问题和改正模块编写中出现的问题。建议在设计复杂的多输出状态机时采用 3.5小节 的编码风格
3.5.1,RTL代码设计
// 可综合的 Verilog 模块设计复杂的多输出状态机时常用的方法
module fsm4(
input i_clk,
input i_rst,
input i_a,
output reg k2,
output reg k1,
output reg [1:0] state
);
reg [1:0] nextstate;
parameter idle = 2'b00;
parameter start = 2'b01;
parameter stop = 2'b10;
parameter clear = 2'b11;
// 每一个时钟沿产生一次可能得状态变化
always@(posedge i_clk)
if(!i_rst)
state <= idle;
else
state <= nextstate;
// 产生下一个状态的组合逻辑
always@(state or i_a)
case(state)
idle: if(i_a)
nextstate = start;
else
nextstate = idle;
start: if(!i_a)
nextstate = stop;
else
nextstate = start;
stop: if(i_a)
nextstate = clear;
else
nextstate = stop;
clear: if(!i_a)
nextstate = idle;
else
nextstate = clear;
default: nextstate = 2'bxx;
endcase
// 产生输出 k1 的组合逻辑
always@(state or i_rst or i_a)
if(!i_rst)
k1 = 0;
else begin
if(state == clear && !i_a) // 从 clear 转向 idle
k1 = 1;
else
k1 = 0;
end
// 产生输出 k2 的组合逻辑
always@(state or i_rst or i_a)
if(!i_rst)
k2 = 0;
else begin
if(state == stop && i_a) // 从 stop 转向 clear
k2 = 1;
else
k2 = 0;
end
endmodule
3.5.2,原理图生成
3.5.3,综合后结果
3.5.4,SIM输出波形图
3.6,总结有限状态机设计的一般步骤
3.2节、3.3节、3.4节、3.5节是同一状态机的4种不同的Verilog模型,它们都是可综合的,在设计复杂程度不同的状态机时,有它们各自的优势。如用不同的综合器对这个不同的Verilog模型进行综合,综合出的逻辑电路可能会有些不同,但是逻辑功能是相同的。
有限状态机设计的一般步骤:
1,逻辑抽象,得出状态转换图。
就是把给出的一个实际逻辑关系表示为时序逻辑函数,可以用状态转换表来描述,也可以用状态转换图来表示,这就需要:
(1)分析给定的逻辑问题,确定输入变量、输出变量以及电路的状态数。通常是取原因(或条件)作为输入变量,取结果作为输出变量。
(2)定义输入、输出逻辑状态的含义,并将电路状态顺序编号。
(3)按照要求列出电路的状态转换表或画出状态转换图。
至此,就把给定的逻辑问题抽象成一个时序逻辑函数了。
2,状态化简。
如果在状态转换图中出现这样两个状态,它们在相同的输入下转换到同一状态去,并得到一样的输出,则称为等价状态。显然等价状态是重复的,可以合并为一个。电路的状态数越少,存储电路也就越简单。状态化简的目的就在于将等价状态尽可能地合并,进而得到最简的状态转换图。
3,状态分配。
状态分配又称为状态编码。通常有很多编码方法,编码方案选择得当,设计的电路可以简单;反之,选得不好,则设计的电路就会复杂许多。在实际设计时,须综合考虑电路复杂度与电路性能之间的折中。在触发器资源丰富的FPGA
或ASIC
设计中,采用独热编码既可以使电路性能得到保证又可充分利用其触发器数量多的优势,也可以采取输出编码的状态指定来简化电路结构,并提高状态机的运行速度。
4,选定触发器的类型并求出状态方程、驱动方程和输出方程。
5,按照方程得出逻辑图。
用Verilog HDL来描述有限状态机,可以充分发挥硬件描述语言的抽象建模能力,使用always块语句和case(if)等条件语句及赋值语句即可方便实现。具体的逻辑化简、逻辑电路到触发器映射均可由计算机自动完成。文章来源:https://www.toymoban.com/news/detail-799115.html
上述设计步骤中的第(2)、(4)、(5)步不再需要很多的人为干预,使电路设计工作得到简化,效率也有很大的提高。
文章来源地址https://www.toymoban.com/news/detail-799115.html
到了这里,关于12-同步状态机的结构以及Mealy和Moore状态机的区别,Verilog实现有限状态机的4种方式,以及总结有限状态机设计的一般步骤的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!