共计 3832 个字符,预计需要花费 10 分钟才能阅读完成。
⭐本专栏针对 FPGA 进行入门学习,从数电中常见的逻辑代数讲起,联合 Verilog HDL 语言学习与仿真,次要对组合逻辑电路与时序逻辑电路进行剖析与设计,对状态机 FSM 进行分析与建模。
🔥文章和代码已归档至【Github 仓库:hardware-tutorial】,须要的敌人们自取。或者关注公众号【AIShareLab】,回复 FPGA 也可获取。
状态图的建设过程
设计一个序列检测器电路。性能是检测出串行输出数据 Sin 中的 4 位二进制序列 0101(自左至右输出),当检测到该序列时,输入 Out=1;没有检测到该序列时,输入 Out=0。(留神思考序列重叠的可能性,如 010101,相当于呈现两个 0101 序列)。
解:首先,确定采纳米利型状态机设计该电路。因为该电路在间断收到信号 0101 时,输入为 1,其余状况下输入为 0,所以采纳米利型状态机。
其次,确定状态机的状态图。依据设计要求,该电路至多应有四个状态,别离用 S1、S2、S3、S4 示意。若假如电路的初始状态用 S0 示意,则可用五个状态来形容该电路。依据剖析,能够画出图 (a) 所示的原始状态图。
察看该图能够看出,S2、S4 为等价状态,可用 S2 代替 S4,于是失去简化状态图。
而后,依据下面的状态图给出该状态机的输入逻辑。该状态机只有一个输入变量 Out,其输入逻辑非常简单,间接标注在状态图中了。若输入变量较多,则能够列出输入逻辑真值表。
最初,就能够应用硬件描述语言对状态图进行形容了。
状态图形容办法
利用 Verilog HDL 语言形容状态图次要蕴含四局部内容:
-
利用参数定义语句 parameter 形容状态机中各个状态的名称,并指定状态编码。例如,对序列检测器的状态调配能够应用最简略的天然二进制码,其形容如下:
parameter S0=2'b00, S1=2'b01, S2 = 2'b10, S3 = 2'b11;
或者,
parameter [1:0] S0=2'b00, S1=2'b01, S2 = 2'b10, S3 = 2'b11;
- 用时序的 always 块形容状态触发器实现的状态存储。
- 应用敏感表和 case 语句 (也能够采纳 if-else 等价语句) 形容的状态转换逻辑。
- 形容状态机的输入逻辑。
形容状态图的办法多种多样,上面介绍几种:
单个 always 块形容状态机的办法(尽量避免)
用一个 always 块对该例的状态机进行形容,其代码如下:
module Detector1 (Sin, CP, nCR, Out) ; | |
input Sin, CP, nCR; // 申明输出变量 | |
output Out ; // 申明输入变量 | |
reg Out; | |
reg [1:0] state; | |
// 申明两个状态触发器变量 state[1]和 state[0],记忆电路现态 | |
//The state labels and their assignments | |
parameter [1:0] S0=2'b00, S1=2'b01, S2 = 2'b10, S3 = 2'b11; | |
always @(posedge CP or negedge nCR) | |
begin | |
if (~nCR) | |
state <= S0; // 在 nCR 跳变为 0 时,异步清零 | |
else | |
case(state) | |
S0: begin Out =1’b0; state <= (Sin==1)? S0 : S1; end | |
S1: begin Out = 1’b0; state <= (Sin==1)? S2 : S1; end | |
S2: begin Out = 1’b0; state <= (Sin==1)? S0 : S3; end | |
S3: if (Sin==1) begin Out =1’b1; state <= S2; end | |
else | |
begin Out =1’b0; state <= S1; end | |
endcase | |
end | |
endmodule |
严格地说,对序列检测器电路用单个 always 块的形容办法所形容的逻辑存在着一个隐含的谬误,即输入信号 Out 的形容。
case 语句中对输入向量的赋值应是下一个状态输入,这点易出错;状态向量与输入向量都由寄存器实现,面积大,不能实现异步米勒状态机。因而,单个 always 块形容状态机的写法仅仅实用于穆尔型状态机。单个 always 块写法的电路构造框图能够用下图进行概括。
两个 always 块形容状态机的办法(举荐写法!)
用两个 always 块对该例的状态机进行形容,其代码如下:
module Detector2 (Sin, CP, nCR, Out) ; | |
input Sin, CP, nCR; // 定义输出变量 | |
output Out ; // 定义输入变量 | |
reg Out; | |
reg [1:0] Current_state, Next_state; | |
parameter [1:0] S0=2'b00, S1=2'b01, S2 = 2'b10, S3 = 2'b11; | |
// 状态转换,时序逻辑 | |
always @(posedge CP or negedge nCR) | |
begin | |
if (~nCR) | |
Current_state <= S0; // 异步清零 | |
else | |
Current_state <= Next_state; | |
// 在 CP 回升沿触发器状态翻转 | |
end | |
// 下一状态产生和输入信号,组合逻辑 | |
always @(Current_state or Sin) | |
begin | |
Next_state =2’bxx; | |
Out=1’b 0; | |
case(Current_state) | |
S0: begin Out =1’b0; Next_state = (Sin==1)? S0 : S1; end | |
S1: begin Out =1’b0; Next_state = (Sin==1)? S2 : S1; end | |
S2: begin Out =1’b0; Next_state = (Sin==1)? S0 : S3; end | |
S3: if (Sin==1) | |
begin Out =1’b1; Next_state = S2; end | |
else | |
begin Out =1’b0; Next_state = S1; end | |
endcase | |
end | |
endmodule |
用两个 always 块形容状态机的写法是值得举荐的办法之一,两个 always 块写法的电路构造框图能够用下图进行概括。
两个 always 块写法的电路构造框图概括。
第一个 always 模块采纳同步时序逻辑形式形容状态转移(两头方框); 第二个 always 模块采纳组合逻辑形式形容状态转移法则(第一个方框)和形容电路的输入信号(第三个方框)。
应用三个 always 块别离形容
即第一个 always 模块采纳同步时序逻辑形式形容状态转移(两头方框); 第二个 always 模块采纳组合逻辑形式形容状态转移法则(第一个方框); 第三个 always 模块形容电路的输入信号,在时序容许的状况下,通常让输入信号通过一个寄存器再输入,保障输入信号中没有毛刺。
用三个 always 块对该例的状态机进行形容,其代码如下:
module Detector3 (Sin, CP, nCR, Out) ; | |
input Sin, CP, nCR; // 定义输出变量 | |
output Out ; // 定义输入变量 | |
reg Out; | |
reg [1:0] Current_state, Next_state; | |
parameter [1:0] S0=2'b00, S1=2'b01, S2 = 2'b10, S3 = 2'b11; | |
// 状态转换,时序逻辑 | |
always @(posedge CP or negedge nCR) | |
begin | |
if (~nCR) | |
Current_state <= S0; // 异步清零 | |
else | |
Current_state <= Next_state; // 在 CP 回升沿触发器状态翻转 | |
end | |
// 下一状态产生,组合逻辑 | |
always @(Current_state or Sin) | |
begin | |
Next_state =2’bxx; | |
case(Current_state) | |
S0: begin Next_state = (Sin==1)? S0 : S1; end | |
S1: begin Next_state = (Sin==1)? S2 : S1; end | |
S2: begin Next_state = (Sin==1)? S0 : S3; end | |
S3: if (Sin==1) | |
begin Next_state = S2; end | |
else | |
begin Next_state = S1; end | |
endcase | |
end | |
/* 输入逻辑: 让输入信号通过一个寄存器再输入,能够打消 Out 信号中的毛刺,时序逻辑 */ | |
always @ (posedge CP or negedge nCR) | |
begin | |
if (~nCR) Out <= 1’b 0; | |
else | |
begin | |
case(Current_state) | |
S0, S1, S2: Out <= 1’b0; | |
S3: if (Sin==1) | |
Out <= 1’b1; | |
else | |
Out <= 1’b0; | |
endcase | |
end | |
end | |
endmodule |
三种形容办法比拟
1-always | 2-always | 3-always | |
---|---|---|---|
结构化设计 | 否 | 是 | 是 |
代码编写 / 了解 | 不宜,了解难 | 宜 | 宜 |
输入信号 | 寄存器输入 | 组合逻辑输入 | 寄存器输入 |
不产生毛刺 | 产生毛刺 | 不产生毛刺 | |
面积耗费 | 大 | 最小 | 小 |
时序束缚 | 不利 | 无利 | 无利 |
可靠性、可维护性 | 低 | 较高 | 最高 |
后端物理设计 | 不利 | 无利 | 无利 |
参考文献:
- Verilog HDL 与 FPGA 数字零碎设计,罗杰,机械工业出版社,2015 年 04 月
- Verilog HDL 与 CPLD/FPGA 我的项目开发教程(第 2 版), 聂章龙, 机械工业出版社, 2015 年 12 月
- Verilog HDL 数字设计与综合(第 2 版), Samir Palnitkar 著,夏宇闻等译, 电子工业出版社, 2015 年 08 月
- Verilog HDL 入门(第 3 版), J. BHASKER 著 夏宇闻甘伟 译, 北京航空航天大学出版社, 2019 年 03 月
欢送关注公众号【AIShareLab】,一起交换更多相干常识,前沿算法,Paper 解读,我的项目源码,面经总结。