完成基础VHDL教程系列第6-11课后,挑战此专家精心设计的测验。旨在挑战你理解极限,不确定时用推理选最合理答案。 阅读每答后的简短解释获取微学习。 问题1 此代码将打印什么? MySignal=-2147483648 MySignal=0 MySignal=10 Correct!Wrong!- 继续 >> 问题2 此代码将打印什么? MySignal=0 MySignal=1 MySignal=10 Correct!Wrong!- 继续 >> 问题3 此代码将打印什么? MySignal=1 MySignal=9 MySignal=10 Cor
在VHDL中,signed和unsigned是专用位向量,让你能在数据总线上执行算术运算。与适合路由信号但不适合计算的std_logic_vector不同,编译器将这些类型解释为数值。 尝试添加std_logic_vector触发编译错误:No feasible entries for infix operator +,因工具无法确定如何将原始位模式视为数字。 基础VHDL教程系列之一。 为启用算术,将向量声明为signed或unsigned: signal <name> : signed(<N-1> downto 0) := <initial_value>
VHDL中并发语句是直接放在架构中、位于任何process块外部的信号赋值。也称并发赋值或并发进程。 编写并发语句时,实际上创建了一个自动敏感于赋值右侧所有信号的进程。换言之,并发赋值是带完整敏感性列表进程的语法糖。 当想实现驱动单一信号的简单组合逻辑时,此简写特别方便。无需拼写带敏感性列表的完整process结构,可直接在架构体中赋值给目标信号。 本教程属基础VHDL教程系列。 正确使用时,代码意图依然清晰——无需为每个要翻转的位搞个进程搞乱设计。 练习 本视频教学创建并发语句: 本教程创建的最终代码: library ieee; use ieee.std_logic_1164.all
Case-When语句根据信号、变量或表达式引导VHDL程序沿多条路径之一执行。它为冗长的if-then-elsif-else链提供更清晰、可读的替代方案,尤其在处理多个离散值时。 许多编程语言用switch或case构造;在VHDL中,case构造是构建多路选择器和其他选择逻辑的主食。 本文属基础VHDL教程系列。 基本语法 case语句规范结构: case <expression> is when <choice> => -- code for this branch when <choice> => -- code for this bra
在VHDL中,模块是通过其实体与外部世界通信的自包含单元。实例化的端口映射子句将实体的形式端口连接到周围设计中的信号。 模块、实体与测试平台 为FPGA或ASIC开发时,设计逻辑驻留在具有明确定义输入输出端口的模块中。无端口的模块是测试平台——仿真包装器,向被测器件(DUT)提供激励但从不出现在物理芯片上。 早期帖子将所有VHDL写在单文件,便于快速实验但不适合生产设计。分离DUT与测试平台提升可读性、复用性,使仿真层次清晰。 常见命名约定 许多团队遵循简单方案:设计文件MyModule.vhd,测试平台MyModuleTb.vhd。DUT架构常称rtl(寄存器传输级),测试平台架构称sim。
创建可复用模块是高效VHDL设计基石,但微小变化常导致代码重复。泛型和泛型映射通过允许编译期配置模块参数解决此问题,保持代码DRY且可维护。 常量避免重复硬编码相同值。它们适合定义信号向量宽度等编译期参数,甚至可映射到泛型常量。与信号或变量不同,常量值在精化后不可变,确保设计一致性。 本文属基础VHDL教程系列。 上一教程构建了8位总线宽度的4输入多路选择器。若现在需要不同宽度的类似MUX,复制粘贴整个模块不是唯一选项。 改为声明保存所需总线宽度的常量,通过泛型传递给模块。仅需在测试平台的常量声明处修改宽度。 VHDL声明常量语法: constant <constant_name>
大多数VHDL设计采用时钟逻辑——通常称为同步或时序逻辑。时钟进程仅在主时钟沿激活,无论其他输入信号如何变化。 时钟逻辑的基本元件是触发器。本教程聚焦带负复位的正沿触发触发器。见下图原理图: 作为采样保持器件,触发器在时钟上升沿捕获输入值并保持该值,直到下一个上升沿或复位信号置位。 注意: 本文属基础VHDL教程系列。 所有时钟进程同步触发并同时采样输入。时钟建立离散时间步,允许设计师将复杂逻辑划分为清晰的周期级事件。 触发器或其阵列也称寄存器。 时钟进程敏感性列表通常仅含时钟信号,因进程仅在时钟沿唤醒。其他输入对触发无影响。 下面是带同步复位的时钟进程可复用模板: process(Clk)
完成基础VHDL教程系列第12-17课,通过此针对性测验检验知识。 关于signed类型哪条陈述正确? 它们能表示比unsigned类型更高的值 若最高位为1则值必须为负 溢出是运行时错误 - 继续 >> 哪个等价于此并发进程? - 继续 >> 运行此代码后Output将是什么值? 0000 0001 UUUU XXXX - 继续 >> 关于端口声明哪条正确? 端口仅用于验证目的 端口可包含信号和变量 端口声明指定模块与外部世界的接口 -
早期教程用wait for语句在仿真中延时。但wait for不能用于生产设计,因真实电路无法指令暂停。在VHDL模块中度量时间的实用方法是计数时钟周期。 每个数字设计都有已知频率的稳定时钟信号。若时钟100MHz,一秒等于1亿个时钟滴答。通过计数这些滴答可可靠生成秒、分、小时及更长时间。 本文属基础VHDL教程系列。 我们实现计数器在每个时钟上升沿增量。当计数器达时钟频率值,一秒过去,二级“秒”计数器增量。类似方法用于分钟(60秒后增量)和小时(60分钟后增量)。可链接更多计数器得天、周、月,仅受FPGA/ASIC资源和计数器位宽限制。 较长计数器消耗更多逻辑资源,也增加传播延迟。计数器链的
在VHDL中,过程是让设计师避免重复代码块的子程序。当同一操作在多处需要时,创建完整模块可能过度。过程提供轻量级可复用方案。 过程可在任何声明区——架构、包或进程——声明,其作用域限于该区域。调用时,过程体执行如同其代码原地书写,给你模块化好处而无单独组件开销。 与函数不同,过程不直接返回值。但可在参数表声明out或inout信号传回值,实际上让过程像带输入输出的小模块。 本文属基础VHDL教程系列。 定义过程的规范语法如下: procedure <procedure_name> (signal|variable|constant <name1> : in|out|i
有限状态机(FSM)是一种确定性逻辑模型,其输出不仅取决于当前输入,还取决于过去输入和输出的序列。在FPGA设计和时序相关VHDL算法中,FSM是捕捉有状态行为的首选抽象。 VHDL中FSM通常实现为时钟进程,用state信号记忆上一配置。状态信号充当内部寄存器,使设计能对跨越多个时钟周期的事件做出反应。 基础VHDL教程 – 第3部分 红绿灯作为FSM 考虑由红绿灯控制的四向十字路口。灯光循环经过有限可见状态——如南北红、南北绿、东西红等。各状态时序(红/黄5秒,绿60秒)由经过的时钟周期驱动。 我们通过定义枚举类型列出所有可能状态来建模这些行为: type t_State is (Nor
函数是VHDL中的子程序,用于实现常用算法。函数接受零个或多个输入值,且总是返回一个值。除了返回值,函数与过程的区别在于不能包含Wait语句,意味着函数始终消耗零仿真时间。 若你熟悉其他语言的函数或方法,VHDL函数应易于掌握。VHDL中不能省略返回值或返回void,函数必须返回某值且返回值必须赋给某物。 本文属基础VHDL教程系列。 VHDL有两类函数:纯和不纯函数。纯函数不允许修改或读取任何外部信号。调用纯函数时给定特定参数,确定返回相同值。我们说该函数无副作用。 VHDL声明函数的语法: [pure|impure] function <function_name> (<
在VHDL中,不纯函数可访问或修改其词法作用域内的任何信号,包括未列为参数的信号。此能力赋予函数副作用——即使提供相同参数,返回值也可能不同,且可能改变未直接返回的外部信号。 纯函数限于确定性行为,而不纯函数通过将重复或有副作用的任务移入单个命名良好的子程序,对清理复杂状态机逻辑极具价值。 注意: 不纯函数最好声明在进程内。在架构或包层级声明无优势,因函数作用域将限于编译时已在作用域内的信号。 何时及为何使用不纯函数 典型场景包括: 计时器到期时复位计数器。 检查倒计时是否结束,避免重复计数器比较逻辑。 封装原本会弄乱主FSM的信号操作。 使用不纯函数在保持核心状态机逻辑可读的同时,仍保留
在VHDL中,只要信号在作用域内,过程即可驱动外部信号。虽然架构中声明的过程无法访问外部信号——因那些信号在编译时不可见——但定义在进程内的过程可自由读写该进程可见的任何信号。 使用进程内过程能有效清理状态机或复杂协议中的重复逻辑。通过将常见动作(如定时状态转移)封装在过程中,可减少样板代码,提高可读性,使每步意图清晰明了。 例如在红绿灯控制器中,将操作重命名为ChangeState(ToState, Minutes, Seconds),无需深究底层变量赋值即可知代码意图。 实践练习 前一教程用不纯函数驱动Counter信号并决定状态变化。但因VHDL要求函数调用必须有返回值,无法将State
完成基础VHDL教程系列第4部分后,通过此测验测试你的进度! 如何在VHDL中度量实时? 使用wait for 1 ns语句 计数时钟周期 利用传播延迟 - 继续 >> 哪条陈述为真? 过程不能包含Wait语句 过程参数总是输入 在过程中使用return关键字时必须不带值 - 继续 >> 哪条陈述描述了此火控系统的根本缺陷? 缺少State信号复位 缺少case语句的others分支 State信号一旦进入Armed状态将卡住 因未给State信号赋默认值,初始状态将随机 - 继续 >>
链表是一种动态数据结构,随元素增删而扩缩。VHDL的面向对象特性——访问类型、记录和受保护类型——使其能清晰高效地实现此结构。 创建DataStructures包 我们将所有链表逻辑封装在专用VHDL包DataStructures中。这个面向未来的名字便于日后扩展树、哈希图等结构。 package DataStructures is -- Public declarations go here end package DataStructures; package body DataStructures is -- Private declarations and implementation
自检测试平台是无需人工检查即可验证被测器件(DUT)正确性的VHDL程序。执行后自动报告OK或Failed状态,是可靠VHDL开发的必备工具。 每个VHDL模块都应有配套自检测试平台。确保任何变更——无论是DUT本身、子模块还是接口——不会静默引入回归。精心设计的测试平台是抵御隐蔽bug的第一道防线。 被测器件 我们用简单且具说明性的DUT:二进制转格雷码转换器。下面是完整RTL实现。 library ieee; use ieee.std_logic_1164.all; entity gray_converter is port ( bin : in std_logic_vector; gra
交互式测试平台是指在测试平台运行时由操作员向被测器件(DUT)提供输入的仿真器设置。通常意味着在仿真器控制台输入命令为DUT提供激励。 虽然应始终创建自检测试平台,但交互式测试平台可以作为很好的补充。手头有交互式测试平台时,临时测试比修改自检测试平台代码更容易。 常在实验室发现问题后,想在测试平台中复现。有了交互式测试平台,只需在仿真器中输入观察到的输入序列,即可复现不良行为。 Tcl与VHDL交互 大多数VHDL仿真器使用Tcl作为控制台语言。仿真器有一堆厂商特定命令,好消息是它们可像其他Tcl命令一样对待。可用Tcl创建复杂、可移植的脚本管理和支持VHDL测试平台。 从Tcl修改VHDL信
环形缓冲区是顺序编程语言中创建队列的常用结构,同样也可以在硬件中实现。本文将介绍如何用VHDL在块RAM中实现环形缓冲区FIFO。 实现FIFO时需要做许多设计决策:需要什么样的接口?资源是否受限?是否需要抗过读和过写能力?延迟是否可接受?这些都是设计FIFO时会考虑的问题。 网上有许多免费的FIFO实现,也有像Xilinx LogiCORE这样的FIFO生成器。但许多工程师仍倾向于自己实现FIFO。因为尽管它们都执行基本的入队和出队任务,但在细节上却可能有巨大差异。 环形缓冲区的工作原理 环形缓冲区是一种FIFO实现,它使用连续内存存储缓冲数据,且数据移动最少。新元素从写入时起保持在同一内存
约束随机验证是一种测试平台策略,依靠为被测设备 (DUT) 生成伪随机事务。目标是通过与 DUT 的随机交互达到预定义事件的功能覆盖率。 开源 VHDL 验证方法学 (OSVVM) 是免费 VHDL 库,包含多个便利包用于创建约束随机测试平台。我们特别关注 RandomPkg 和 CoveragePck,本文将使用它们。建议访问 OSVVM GitHub 页面了解库更多特性。 被测设备 直接进入示例以更好解释约束随机测试平台如何区别于使用定向测试的经典测试平台。上篇博文创建了环形缓冲区 FIFO,但未创建自检测试平台验证模块正确性。 我们将为环形缓冲区 FIFO 创建使用约束随机验证的完善测试
VHDL