VHDL教程
几年前,当我第一次被介绍给“可编程逻辑”时,它就是对我所面临的许多挑战的解答。尽管这些零件按当今的标准是原始的(简单的PAL相对于FPGA),但它们是满足特定逻辑块需求的极具成本效益的工具。
快速链接
- 第1部分: VHDL教程
- 第2部分: 第2部分-测试平台
- 第3部分: 结合时钟和顺序逻辑
- 第4部分: 创建分层设计
- 第5部分: 一个实际的例子-第1部分-硬件
- 第6部分: 实际示例-第2部分-VHDL编码
- 第7部分: 一个实际示例-第3部分-VHDL测试平台
我继续将这些功能强大的模块整合到我的许多最新设计中。我当前最喜欢的零件线是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”用于定义由几位组成的总线或字。
下一步是声明在设计内部使用的所有信号(或变量)。在此示例中,我需要一个计数器来代表可编程的倒数计时器,该计时器将生成时钟信号(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测试平台来练习这些示例。
设计愉快!
基因
---------完成的示例-------
- 评论
- Write a Comment 选择添加评论







要发布对评论的回复,请单击每个评论所附的“回复”按钮。要发布新评论(而不是回复评论),请查看评论顶部的“写评论”标签。
注册后,您可以参加所有相关网站上的论坛,并获得所有pdf下载的访问权限。