Blogs

VHDL教程

吉恩·布雷尼曼2007年10月4日7条评论

几年前,当我第一次被介绍给“可编程逻辑”时,它就是对我所面临的许多挑战的解答。尽管这些零件按当今的标准是原始的(简单的PAL相对于FPGA),但它们是满足特定逻辑块需求的极具成本效益的工具。

快速链接

我继续将这些功能强大的模块整合到我的许多最新设计中。我当前最喜欢的零件线是Xilinx CoolRunner系列(XC2Cxxx)。在本文中,我将提供一个针对XC2C32A CPLD的活动设计项目的简化示例。

本示例摘自最近的数据采集项目。对于此设计,我需要生成一个时钟信号(ADCClk),该信号可以在一系列固定速率(20MHz,10MHz,4MHz,2MHz,1MHz和400KHz)上进行编程。该设备的主时钟固定为40MHz。该器件具有一个简单的4位端口(inByte),具有可选的寄存器地址(RegSel用于选择最多四个寄存器,但为简单起见,仅显示单个寄存器地址)。被寻址的寄存器在寄存器选通信号(RegStrb)的上升沿更新。根据下表,通过此端口设置时钟速率,RegSel =“ 01”。还有一条全局复位线(SeqReset),用于在以逻辑低电平驱动时将设备预置为已知状态。

InByte @ RegSel =“ 01” ADCClk速率
000 20MHz
001 10MHz
010 4MHz
011 2MHz
100 1MHz
101至111 400KHz

要构建VHDL模块,第一步是定义设备的所有输入和输出。以下是ClkDiv示例的输入和输出的声明。在Xilinx ISE环境中,VHDL编辑器使用“-”作为注释行。在我的代码中,我扩展了此注释结构,以显示输入/输出(----输出)的方向以及零件连接到的设备。 “ STD_LOGIC”是一个简单的逻辑值或位(“ 1”,“ 0”,“ X”或“ Z”),而“ STD_LOGIC_VECTOR”用于定义由几位组成的总线或字。

ClkDiv实体

下一步是声明在设计内部使用的所有信号(或变量)。在此示例中,我需要一个计数器来代表可编程的倒数计时器,该计时器将生成时钟信号(ADC_div)。计数器需要在1到40的范围内进行计数,并定义为6位向量(STD_LOGIC_VECTOR(5降至0))。需要额外的信号来创建时钟的“ toggle”寄存器(ADDClk)和用于保存命令时钟速率的寄存器(ClkSel)。创建信号时,可以为信号定义初始条件(“:=”用于指定初始值)。

讯号

在定义了所有输入,输出和内部信号之后,我们可以开始有趣的部分。然后在一系列过程和分配中定义零件的行为。当过程灵敏度列表中的信号发生更改时,将执行过程。只要赋值语句右侧的信号发生更改,就将评估赋值。在此示例中,有两个过程和一个分配。

本示例中使用的过程将执行时钟划分,并提供一个简单的可寻址锁存器来存储时钟除数命令。每当更改其任何输入(Mclk或SeqReset)时,都会执行第一个进程(ClkDiv)。输入SeqReset用于将与此过程相关的所有信号设置为默认或初始条件。这包括将时钟切换(ADCClk)的初始值设置为'0'。

时钟分频器

在上图中,线33至35用于提供复位条件。当SeqReset设置为'0'时,信号(ADCClk和ADC_div)设置为其初始状态。如果SegReset不为'0',则测试Mclk信号的下降沿(第36行在Mclk ='0'的当前值下寻找Mclk的变化)。如果条件为真,则处理其余逻辑。下一个测试是对ADC_div计数器进行零检查。如果计数器等于“ 000000”(第37行),则ADCClk信号被切换(第38行),即,如果它为“ 0”,则设置为“ 1”,反之亦然。下一步是重新加载计数器。计时器的重载阀由ClkSel值确定。在VHDL中,使用case / when语句根据信号的当前值执行操作。在此示例(第39至51行)中,使用了case / when结构来处理计数器(ADC_div)的重载。如果计数器(ADC_div)不为零(第37行),则执行“ else”子句,并且ADC_div减1(第53行)。为了减少计数器,首先将值转换为无符号值,然后从该值中减去1。然后用新值更新ADC_div。

每当更改其任何输入(RegStrb或SeqReset)时,都会执行第二个进程(ClkLatch)。输入SeqReset用于将与此过程相关的所有信号设置为默认或初始条件。这包括将时钟选择寄存器(ClkSel)的初始值设置为“ 100”(除以40或1MHz)。

时钟选择锁存器

在上图中,线60至61用于提供重置条件。当SeqReset设置为'0'时,信号(ClkSel)设置为其初始状态。如果SegReset不为'0',则对RegStrb信号进行上升沿测试(第62行使用RegStrb = 1的当前值来查找RegStrb的变化)。如果条件为真,则处理大小写/逻辑(第63至69行)。在此示例中,仅实现时钟选择寄存器。如果RegSel信号设置为“ 01”,则输入信号的最后三位(InByte)将传输到时钟选择寄存器(ClkReg)。

该示例的最后一步是分配语句,该语句将内部信号(ADCClk)传输到输出引脚(ADC_Clk)。由于ClkDiv逻辑将ADCClk用作输入和输出(ADCClk,因此使用了单独的内部信号(ADCClk)

转让声明

将所有部分放在一起,我们得到了Xilinx CPLD的VHDL程序,该程序是可编程时钟分频器。本文末尾显示的示例可以轻松地编译为XC2C32A-6VQ44部分。摘要显示该部分仅部分充满,为将来的增强留有余地。

概要

在以后的文章中,我将展示一些更高级的程序和一个VHDL测试平台来练习这些示例。

设计愉快!

基因

---------完成的示例-------

VHDL列出第1部分

VHDL列出第2部分


[-]
评论者 猫王2007年10月7日
非常好
[-]
评论者 加里·斯托弗2007年10月15日
出色的写作
[-]
评论者 srikantht2007年10月18日
做得好
[-]
评论者 rajasbtech2009年10月7日
亲爱的基因布雷尼曼, 我认为在第1行第48行中错误地给出了重载值
[-]
评论者 基因型2009年10月11日
嗨rajasbtech, 是的,您是对的,此清单上的重新加载值不正确。在以下帖子中(在测试台上),我发现了错误并修复了该列表。 感谢您对我的检查。 Gene
[-]
评论者 dat_a3cbq912011年11月13日
非常有帮助!
[-]
评论者 2012年2月23日
亲爱的先生先生, 谢谢您的博客先生,这将有助于我通过我的主题。

要发布对评论的回复,请单击每个评论所附的“回复”按钮。要发布新评论(而不是回复评论),请查看评论顶部的“写评论”标签。

注册后,您可以参加所有相关网站上的论坛,并获得所有pdf下载的访问权限。

注册

我同意 使用条款隐私政策.

试试我们偶尔但很受欢迎的时事通讯。非常容易退订。
或登录