下冰雹 · 2022年03月05日

【安路 EG4S20 版本】基础实验设计与实现:实验5 触发器

实验5.1 使用门级结构描述D触发器

实验设计目标

  1. 在FPGA中使用门级结构描述D触发器。
  2. 通过此实验学习门级结构建模的基本方法。

实验设计思路

一个逻辑电路是由许多逻辑门和开关组成的,因此用基本逻辑门的模型来描述逻辑电路结构是最直观的。本实验设计使用结构描述语句实现D触发器功能,采用带异步置位和清零端的正边沿触发方式,输入信号包含时钟信号CLK、置位端Setn、清零端Clrn和一个数据输入D,输出信号包含数据输出Q和~Q。当Setn为低电平时输出Q恒为1;当Setn为高电平且Clrn为低电平时输出恒为0;当Setn和 Clrn都为高电平时,输出Q在时钟信号CLK的上升沿处被赋予输入D的值。

图5.1是带异步置位和清零端的正边沿触发的D触发器的电路结构图,该逻辑电路的行为分析如下:
image.png
图5.1 带异步置位和清零端的正边沿触发的D触发器
当Setn和Clrn都为1时,可不考虑Setn和Clrn引脚,此时与非门1和与非门2构成一个SR锁存器。当~S和~R(即图5.1中的反馈信号f4和f5)都为1时,该锁存器处于存储状态。假设,时钟信号CLK为0,D为1,则信号f4和f5都为1,SR锁存器进入存储状态。同时,信号f6将变为0,f3将为1。假设CLK变为1,这将使f4变为0,输出Q被置为1。如果现在输入D变为0,时钟信号CLK仍为1,则f6将变为1,只要时钟信号CLK保持为1,f3也将保持为1。则f4仍为0,输出Q保持为1不变。而当时钟信号变为0时,f4和f5都将变为1,SR锁存器再次处于存储状态,输出Q保持为不变。也就是说输出Q只在时钟信号CLK的上升沿被置为输入D的值。其他情况也可类似讨论。
当置位信号Setn(清零信号Clrn)为0时,输出Q立即变为1(0),而不用等到下一个时钟上升沿的到来,此即为异步置位和清零的特点。并且对于输出Q来说,Setn的优先级高于Clrn。

功能模块图与输入输出引脚说明

该工程包含顶层模块triggerD1与底层模块trigger_module,图5.2是整个工程的模块功能图。本实验仅验证了输出Q而未验证输出~Q,下面介绍一下顶层模块各引脚的功能:
image.png
图5.3 D触发器模块功能图

  • CLK:50MHz的时钟信号输入。用CLK的上升沿作为D触发器的触发信号。
  • Setn:置位输入信号,与SW1相连。当Setn为低电平时输出Q恒为1。
  • Clrn:清零输入信号,与SW0相连。当Setn为高电平且Clrn为低电平时输出Q恒为0。对输出Q来说,Setn信号的优先级高于Clrn信号。
  • SW_In:拨动开关输入,与SW2相连。SW_In直接连接“D触发器”的输入“D”,用于模拟输入信号。
  • LED_Out:输出到LED0。LED_Out直接连接“D触发器”的输出“Q”,通过LED灯的亮灭情况来显示触发器的输出Q。

程序设计

图5.3是截取自底层模块trigger_module的部分代码:
image.png
图5.3 D触发器实验核心代码
○ 5-9:输入输出信号声明。
○ 11-21:使用门级结构描述D触发器的电路结构图(图5.1)。门声明语句的格式为:
<门的类型>[<驱动能力><延时>]<门实例1>[,<门实例2>,…,<门实例n>];
门的类型是门声明语句必须的;驱动能力和延时是可选项;门实例1是在本模块中所引用的第一个这种类型的门,而门实例n是引用的第n个这种类型的门,且在结束时使用逗号,最后才用分号。
在本例中,代码第11行使用了一个名为U1的与非门,对应图5.1中的与非门1,输入为Setn、f4和f2,输出为f1。输出与输入无延时。

FPGA管脚配置

以下是Anlogic FPGA的IO Constraint,CLK时钟输入信号与Anlogic_FPGA开发板上的50MHz的晶振时钟相连;置位输入信号Setn与开发板上的SW1相连;清零输入信号Clrn与开发板上的SW0相连;LED_Out输出信号与LED0相连;SW_In输入信号与开发板上的SW2相连。
set_pin_assignment { CLK } { LOCATION = R7; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Clrn } { LOCATION = A9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Setn } { LOCATION = A10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In } { LOCATION = B10; IOSTANDARD = LVCMOS33; }

实验结果

当开关SW1拨向下(Setn = 0)时,LED0点亮;当开关SW1拨向上(Setn = 1),SW0拨向下(Clrn = 0)时, LED0熄灭;当开关SW1,SW0均拨向上(Setn = 1,Clrn = 1)时,在每个时钟的上升沿,LED0输出SW2的状态。因篇幅有限,置位与清零功能请自行验证。

思考与拓展

  • 本实验仅验证了输出Q而未验证输出~Q。对于输出Q来说,Setn信号的优先级高于Clrn信号,那么对于输出~Q又是怎样的呢?请适当修改程序同时观察输出Q和~Q,并结合图5.1解释实验现象。

实验小结

Verilog既可以是一种行为描述的语言也可以是一种结构描述的语言。Verilog模型可以是实际电路的不同级别的抽象,这些抽象的级别包括:系统级、算法级、RTL(Register Transfer Level)级、门级和开关级。前三种都属于行为描述,后两种属于结构描述,RTL级是描述数据在寄存器之前流动和如何处理、控制这些数据流动的模型,门级是描述逻辑门及逻辑门之间的连接的模型。本实验使用门级结构描述D触发器,通过此实验可以学习门级结构建模的基本方法,在下一节实验中将使用行为描述语句实现8D触发器功能。

实验5.2 使用行为描述语句实现8D触发器

实验设计目标

  1. 在FPGA中使用行为描述语句实现8D触发器功能。
  2. 结合实验5.1与实验5.1,对比理解行为描述语句和结构描述语句的不同及各自的优点。

实验设计思路

输出在时钟信号某个特定时刻随输入改变的器件称为触发器。本实验设计实现一个带异步置位与清零端的正边沿触发的8D触发器,除包含8个数据输入端D7~D0、和8个数据输出端Q7~Q0外,其他功能均与实验5.1相同,此处就不再赘述。
表5.1是第i组输入输出信号的真值表,从真值表可以写出$Q_i$的逻辑表达式:
image.png

表5.1 8D触发器真值表

功能模块图与输入输出引脚说明

该工程包含顶层模块triggerD2与底层模块trigger_module,图5.5是整个工程的模块功能图。
image.png
图5.5 8D触发器模块功能图
下面介绍一下顶层模块各引脚的功能:

  • CLK信号、Setn信号和Clrn信号的功能均与实验5.1中D触发器相同,但在本例中,如下图,Setn信号连接到Key_Col[0],Clrn信号连接到Key_Col[1]。这里我们将矩阵键盘的行信号(Key_Row[3:0])输出恒定的4’b1110,即Key_Row[0]始终为低,这样Key0按下时,Key_Col[0](FPGA的E11脚)由高变低,Key1按下时,Key_Col[1](FPGA的D11脚)由高变低。
    image.png
  • SW_In:拨动开关输入,共有八位。SW_In[7:0]分别连接“8D触发器”的数据输入“D7~D0”,用于模拟输入信号。
  • LED_Out:输出到LED灯,共有八位。LED_Out[7:0]分别连接“8D触发器”的输出“Q7~Q0”,通过8个LED灯的亮灭情况来显示触发器的输出结果。

程序设计

图5.6是截取自底层模块trigger_module的部分代码:
image.png
图5.6 8D触发器实验核心代码
○ 5-9:输入输出信号声明。
○ 11-21:使用行为描述语句实现带异步置位和清零端的8D触发器的逻辑表达式,见公式(5.1)。Setn信号的优先级高于Clrn信号。

FPGA管脚配置

以下 是Anlogic FPGA的IO Constraint,CLK信号、Setn信号和Clrn信号的配置方式均与实验5.1中相应信号的配置方式相同; LED_Out[7:0]输出信号分别与开发板上的LED7~LED0相连;SW_In[7:0]输入信号分别与SW7~SW0相连。
set_pin_assignment { CLK } { LOCATION = R7; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Clrn } { LOCATION = D11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[0] } { LOCATION = E10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[1] } { LOCATION = C10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[2] } { LOCATION = F9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[3] } { LOCATION = D9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[0] } { LOCATION = B14; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[1] } { LOCATION = B15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[2] } { LOCATION = B16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[3] } { LOCATION = C15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[4] } { LOCATION = C16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[5] } { LOCATION = E13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[6] } { LOCATION = E16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[7] } { LOCATION = F16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Setn } { LOCATION = E11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[0] } { LOCATION = A9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[1] } { LOCATION = A10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[2] } { LOCATION = B10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[3] } { LOCATION = A11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[4] } { LOCATION = A12; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[5] } { LOCATION = B12; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[6] } { LOCATION = A13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[7] } { LOCATION = A14; IOSTANDARD = LVCMOS33; }

实验结果

当按键开关KEY0按下时,LED7~LED0均点亮;当按键开关KEY0不按下,KEY1按下时,LED7~LED0均熄灭;当按键开关KEY0,KEY1均不按下时,在每个时钟的上升沿,LED7~LED0分别输出SW7~SW0的状态。因篇幅有限,置位与清零功能请自行验证。

思考与拓展

图5.8是使用if语句直接描述D触发器功能的实验代码,它不同于实验5.1节从触发器的门级结构出发,也不同于实验5.3节从触发器的真值表出发,实际上在设计更为复杂的FPGA系统时,往往结合这几种方式,择优处理。请参考图5.8示代码自行建立工程实现8D触发器功能。
image.png
图5.8 if语句实现8D触发器参考代码

实验小结

  • 在本实验中,我们使用了非阻塞语句运算符“<=”代替阻塞语句运算符“=”。当使用阻塞运算符“=”时,赋值语句立即就把当前值赋给变量;但是,当使用非阻塞运算符“<=”时,赋值语句要等到always块结束时后,才完成对变量的赋值操作。
  • 行为描述语句可描述顺序执行或并行执行的程序结构,本节实验使用行为描述语言实现8D触发器功能,相较于实验5.1,程序更加直观、简洁,请结合实验5.1理解它们各自的特点和优势。

实验5.3 实现4JK触发器

实验设计目标

  1. 设计实现一个4输入的带置位和清零端的正边沿触发的JK触发器。
  2. 通过此实验学习利用编程得到任意频率的时钟信号的基本方法。

实验设计思路

类似于实验5.2节,本节实验设计实现一个带置位和清零端的正边沿触发的JK触发器。包含时钟信号CLK1,置位端Setn,清零端Clrn,四组数据输入信号J3~J0、K3~K0和四组数据输出信号Q3~Q0。当Setn和 Clrn都为高电平时,输出Q在时钟信号CLK1的上升沿处随输入J、K的值变化,在J、K端均为1时,每遇到一个时钟的上升沿,输出端的状态翻转一次。
表5.2是第i组输入输出信号的真值表,Qn+1表示该组输出的当前值,$Q_n$表示该组输出上一刻的状态,从真值表可以写出Qn+1的逻辑表达式:
image.png
image.png
表5.2 带置位与清零端的JK触发器真值表

功能模块图与输入输出引脚说明

JK触发器工程包含顶层模块triggerJK1和底层模块trigger_module,图5.8是整个工程的模块功能图。下面介绍一下顶层模块各引脚的功能:
image.png
图5.8 JK触发器模块功能图

  • CLK:50MHz的系统基准时钟输入。为了能观察到JK触发器的翻转效果,必须降低时钟信号CLK1的频率,将CLK适当分频可得到频率为12.5HZ的时钟信号CLK1,用CLK1的上升沿作为JK触发器的触发信号。
  • Setn:置位输入信号,连接至Key_Col[0]。当Key_Row[3]输出低电平,KEY0按下时,Setn由高电平变为低电平,JK触发器输出Q恒为1。
  • Clrn:清零输入信号,连接至Key_Col[1],当Key_Row[3]输出低电平,KEY1按下时,Clrn由高电平变为低电平。当Setn为高电平,且Clrn为低电平时输出Q恒为0。且Setn信号的优先级高于Clrn信号。
  • SW_In:拨动开关输入,共有八位总线。SW_In[7:4]分别连接“JK触发器”的输入J3~J0,SW_In[3:0]分别连接“JK触发器”的输入K3~K0,用于模拟输入信号。
  • LED_Out:输出到LED灯,共有八位总线。LED_Out[7:4]分别连接“JK触发器”的输出Q3~Q0;LED_Out[3:0]分别连接“JK触发器”的输出Q_n0(对应于表5.2中的),通过LED灯的亮灭情况来观察触发器的输出效果。

程序设计

图5.9是截取自底层模块trigger_module的部分代码:
image.png
图5.9 JK触发器实验核心代码
○ 13-26:一个分频程序的基本写法,用于产生频率为12.5Hz的时钟信号CLK1。13-15定义了该分频程序需用到的内部信号及参数,需要注意的是常量的书写格式;19行代码中的“-1’b1”用于保证所得到的时钟信号CLK1的频率的准确性,非常重要;时钟信号CLK1的频率计算公式为:
image.png
○ 28-38:实现带异步置位和清零端的JK触发器的逻辑表达式,见公式(5.2)。Setn信号的优先级高于Clrn信号。

FPGA管脚配置

以下是Anlogic FPGA的IO Constraint,CLK信号、Setn信号、Clrn信号、SW_In[7:0]输入信号和LED_Out[7:0]的引脚连接信息如下表。
set_pin_assignment { CLK } { LOCATION = R7; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Clrn } { LOCATION = D11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[0] } { LOCATION = D9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[1] } { LOCATION = F9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[2] } { LOCATION = C10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Key_Row[3] } { LOCATION = E10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[0] } { LOCATION = B14; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[1] } { LOCATION = B15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[2] } { LOCATION = B16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[3] } { LOCATION = C15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[4] } { LOCATION = C16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[5] } { LOCATION = E13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[6] } { LOCATION = E16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[7] } { LOCATION = F16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Setn } { LOCATION = E11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[0] } { LOCATION = A9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[1] } { LOCATION = A10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[2] } { LOCATION = B10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[3] } { LOCATION = A11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[4] } { LOCATION = A12; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[5] } { LOCATION = B12; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[6] } { LOCATION = A13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { Sw_In[7] } { LOCATION = A14; IOSTANDARD = LVCMOS33; }

实验结果

本实验设计实现包含4组输入输出信号的JK触发器,在验证实验时仅需挑选其中一组进行观察。如挑选第四组输入输出信号,SW7和SW3分别连接J3、K3输入信号,LED7和LED3分别连接Q3、Q_n3输出信号。当SW7和SW3均拨至“DOWN”时,输出处于“保持”状态,LED7和LED3的状态不改变;当SW7和SW3分别拨至“DOWN、UP”时,输出Q为0,LED7灭,LED3亮;当SW7和SW3分别拨至“UP、DOWN”时,输出Q为1,LED7亮,LED3灭;当SW7和SW3均拨至“UP”时,输出处于“翻转”状态,每遇到一个时钟信号CLK1的上升沿,LED7和LED3的状态翻转一次。因篇幅受限,其他情况请自行验证。

思考与拓展

1 在观察现象时,发现实验结果不太理想,LED灯的状态变换情况存在一定的延时,请问这是什么原因造成的?
2 为解决1中的延时问题,令trigger_module.v文件中的参数Timex = 21'd200_000,当SW7和SW3均拨至“UP”时,LED7和LED3快速闪烁。
3 参考实验5.1中D触发器实验思路,使用结构描述的方式实现带置位和清零端的JK触发器功能。

END

文章来源:https://www.yuque.com/yingmuketang/01/wxm8ek

推荐内容

更多内容请关注走进FPGA专栏
推荐阅读
关注数
1615
内容数
27
本专栏将以【安路EG4S开发板】为例,从基础板卡信息及使用教程,基础实验设计与实现及综合性实验设计与实现带大家学习FPGA。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息