📄 第6节 verilog常用程序示例 -与非网专题: fpga开发实用教程.htm
字号:
cnt <= 0;
<BR>
clk_out <= !clk_out;
<BR> end
<BR>
else begin
<BR>
cnt <= cnt + 1;
<BR>
clk_out <= clk_out;
<BR>
end <BR> end
<BR><BR>endmodule <BR><BR>上述程序经过综合Synplify Pro后,其RTL级结构如图2-13所示。 </P>
<P align=center><IMG height=152 alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206064285.jpg"
width=481><BR><BR><BR>图2-13 16分频电路的RTL结构图 </P>
<P align=left><BR>在ModelSim 6.2b中完成仿真,其结果如图2-14所示,从中可以看出例2-21成功实现了输入时钟的16分频。
</P>
<P align=center><IMG height=59 alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206431980.jpg" width=650></P>
<P align=center><BR>图2-14 16分频电路的仿真结果示意图 </P>
<UL>
<LI>奇数分频电路 </LI></UL>
<P>奇数倍分频有多种实现方法,下面介绍常用的错位“异或”法的原理。如进行三分频,通过待分频时钟上升沿触发计数器进行模三计数,当计数器计数到邻近值进行两次翻转。比如在计数器计数到1时,输出时钟进行翻转,计数到2时再次进行翻转,即在邻近的1和2时刻进行两次翻转。这样实现的三分频占空比为1/3或者2/3。如果要实现占空比为50%的三分频时钟,可以通过待分频时钟下降沿触发计数,和上升沿同样的方法计数进行三分频,然后将下降沿产生的三分频时钟和上升沿产生的时钟进行相或运算,即可得到占空比为50%的三分频时钟。
<BR>
<BR>这种错位“异或”法可以推广实现任意的奇数分频:对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发的模N计数,计数到某一选定值时进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%奇数N分频时钟。再者同时进行下降沿触发的模N计数,到和上升沿触发输出时钟翻转选定值相同值时,进行输出时钟时钟翻转,同样经过(N-1)/2时,输出时钟再次翻转生成占空比非50%的奇数N分频时钟。两个占空比非50%的N分频时钟相或运算,得到占空比为50%的奇数N分频时钟。
<BR><BR>例2-22 使用Verilog实现3分频电路。 <BR><BR>module clk_div3(clk_in, reset, clk_out);
<BR> input clk_in; <BR> input
reset; <BR> output clk_out;
<BR><BR> reg [1:0] cnt, cnt1;
<BR> reg clk_1to3p, clk_1to3n;
<BR> always @(posedge clk_in) begin
<BR>
if(!reset) begin
<BR>
cnt <= 0;
<BR>
clk_1to3p <= 0;
<BR> end
<BR> else
begin
<BR>
if(cnt == 2'b10) begin
<BR>
cnt <= 0;
<BR>
clk_1to3p <=
clk_1to3p; <BR> end
<BR> else
begin
<BR>
cnt <= cnt + 1;
<BR>
clk_1to3p <= !clk_1to3p;
<BR>
end <BR> end <BR>
end <BR><BR> always @(negedge clk_in) begin
<BR> if(!reset) begin
<BR>
cnt1 <= 0;
<BR>
clk_1to3n <= 0;
<BR> end
<BR> else begin
<BR>
if(cnt1 == 2'b10) begin
<BR>
cnt1 <= 0;
<BR>
clk_1to3n <=
clk_1to3n; <BR>
end
<BR>
else begin
<BR>
cnt1 <= cnt1 +
1; <BR> clk_1to3n
<=
!clk_1to3n; <BR> end
<BR>
end <BR> end
<BR><BR> assign clk_out = clk_1to3p |
clk_1to3n; <BR><BR>endmodule <BR><BR>上述程序经过综合Synplify Pro后,其RTL级结构如图2-15所示。</P>
<P align=center><IMG alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206064850.jpg"> <BR><BR><BR>图2-15
3分频电路的RTL结构图 </P>
<P align=left><BR>在ModelSim 6.2b中完成仿真,其结果如图2-16所示,可以看到输出时钟为占空比为50%的3分频时钟。 </P>
<P align=center><IMG height=45 alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206432022.jpg"
width=650><BR><BR><BR>图2-16 3分频电路的仿真结果</P>
<P align=left><BR>2.同步采样模块
<BR><BR>在实际应用中,外部输入的异步信号需要经过系统时钟的同步化,且将输入的异步信号整形成一个时钟长的脉冲信号,如图2-17所示。这里以例2-23来说明实现的方法。
</P>
<P align=center><IMG height=116 alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206064969.jpg"
width=469><BR><BR><BR>图2-17 异步信号的同步采样示意图 </P>
<P align=left><BR>例2-23 使用Verilog将外部异步信号进行同步整形。 <BR><BR>module clk_syn(clk,
reset, s_in, s_out); <BR> input clk;
<BR> input reset;
<BR> input
s_in; <BR> output s_out;
<BR><BR> reg s_t1, s_t2;
<BR> always @(posedge clk) begin
<BR>
if(!reset)
begin <BR> s_t1
<= 0;
<BR>
s_t2 <= 0;
<BR>
end <BR> else
begin
<BR>
s_t1 <=
s_in; <BR> s_t2
<=
s_t1; <BR> end <BR> end <BR><BR> assign
s_out = s_t1 & (!s_t2); <BR><BR>endmodule <BR><BR>上述程序经过综合Synplify
Pro后,其RTL级结构如图2-18所示。从结果上看,该电路非常简单,但需要一定的时序逻辑能力才能真正理解该段程序。 </P>
<P align=center><IMG height=116 alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206065098.jpg"
width=558><BR><BR><BR>图2-18 同步电路的RTL结构示意图</P>
<P align=left><BR>在ModelSim 6.2b中完成仿真,其结果如图2-19所示,将不等长的高电平信号整形成宽度为一个时钟周期的脉冲信号。
</P>
<P align=center><IMG height=56 alt=""
src="第6节 Verilog常用程序示例 -与非网专题: FPGA开发实用教程.files/1206432073.jpg"
width=650><BR><BR><BR>图2-19 同步电路的仿真结果示意图</P>
<P align=left><BR>其中,如果在时钟的上升沿din="1",则x=1,y=0,dout=x and (not
y)=1;如果din="1"超过一个时钟宽度,则x=1,y=1,dout=x and (not
y)=0。即使din在时钟周期内出现抖动,也不会影响输出结果,还是被整形成一个时钟宽度。所以不管是长周期信号还是短周期信号,经过同步采样后,有效高电平宽度都等于时钟周期。<BR><BR>3.同步状态机的Verilog实现
<BR><BR>状态机一般包括组合逻辑和寄存器逻辑两部分。组合电路用于状态译码和产生输出信号,寄存器用于存储状态。状态机的下一个状态及输出不仅与输入信号有关,还与寄存器当前状态有关。根据输出信号产生方法的不同,状态机可分为米里(Mealy)型和摩尔(Moore)型。前者的输出是当前状态和输入信号的函数,后者的输出仅是当前状态的函数。在硬件设计时,根据需要决定采用哪种状态机。
</P>
<UL>
<LI>
<DIV align=left>状态编码 </DIV></LI></UL>
<P
align=left>状态编码又称状态分配。通常有多种编码方法,编码方案选择得当,设计的电路可以简单;反之,电路会占用过多的逻辑或速度降低。设计时,须综合考虑电路复杂度和电路性能这两个因素。下面主要介绍二进制编码、格雷编码和独热码。
<BR><BR>二进制编码和格雷码都是压缩状态编码。二进制编码的优点是使用的状态向量最少,但从一个状态转换到相邻状态时,可能有多个比特位发生变化,瞬变次数多,易产生毛刺。格雷编码在相邻状态的转换中,每次只有1个比特位发生变化,虽减少了产生毛刺和一些暂态的可能,但不适用于有很多状态跳转的情况。
<BR><BR>独热码是指对任意给定的状态,状态向量中只有1位为1,其余位都为0。n状态的状态机需要n个触发器。这种状态机的速度与状态的数量无关,仅取决于到某特定状态的转移数量,速度很快。当状态机的状态增加时,如果使用二进制编码,那么状态机速度会明显下降。而采用独热码,虽然多用了触发器,但由于状态译码简单,节省和简化了组合逻辑电路。独热编码还具有设计简单、修改灵活、易于综合和调试等优点。对于寄存器数量多、而门逻辑相对缺乏的FPGA器件,采用独热编码可以有效提高电路的速度和可靠性,也有利于提高器件资源的利用率。独热编码有很多无效状态,应该确保状态机一旦进入无效状态时,可以立即跳转到确定的已知状态。</P>
<UL>
<LI>有限状态机的Verilog实现 </LI></UL>
<P>用Verilog
语言描述有限状态机可使用多种风格,不同的风格会极大地影响电路性能。通常有3种描述方式:单always块、双always块和三always块。
<BR><BR>单always块把组合逻辑和时序逻辑用同一个时序always块描述,其输出是寄存器输出,无毛刺。但是这种方式会产生多余的触发器,代码难于修改和调试,应该尽量避免使用。
<BR>
<BR>双always块大多用于描述Mealy状态机和组合输出的Moore状态机,时序always块描述当前状态逻辑,组合逻辑always块描述次态逻辑并给输出赋值。这种方式结构清晰,综合后的面积和时间性能好。但组合逻辑输出往往会有毛刺,当输出向量作为时钟信号时,这些毛刺会对电路产生致命的影响。
<BR>
<BR>三always块大多用于同步Mealy状态机,两个时序always块分别用来描述现态逻辑和对输出赋值,组合always块用于产生下一状态。这种方式的状态机也是寄存器输出,输出无毛刺,并且代码比单always块清晰易读,但是面积大于双always块。随着芯片资源和速度的提高,目前这种方式得到了广泛应用。
<BR> <BR>下面以三always块模块给出状态机的Verilog模板。
<BR><BR>// 构成状态跳转环 <BR>always @(posedge clk or negedge rst_n)
<BR> current_state <=
next_state; <BR><BR>// 完成状态机的内部逻辑 <BR>always @ (current_state or ) begin
<BR> case(current_state)
<BR>
S1: next_state = S2;
<BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -