知识点:
状态寄存器由 n 个触发器组成,则最多可以记忆 2n 个状态
状态机可以分为 Mealy 状态机和 Moore 状态机:
如果时序逻辑的输出不但取决于状态还取决于输入,称为 Mealy 状态机
![[1689141969116.png]]
如果时序逻辑的输出只取决于状态,而不取决于输入,称为 Moore 状态机
![[1689141934053.png]]
(流水线寄存器:在输出逻辑 G 后面再加一组与时钟同步的寄存器输出流水线寄存器《Verilog 数字系统设计教程·第四版·夏宇闻》P 167)
目前大多数综合器往往不支持在一个 always 模块中由多个事件触发的状态机(即隐含状态机)
为了能综合出有效的电路,由 Verilog HDL 描述的状态机应明确地由唯一时钟触发。如果非要使用不同时钟触发的模块,可以使用几个 always,并在每一个 always 中赋予的时钟信号不同切有一定的关联性
状态机的设置问题
状态必须明确赋值,通常使用参数(parameters)或宏定义(define)语句加上赋值语句来实现
前面所介绍的数据选择器、比较器、加法器、计数器等,都只是实现某种单一的特定功能,因此称为功能部件级电路,将几者结合起来即可组成复杂的数字系统。
通常使用状态图或者状态表描述只有几个输入输出的电路称为有限状态机(Finite State Machine,简称 FSM),而对于更为复杂的数字系统,使用 FSM 过于复杂,因此提出了算法状态机(Algorithmic State Machine,简称 ASM)(《电子技术基础·数字部分·康华光》第六版 P 481)
描述 FSM 的转换过程,有三种方法:3 段式、2 段式、1 段式。其中 3 段式是处理复杂状态机时最推荐的
0)首先,根据状态机的个数确定状态机编码。(利用编码给状态寄存器赋值,代码可读性更好)
1)状态机第一段,时序逻辑,非阻塞赋值,传递寄存器的状态(描述各个状态之间是怎么转换的)
2)状态机第二段,组合逻辑,阻塞赋值,根据当前状态和当前输入,确定下一个状态机的状态(描述每一个状态下应该要做什么事情)
3)状态机第三段,输出的定义。(对于描述 Mealy 状态机,使用时序逻辑,非阻塞赋值,因为是 Mealy 型状态机,根据当前状态和当前输入,确定输出信号;对于描述 Moore 状态机,使用组合逻辑,直接使用 assign 语句或者 always 模块即可)
2 段式是在 3 段式的基础上,将第 2、3 部分结合为一个部分,则只剩下了两段(第 0 段视作准备部分,并不算作一段);1 段式则是将第 1、2、3 部分结合为一个部分。不难得出,在面对复杂逻辑时,3 段式更加分明、清晰;而对于简单逻辑时,1 段式更加简单、明了
流水线:流水线的基本思想是:把一个重复的过程分解为若干个子过程,每个子过程由专门的功能部件来实现。将多个处理过程在时间上错开,依次通过各功能段,这样每个子过程就可以与其他子过程并行进行
同步复位、异步复位:
同步复位:复位信号在时钟有效边沿到来时有效。如果时钟激励,无论复位信号怎样变化,电路也不会执行复位。
同步复位的优点:信号间是同步的,能滤除复位信号中的毛刺,有利于时序分析。
同步复位的缺点:大多数触发器单元是没有同步复位端的,采用同步复位会多消耗部分逻辑资源。且复位信号的宽度必须大于一个时钟周期,否则可能会漏掉复位信号。(B 站)
异步复位:无论时钟到来与否,只要复位信号有效,电路就会执行复位操作。
异步复位的优点:大多数触发器单元有异步复位端,不会占用额外的逻辑资源。且异步复位信号不经过处理直接引用,设计相对简单,信号识别快速方便。
异步复位的缺点:复位信号与时钟信号无确定的时序关系,异步复位很容易引起时序上 removal 和 recovery 的不满足。且异步复位容易受到毛刺的干扰,产生意外的复位操作。(B 站)
ASM 算法状态机有三种基本符号:状态框、判断框、输出框(《电子技术基础·数字部分·康华光》第六版 P 491)
但是基于算法的行为级描述是最抽象的,用类似于编程语言的过程算法形式描述系统的功能,不涉及任何硬件电路的实现。因此,这一层设计的某些描述不能被开发软件综合成具体结构形式,故常用于复杂数字系统的仿真,用来证明设计是否正确。
实例题目:
序列检测器
例 1.1 设计一个序列检测器电路当检测出串行输入数据 Data 中的 4 位二进制序列 0101(自左至右输入),当检测到该序列时,输出 Out 为 1,没有检测到该序列时,输出 Out 为 0,并在 SparkRoad 上实现。
(点评与想法: )
解:
Verilog 代码实现如下:
module xulie(
input data,
input clk,reset, //reset是复位,当reset=1时,回归最初状态
output reg out
);
reg [1:0]state,state_n;
parameter s0=2'b00,s1=2'b01,s2=2'b10,s3=2'b11;
always@(posedge clk)begin
if(reset)begin
state<=s0;
end
else begin
state<=state_n;
end
end
always@(state,data)begin
case(state)
s0:begin
out=0;
state_n=(data==1)?s0:s1;
end
s1:begin
out=0;
state_n=(data==1)?s2:s1;
end
s2:begin
out=0;
state_n=(data==1)?s0:s3;
end
s3:begin
if(data)begin
state_n=s2;
out=1;
end
else begin
state_n=s1;
out=0;
end
end
endcase
end
endmodule
Testbench 代码实现如下:
`timescale 1ns/1ps
module xulie_tb;
reg clk,data,reset;
wire out;
initial begin
data=1'b0;
clk=1'b0;
reset=1'b1;
end
always@(*)begin
forever begin
#50 clk<=~clk;
end
end
always@(posedge clk)begin
#20 reset=1'b0;
#26 data=1'b0;
#51 data=1'b1;
#101 data=1'b0;
#101 data=1'b1;
#101 data=1'b0; //顺利检测并输出1
#101 data=1'b1;
#101 data=1'b0;
#825 data=1'b0;
#925 data=1'b1; //序列并不满足,输出为0
#1025 data=1'b0;
#1125 data=1'b1;
#1225 data=1'b0;
#1325 reset=1'b1;
#1425 data=1'b1; //reset在过程中为1,输出为0
#1525 reset=1'b0;
end
xulie xulie_tb_1(
.data(data),
.clk(clk),
.reset(reset),
.out(out)
);
endmodule
仿真波形如下:
![[1689163972130.png]]
例 1.2 创建带有一个输入的计时器:当检测到特定输入模式 (1101) 时启动,再移 4 位以确定延迟的持续时间,等待计数器完成计数,并且通知用户并等待用户确认,并在 SparkRoad 上实现。
(点评与想法: 出自 Hdlbits 上的 The complete timer )
解:
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
parameter idle = 0, s1 = 1, s2 = 2, s3 = 3, b0 = 4, b1 = 5;
parameter b2 = 6, b3 = 7, counts = 8, waiting = 9;
reg [3:0] state, next_state;
reg [9:0] counter;
always @(*) begin
case (state)
idle: next_state = data ? s1 : idle;
s1: next_state = data ? s2 : idle;
s2: next_state = data ? s2 : s3;
s3: next_state = data ? b0 : idle;
b0: next_state = b1;
b1: next_state = b2;
b2: next_state = b3;
b3: next_state = counts;
counts: next_state = (count == 0 && counter == 999) ? waiting : counts;
waiting:next_state = ack ? idle : waiting;
endcase
end
always @(posedge clk) begin
if (reset) begin
count <= 0;
counter <= 0;
end
else begin
case (state)
b0: count[3] <= data;
b1: count[2] <= data;
b2: count[1] <= data;
b3: count[0] <= data;
counts: begin
if (count >= 0) begin
if (counter < 999) begin
counter <= counter + 1;
end
else begin
count <= count - 1;
counter <= 0;
end
end
end
default: counter <= 0;
endcase
end
end
always @(posedge clk) begin
if (reset) begin
state <= idle;
end
else begin
state <= next_state;
end
end
assign counting = (state == counts);
assign done = (state == waiting);
endmodule