Verilog奇偶分频、一段式、两段式、三段式状态机
verilog三段式写法 -回复

verilog三段式写法-回复Verilog三段式写法及其应用[引言]Verilog是一种硬件描述语言,常用于数字系统设计和验证。
其三段式写法是一种结构化代码编写方法,使得Verilog代码更具可读性和可维护性。
本文将介绍Verilog三段式写法的基本原则和应用。
[主体]一、Verilog三段式写法的基本原则Verilog三段式写法分为模块声明段、模块实例化段和连线连接段三个部分。
遵循以下原则可以使得代码更加易读、易写和易维护。
1. 模块声明段:模块声明段用于定义模块的输入输出端口、内部信号和模块内部子模块。
在此段中,要定义输入输出端口的类型、宽度,并按照功能进行分组,以增强代码的清晰度和可读性。
2. 模块实例化段:模块实例化段用于实例化其他模块。
在此段中,以模块名为关键字,通过实例名来调用其他模块。
通过这种方式,可以方便地进行模块的复用,提高代码编写的效率。
3. 连线连接段:连线连接段用于将模块内信号和模块之间的端口进行连接。
在此段中,通过连线语句将模块内的信号与输入输出端口相连接。
这里可以使用连线运算符"->"和"<-"来表示方向,以增加代码的可读性。
二、Verilog三段式写法的应用Verilog三段式写法可以有效地帮助我们组织和管理代码,下面列举几个应用场景:1. 声明段的应用:在声明段中,我们可以按照功能和类型对端口进行分组。
例如,我们可以将输入端口和输出端口分开定义,可以使得代码更加清晰易读。
同时,在定义端口的时候,我们可以指定端口的数据类型和位数,这样可以提高代码的安全性和可读性。
2. 实例化段的应用:在实例化段,我们可以实例化其他模块,并且给实例化的模块分配实例名。
通过实例化可以方便地实现模块之间的复用和调用,提高代码的可维护性和可扩展性。
同时,实例名的设置也可以使得代码更加易读和易理解。
3. 连线连接段的应用:在连线连接段,我们可以使用连线语句将模块内的信号与输入输出端口相连接。
verilogHDL分频器(奇数分频和偶数分频)

module clk_div(//-----------input-----------iCLK,div,//-----------output----------oCLK);//-----------input-----------parameter WIDE=14;input iCLK;input[WIDE-1:0]div;//-----------output-----------output oCLK;wire oCLK_odd;wire oCLK_even;assign oCLK=div[0]?oCLK_odd:oCLK_even;div_odd DUTo (.iCLK(iCLK),.oCLK(oCLK_odd),.div(div)); div_even DUTe (.iCLK(iCLK),.oCLK(oCLK_even),.div(div));endmodule// oddmodule div_odd(//--------input--------iCLK,div,//--------output--------oCLK);//--------input--------parameter WIDE=14;input iCLK;input[WIDE-1:0]div;//--------output--------output oCLK;reg outCLK;/*=========================== solve 1=========================== reg cout;reg[WIDE-1:0] cnt;initial cnt=0;wire inCLK;reg cc;initial cc=0;always @(posedge cout)cc<=~cc;assign inCLK = iCLK^cc;always @(posedge inCLK)beginif(cnt<(div[WIDE-1:1]))begincnt<=cnt+1;cout<=1'b0;endelsebegincnt<=0;cout<=1'b1;endendalways @(negedge iCLK)outCLK <= cout;assign oCLK=cc;*///======================== //solve 2//======================== reg[WIDE-1:0] cnt_a;initial cnt_a=0;reg[WIDE-1:0] cnt_b;initial cnt_b=0; reg cout_a;reg cout_b;always @(negedge iCLK)beginelse if(cnt_a<=(div[WIDE-1:1]))begincnt_a=cnt_a+1;cout_a=1'b1;endelse if(cnt_a>(div[WIDE-1:1])&&cnt_a<(div[WIDE-1:0]-1))begincout_a=1'b0;cnt_a=cnt_a+1;endelsebegincnt_a=0;endendalways @(posedge iCLK)beginif(cnt_b<=(div[WIDE-1:1]))begincnt_b=cnt_b+1;cout_b=1'b1;endelse if(cnt_b>(div[WIDE-1:1])&&cnt_b<(div[WIDE-1:0]-1))begincout_b=1'b0;cnt_b=cnt_b+1;endelsebegincnt_b=0;endendassign oCLK = cout_a&cout_b;endmodule//evenmodule div_even(//--------input--------iCLK,div,//--------output--------oCLK);//--------input--------parameter WIDE=14;input iCLK;input[WIDE-1:0]div;//--------output--------output oCLK;reg oCLK;initial oCLK = 1'b0;reg[WIDE-1:0] cnt;initial oCLK = 0;always @(posedge iCLK)beginif(cnt<(div[WIDE-1:1]-1))cnt <= cnt + 1;elsebegincnt <= 0;oCLK <= ~oCLK;endendendmodule//============================//testbench//============================/*module clk_div_test;//-----------input-----------parameter WIDE=14;reg iCLK;reg[WIDE-1:0] div;//-----------output-----------wire oCLK;clk_div cc(.iCLK(iCLK),.div(div),.oCLK(oCLK));always #20 iCLK = ~iCLK;initialbeginiCLK = 0;div=14'd7;#1000 $stop;endendmodule*/module clk_div14bits(clk,a,clkout);input clk,a;output clkout;reg clkout;wire oCLK1,oCLK2;clk_div cc1(.div(14'd8),.iCLK(iCLK),.oCLK(oCLK1)); clk_div cc2(.div(14'd9),.iCLK(iCLK),.oCLK(oCLK2));always @(a or posedge clkin)beginif(a==1)clkout=oCLK1;elseclkout=oCLK2;endendmodule//测试代码//testbenchmodule clk_div14bits_test;//-----------input-----------parameter WIDE=14;reg clk;reg[WIDE-1:0] div;//-----------output-----------wire oCLK;clk_div14bits cc3(.clk(clk),.a(a),.clkout(clkout)); always #20 clk = ~clk;initialbeginiCLK = 0;div=14'd7;#1000 $stop;EndModelsim仿真结果1.七分频2.四分频。
verilog三段式

verilog三段式
Verilog的三段式(Three-Level Hierarchy)是一种组织和设计Verilog代码的结构方法,它将代码分成三个级别,以实现模块化和可重用性。
这些级别分别是顶层(Top-level)、中层(Intermediate-level)和底层(Low-level),每个级别都有不同的功能和目的。
1.顶层(Top-level):顶层是整个设计的最高级别,它组织和
连接所有的模块,包括顶层模块和其它外部模块。
在这个层次上,你可以定义主要的模块和其它全局信号,处理模块之间的接口和通信。
通常,顶层模块是设计的入口点,在这里实例化和连接所有的子模块。
2.中层(Intermediate-level):中层是中间级别的模块,它们被
实例化在顶层模块中使用。
这些模块可以是包含顶层模块的主要子模块,也可以是一些复杂的功能模块。
在中层模块中,你可以定义局部信号和局部逻辑,用来实现特定的功能或任务。
这些模块有助于模块化和简化设计,提高代码的可读性和可维护性。
3.底层(Low-level):底层是最低级别的模块,在中层模块中
被实例化和使用。
它们通常是具体的基础模块,实现了基本的功能和操作。
这些模块可以是逻辑门、寄存器、计数器等,也可以是包含简单组合逻辑的小模块。
底层模块通常是最基本的构建块,在设计中提供了底层的功能和细节。
按照这种三段式的组织方式,可以将设计分成几个层次,使代码模块化、结构清晰,并且方便维护和重用。
每个级别都负责不同的任务和功能,遵循了"自顶向下"的设计原则,让整个设计变得更加可靠和可管理。
用Verilog语言实现奇数倍分频电路3分频5分频7分频

用Verilog语言实现奇数倍分频电路3分频5分频7分频Verilog是一种硬件描述语言(HDL),用于描述数字电路的行为和结构。
使用Verilog语言实现奇数倍分频电路可以分为以下几个步骤:1.定义输入和输出端口通过module关键字定义一个模块,并指定输入和输出端口的信号。
```verilogmodule OddDividerinput clk,output reg out_3x,output reg out_5x,output reg out_7x```2.定义局部变量和计数器定义一个局部变量和一个计数器,用于跟踪时钟周期并确定何时输出。
```verilogreg [2:0] count;```3.实现分频逻辑使用always块,根据计数器的值判断何时输出,并在输出端口上更新信号。
```verilogif (count == 3'b000) beginout_3x <= !out_3x;endif (count == 3'b001) beginout_5x <= !out_5x;endif (count == 3'b010) beginout_7x <= !out_7x;endcount <= count + 1;end```4.结束模块使用endmodule关键字结束模块定义。
```verilogendmodule完整的Verilog代码如下:```verilogmodule OddDividerinput clk,output reg out_3x,output reg out_5x,output reg out_7xreg [2:0] count;if (count == 3'b000) begin out_3x <= !out_3x;endif (count == 3'b001) begin out_5x <= !out_5x;endif (count == 3'b010) begin out_7x <= !out_7x;endcount <= count + 1;endmodule```以上代码实现了一个奇数倍分频电路,其中输入时钟信号为`clk`,输出分别是3倍分频的信号`out_3x`,5倍分频的信号`out_5x`和7倍分频的信号`out_7x`。
verilog 三段式状态机

Verilog状态机设计‐‐‐‐‐‐‐‐‐三段式状态机练习:设计一个串行数据检测器。
要求是:连续4个或4个以上的1时输出为1,其他输入情况下为0。
编写测试模块并给出仿真波形。
目的:学会状态机设计方法模块源码`timescale 1ps/1psmodule FSM (input iCLK,input iRST_N,input iA,output oMATCH);parameter S0 = 3'b000,S1 = 3'b001,S2 = 3'b010,S3 = 3'b011,S4 = 3'b100;reg [2:0] state, next_state;reg match, next_match;wire is_match_out;assign oMATCH = match;// sequential circuitalways@(posedge iCLK, negedge iRST_N) beginif (!iRST_N) beginstate <= S0;match <= 1'b0;endelse beginstate <= next_state;match <= next_match;endend// combinational circuit for state logicalways@(*) begin //*号不能改为posedge iCLK, negedge iRST_N next_state = S0;case (state)S0 : next_state = (iA==1) ? S1 : S0;S1 : next_state = (iA==1) ? S2 : S0;S2 : next_state = (iA==1) ? S3 : S0;S3 : next_state = (iA==1) ? S4 : S0;S4 : next_state = (iA==1) ? S4 : S0;endcaseend// combinational circuit for output logicassign is_match_out = (next_state == S4) ? 1 : 0;//注意点:如何next_state用state则输出会比现在延时1个周期。
verilog三段式状态机格式

Verilog三段式状态机格式1. 引言在数字电路设计领域,状态机是一种非常重要的设计工具,它能够描述系统在不同状态下的行为。
Verilog是一种硬件描述语言,可以用于描述数字电路的设计和验证。
其中,三段式状态机格式是一种常用的描述方式,本文将针对这一主题展开深入探讨。
2. 三段式状态机的定义三段式状态机包括状态寄存器、组合逻辑和next state逻辑。
状态寄存器用于存储系统的当前状态。
组合逻辑根据输入信号和当前状态计算出输出信号和下一个状态。
next state逻辑用于确定下一个状态的取值。
三段式状态机可以清晰地描述系统的状态转移关系,具有良好的可读性和可维护性。
3. 深入理解三段式状态机在实际应用中,三段式状态机格式能够很好地应对复杂的状态转移逻辑。
通过合理的状态定义和状态转移规则,可以实现高效、稳定的系统设计。
三段式状态机还有利于设计验证和仿真,能够有效减少错误的引入,并提高系统的可靠性。
4. 三段式状态机在Verilog中的应用在Verilog语言中,可以通过module和always语句来描述三段式状态机。
通过module定义状态寄存器和组合逻辑,明确定义输入、输出和状态变量。
通过always语句描述next state逻辑,根据输入信号和当前状态计算下一个状态的取值。
采用Verilog描述三段式状态机,能够有效提高设计的可移植性和可重用性。
5. 个人理解与观点三段式状态机格式作为一种强大的状态机描述方式,在数字电路设计中具有广泛的应用。
我个人认为,深入理解并灵活应用三段式状态机格式,对于提高数字电路设计的效率和质量具有重要意义。
通过对状态机转移关系的清晰描述,可以有效减少设计错误和优化系统性能。
6. 总结与回顾三段式状态机格式在Verilog语言中的应用具有重要价值。
通过本文的探讨,我对三段式状态机的概念和应用有了更深入的理解。
在今后的数字电路设计中,我将更加灵活地运用三段式状态机格式,以期实现更高效、可靠的系统设计。
verilog三段式写法 -回复
verilog三段式写法-回复Verilog是一种硬件描述语言(Hardware Description Language,HDL),用于硬件设计和验证。
它是一种具有结构化特点的编程语言,广泛应用于数字电路设计、芯片设计和系统级仿真。
在这篇文章中,我们将深入探讨Verilog的三段式写法,以及如何使用它进行硬件设计和验证。
一、Verilog的三段式写法简介Verilog的三段式写法是指使用三个不同的部分来描述硬件设计,即模块声明、端口声明和行为描述。
通过将硬件描述划分为这三个部分,可以使代码更加清晰、易读和易于维护。
1. 模块声明(Module Declaration):模块声明是Verilog代码的第一部分,用于定义模块的名称和端口列表。
模块是硬件设计的基本单位,一个模块可以包含多个输入端口和输出端口,用于实现特定的功能。
2. 端口声明(Port Declaration):端口声明是Verilog代码的第二部分,用于定义模块的输入和输出端口。
输入端口用于接收输入信号,输出端口用于产生输出信号。
端口声明中包含了端口的名称、方向(输入或输出)以及数据类型。
3. 行为描述(Behavioral Description):行为描述是Verilog代码的第三部分,用于描述模块的行为、逻辑和功能。
行为描述可以使用组合逻辑和时序逻辑来实现各种硬件功能。
组合逻辑指的是基于输入信号产生输出信号的逻辑,而时序逻辑则表示基于时钟和状态的逻辑。
二、模块声明模块声明是Verilog代码的第一部分,用于定义模块的名称和端口列表。
模块声明的语法如下所示:module module_name (port_list);输入和输出信号的声明input [n:0] input_signal;output [m:0] output_signal;内部信号的声明wire [p:0] internal_signal;模块行为描述...endmodule在模块声明中,语句`module module_name(port_list);`定义了一个模块的名称和端口列表。
Verilog常用分频器的实现
Verilog常用分频器的实现分频器是指使输出信号频率为输入信号频率整数分之一的电子电路。
在许多电子设备中如电子钟、频率合成器等,需要各种不同频率的信号协同工作,常用的方法是以稳定度高的晶体振荡器为主振源,通过变换得到所需要的各种频率成分,分频器是一种主要变换手段。
早期的分频器多为正弦分频器,随着数字集成电路的发展,脉冲分频器(又称数字分频器)逐渐取代了正弦分频器。
下面以Verilog HDL语言为基础介绍占空比为50%的分频器。
1.偶分频偶分频比较简单,假设为N分频,只需要计数到N/2‐1,然后时钟翻转、计数清零,如此循环就可以得到N(偶)分频。
代码如下。
module fp_even(clk_out,clk_in,rst);input clk_in,rst;output clk_out;reg [7:0] cnt;reg clk_out;`define N 6always@(posedge clk_in or negedge rst)beginif(!rst)begincnt<=0;clk_out<=0;endelse beginif(cnt==`N/2‐1)beginclk_out<=~clk_out;cnt<=0;endelse cnt<=cnt+1;endendendmodule2.奇分频实现奇数分频(N)分频,分别用上升沿到(N-1)/2,再计数到N-1;用下降沿计数到(N-1)/2,再计数到N-1。
得到两个波形,然后把它们相或即可得到N分频。
代码如下。
module fp_odd(clk_in,clk_out,rst,clk_neg,clk_pos);input clk_in,rst;output clk_out,clk_pos,clk_neg;reg [7:0] cnt_pos,cnt_neg;reg clk_pos,clk_neg;`define N 5always@(posedge clk_in or negedge rst) //从零到N‐1不停地循环计数(上升沿)beginif(!rst) cnt_pos<=0;else if(cnt_pos==`N‐1) cnt_pos<=0;else cnt_pos<=cnt_pos+1;endalways@(posedge clk_in or negedge rst)beginif(!rst) clk_pos<=0;else if( cnt_pos==(`N‐1)/2 ) clk_pos<=~clk_pos;else if(cnt_pos==`N‐1) clk_pos<=~clk_pos;endalways@(negedge clk_in or negedge rst) //从零到N‐1不停地循环计数(下降沿)beginif(!rst) cnt_neg<=0;else if(cnt_neg==`N‐1) cnt_neg<=0;else cnt_neg<=cnt_neg+1;endalways@(negedge clk_in or negedge rst)beginif(!rst) clk_neg<=0;else if( cnt_neg==(`N‐1)/2 ) clk_neg<=~clk_neg;else if(cnt_neg==`N‐1) clk_neg<=~clk_neg;endassign clk_out=clk_neg|clk_pos;endmodule3.任意占空比的任意分频在 verilog程序设计中,我们往往要对一个频率进行任意分频,而且占空比也有一定的要求。
Verilog实现奇数和偶数分频器和半整数及任意小数分频器程序
1、半整数分频占空比不为50%//说明:设计的史上最好用的半整数分频占空比不为50%,包含设计思路module div_5(clk,clk_div,cnt1,cnt2,temp1,temp2);//N+0.5input clk;output clk_div;output reg[31:0]cnt1,cnt2;output reg temp1,temp2;initial begin temp1=0;temp2=1;end //首先进行初始化,temp1=0;temp2=1 parameter N=5; //设定分频系数为N+0.5always @(posedge clk) //temp1上升沿跳变beginif(cnt1==2*N) //2*Nbegin cnt1[31:0]<=32'd0;endelse begin cnt1[31:0]<=cnt1[31:0]+32'd1;endif(cnt1==32'd0) begin temp1<=1;end //高电平时间为N+1;if(cnt1==N+1) begin temp1<=0;end//低电平时间为N;endalways@(negedge clk) //temp2下降沿跳变beginif(cnt2==2*N) //2*Nbegin cnt2[31:0]<=32'd0;endelse begin cnt2[31:0]<=cnt2[31:0]+32'd1;endif(cnt2==32'd0) begin temp2<=0;end //低电平时间为N;if(cnt2==N) begin temp2<=1;end //高电平时间为N+1;endassign clk_div=temp1&&temp2; //逻辑与endmodule//如果要进行N+0.5分频//思路:总的来说要进行N+1+N=2N+1次分频//在时钟的上升沿和下降沿都进行跳变//上升沿进行占空比为N+1比N的时钟temp1;//下降沿进行占空比为N比N+1的时钟temp2;//最后div=temp1&&temp2 即可得到所需要的半整数分频分频5.5仿真结果2、奇数分频占空比为50%//说明:奇数分频。
奇偶分频电路verilog代码
奇偶分频电路verilog代码奇偶分频电路verilog代码1.偶数分频器偶数分频器只要在计数器为N/2-1时反转输出就⾏//4分频器module clk_div(input clk,input rst_n,output reg clk_div4);reg [3:0]count;parameter N=4;//若⽤integer i 采⽤always@(posedge clk or negedge rst_n)beginif(rst_n)begincount <=4'b0;endelse if(count==4'b1)begincount <=4'b0;endelse begincount <=count +4'd1;endendalways @(posedge clk or negedge rst_n)beginif(rst_n)beginclk_div4 <=1'b0;endelse if(count==4'b1)beginclk_div4<=~clk_div4;endelse beginclk_div4<=clk_div4;endendendmodule2.奇数分频器奇数分频器有两种,⼀种是占空⽐为50的⼀种是占空⽐⾮20的。
⾸先是占空⽐⾮50的,⽤错位异或实现module div5(input clk,input rst_n,output clk_div5);reg clk1;reg clk2;reg [2:0] count;always @(posedge clk or negedge rst_n) beginif(rst_n)begincount <=3'd0;endelse if(count==3'd4)begincount <=3'd0;endelse begincount <=count+1'b1;endendalways @(posedge clk or negedge rst_n) beginif(rst_n)beginclk1<=1'b0;endelse if(count==3'd4)beginclk1 <=~clk1;endelse beginclk1<=clk1;endendalways @(posedge clk or negedge rst_n) beginif(rst_n)beginclk2<=1'b0;endelse if(count==3'd2)beginclk2 <=~clk2;endelse beginclk2<=clk2;endendassign clk_div5 = clk2^clk1 ;endmodule关键是第⼀个clk等计数器=N-1跳,第⼆个在(N-1)/2跳接下来是50占空⽐的,⽤另⼀个下降沿实现module top(input clk,input rst_n,output clk_div);reg clk1;reg clk2;reg [2:0] count;always @(posedge clk or negedge rst_n) beginif(rst_n)beginclk1 <=1'd0;endelse if(count==3'd0)beginclk1 <=1'd1;endelse if(count==3'd2)beginclk1 <=1'b0;endendalways @(posedge clk or negedge rst_n) beginif(rst_n)begincount <=3'd0;endelse if(count==3'd4)begincount <=3'd0;endelse begincount <=count+1'b1;endendalways @(negedge clk or negedge rst_n) beginif(rst_n)beginclk2<=1'b0;endelse beginclk2<=clk1;endendassign clk_div = clk2 || clk1 ;endmodule关键在第⼀个于(N-1)/2的时候从1跳0,第⼆个下降沿触发,相当于第⼀个的后⼀级寄存器。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
汇报总结1、偶数分频偶数倍分频相对简单,可以通过计数器对预分频的脉冲沿计数实现,如果要进行N倍(N为整数)偶数分频,可由预分频的时钟触发计数器计数,当计数器从0计数到N/2—1时,输出时钟进行翻转,并给计数器一个复位信号,使得下一个时钟从零开始计数,以此循环下去。
分频的主体程序如下:`define div_en 8module freq_div_even(clk_in,reset,clk_out);input clk_in;input reset;output clk_out;reg clk_out;reg[2:0] count;initialbegincount=0;clk_out=0;endalways@(posedge clk_in)beginif(!reset)begincount<=0;clk_out<=0;endelseif(count==(`div_en/2-1))beginclk_out<=~clk_out;count<=0;endelsebegincount<=count+1;endendendmodule下面定义N为8,对一个脉冲8分频,测试程序如下:`timescale 1ns/1nsmodule testbench;reg reset;reg clk_in;reg[2:0] count;wire clk_out;freq_div_even test(.clk_in(clk_in),.reset(reset),.clk_out(clk_out));initialbeginreset=0;clk_in=0;#5 reset=1;endalways #10 clk_in=~clk_in;endmodule波形图如下:2、奇数分频对于对占空比没有特殊要求的奇数分频,需要对上升沿和下降沿脉冲进行计数,利用下降沿产生的波形移相半个输入脉冲的作用,最后用错位“异或”法实现。
一个n(n=3)分频的程序如下:module clk_divN(clk_in,reset,clk_out);input clk_in;input reset;output clk_out;integer cnt1,cnt2;reg clk_divp;reg clk_divn;parameter n=3;always@(posedge clk_in)beginif(!reset)beginclk_divp<=0;cnt1<=0;endelseif(cnt1==(n-1))cnt1<=0;elseif(cnt1==0|cnt1==(n-1)/2)begincnt1<=cnt1+1;clk_divp<=~clk_divp;endelsecnt1<=cnt1+1;endalways@(negedge clk_in)beginif(!reset)beginclk_divn<=0;cnt2<=0;endelseif(cnt2==(n-1))cnt2<=0;elseif(cnt1==0|cnt1==(n-1)/2)begincnt2<=cnt2+1;clk_divn<=~clk_divn;endelsecnt2<=cnt2+1;endassign clk_out=clk_divp|clk_divn;endmodule测试程序如下:`timescale 1ns/1nsmodule clk_div3_tb;reg clk_in;reg reset;wire clk_out;clk_divN uut (.clk_in(clk_in),.reset(reset),.clk_out(clk_out));initialbeginclk_in = 0;reset = 0;#10 reset=1;endalways #5 clk_in=~clk_in;endmodule3分频、5分频和7分频仿真波形分别如下:3分频5分频7分频3、状态机状态机分为两种、一种称为Mealy状态机,它的时序逻辑输出不但取决于状态还取决于输入;另外一种称为Moore状态机,它的输出只取决于当前的状态。
实际的设计工作中大部分都是Mealy状态机。
有限状态机设计一般步骤:1、逻辑抽象,得出状态转换图;2、状态化简;3、状态分配;4、选定触发器的类型并求出状态方程、驱动方程和输出方程;5、按照方程得出逻辑图。
FSM的描述方法有3中:1、在1个always 模块里面,该模块中既描述状态转移,又描述状态的输入和输出,这种写法一般被称为一段式FSM 描述方法;2、还有一种写法是将用2 个always 模块,其中一个always 模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律,这种写法被称为两段式FSM 描述方法;3、还有一种写法是在两段式描述方法基础上发展出来的,这种写法使用3 个always 模块,一个always模块采用同步时序描述状态转移;第二个采用组合逻辑判断状态转移条件,描述状态转移规律;第三个always模块使用同步时序电路描述每个状态的输出,这种写法本书称为三段式。
三种描述方式的优缺点比较如下表:我们主要学习三段式的FSM描述方法。
例如:需要编写下图所示状态机:一段式的的程序,如下:// state_1paragraph.vmodule state_1para( reset,clk,x,out);input reset,clk;input x;output out;reg [1:0] out;reg [2:0] Next_state; //NextStateparameter [2:0] //one hot with zero idleS0 = 2'b00,S1 = 2'b01,S2 = 2'b10,S3 = 2'b11;always @ (posedge clk or negedge reset)if (!reset)beginNext_state <= S0;out <= 2'b00;endelsebeginNext_state <= 2'bx;out <= 2'b00;case (Next_state)S0:beginif (x==0)beginout <= 2'b00;Next_state <= S0;endelsebeginout <= 2'b01; //输出要看下一状态Next_state <= S1;endendS1:beginif (x==0)beginout <= 2'b00;Next_state <= S0;endelsebeginout <= 2'b10;Next_state <= S2;endendS2:beginif (x==0)beginout <= 2'b00;Next_state <= S0;endelsebeginout <= 2'b11;Next_state <= S3;endendS3:beginif (x==0)beginout <= 2'b00;Next_state <= S0;endelsebeginout <= 2'b11;Next_state <= S3;endendendcaseendendmodule两段式的程序如下:module state_2para( reset,clk,x,out);input reset,clk;input x;output out;reg [1:0] out;reg [2:0] Next_state,Current_state; parameter [2:0] //one hot with zero idleS0 = 2’b00,S1 = 2’b01,S2 = 2’b10,S3 = 2’b11;//描述状态转移,非阻塞方式赋值always @ (posedge clk or negedge reset)if (!reset)Current_state <= S0;elseCurrent_state <= Next_state;//描述状态转移的条件,阻塞方式赋值always @ (Current_state or x)beginNext_state = 2’bx;S3_out;case (Current_state)S0:beginS0_out;if (x==0) Next_state = S0;else Next_state = S1;endS1:beginS1_out;if (x==0) Next_state = S0;else Next_state = S2;endS2:beginS2_out;if (x==0) Next_state = S0;else Next_state = S3;endS3:beginS3_out;if (x==0) Next_state = S0;else Next_state = S3;endendcaseend//定义输出任务task S0_out;out = 2'b00;endtasktask S1_out;out = 2'b01;endtasktask S2_out;out = 2'b10;endtasktask S3_out;out = 2'b11;endtaskendmodule三段式的程序如下:module state3 ( reset,clk,x,out);input reset,clk;input x,;output out;reg [1:0] out;reg [2:0] Next_state,Current_state;parameter [2:0]S0 = 2’b00,S1 = 2’b01,S2 = 2'b10,S3 = 2’b11;always @ (posedge clk or negedge reset)if (!reset)Current_state <= S0;elseCurrent_state <= Next_state;always @ (reset or Current_state or x) //与二段式区别beginNext_state = 2’bx;case (Current_state) //注意S0:beginif (x==0) Next_state = S0;else Next_state = S1;endS1:beginif (x==0) Next_state = S0;else Next_state = S2;endS2:beginif (x==0) Next_state = S0;else Next_state = S3;endS3:beginif (x==0) Next_state = S0;else Next_state = S3;endendcaseendalways @ (posedge clk or negedge reset)if (!reset)out <= 0;elsebeginout <= 0;case (Next_state)//需要注意,不是Current_stateS0: out <= 2’b00;S1: out <= 2’b01;S2: out <= 2’b10;S3: out <= 2’b11;endcaseendendmodule三种方法的测试程序如下:// state_1paragraph_tb.v`timescale 1ns/1nsmodule state_1parag_tb;reg reset;reg clk;reg x;wire[1:0] out;state_1para tb( .reset(reset),.clk(clk),.x(x),.out(out));initialbeginclk=0;reset=0;x=0;#10 reset=1;#1000 reset=0;# 100 reset=1;endalways #20 clk=~clk;always@(posedge clk)begin#10 x={$random}%2;//输入x随机在0和1之间变化endendmodule一段式的仿真波形图二段式的仿真波形图三段式的仿真波形图。