VHDL 中的有符号和无符号类型是位向量,就像 std_logic_vector 类型一样。不同之处在于,虽然 std_logic_vector 非常适合实现数据总线,但对于执行算术运算却毫无用处。 如果您尝试将任何数字添加到 std_logic_vector 类型,ModelSim 将产生编译错误:中缀运算符“+”没有可行条目。这是因为编译器不知道如何解释向量的这个比特集合。 这篇博文是基本 VHDL 教程系列的一部分。 我们必须将向量声明为有符号或无符号,以便编译器将其视为数字。 声明有符号和无符号信号的语法是:signal <name> : signed(<N
VHDL 中的并发语句是架构内的信号分配,但在正常流程构造之外。并发语句也称为并发赋值或并发进程。 当您创建并发语句时,您实际上是在创建一个具有某些明确定义的特征的流程。并发语句总是等价于使用敏感度列表的过程,其中信号赋值运算符右侧的所有信号都在敏感度列表中。 当您想要创建导致分配单个信号的简单逻辑时,这些速记符号过程很有用。您可以直接在架构中简单地分配给目标信号,而不是输入带有灵敏度列表的完整过程结构和所有这些。 这篇博文是基本 VHDL 教程系列的一部分。 如果使用得当,代码的意图仍然很清楚。无需为您想要翻转的每一位创建一个流程。 运动 在本视频中,我们将学习如何创建并发语句
Case-When 语句将导致程序根据信号、变量或表达式的值从多个不同路径中取一个。它是具有多个 Elsif 的 If-Then-Elsif-Else 语句的更优雅的替代方案。 其他编程语言也有类似的结构,使用诸如 switch 之类的关键字 , 案例 ,或选择 .除此之外,Case-When 语句通常用于在 VHDL 中实现多路复用器。继续阅读,或观看视频了解如何操作! 这篇博文是基本 VHDL 教程系列的一部分。 Case-When 语句的基本语法是:case <expression> is when <choice
模块是 VHDL 代码的独立单元。模块通过 entity 与外界通信 . 港口地图 是模块实例化的一部分,您可以在其中声明模块的输入和输出应连接到哪些本地信号。 在本系列之前的教程中,我们一直在主 VHDL 文件中编写所有代码,但通常我们不会这样做。我们创建逻辑的目的是在 FPGA 或 ASIC 设计中使用它,而不是用于模拟器。 为在模拟器中运行而创建的 VHDL 模块通常没有输入或输出信号。它是完全独立的。这就是为什么我们设计的实体是空的。 entity之间一直没有任何东西 标签和 end entity; 标记。 这篇博文是基本 VHDL 教程系列的一部分。 没有任何输入或输出信号
创建模块是重用代码的好方法,但您通常需要在整个设计中具有较小变化的相同模块。这就是泛型和泛型映射的用途。它允许您在编译时使模块的某些部分可配置。 当我们想避免一遍又一遍地输入相同的值时,就会使用常量。它们可用于在编译时定义信号向量的位宽,甚至还可以映射到通用常量。常量可以在代码中的任何地方代替信号和变量,但是它们的值在编译后不能改变。 这篇博文是基本 VHDL 教程系列的一部分。 在上一教程中,我们创建了一个总线宽度为 8 位的 4 输入多路复用器模块。但是,如果我们还需要具有不同总线宽度的类似 MUX 怎么办?将代码复制粘贴到新模块中并更改数字的唯一解决方案是吗? 幸好没有。 可
绝大多数 VHDL 设计使用时钟逻辑 ,也称为同步逻辑 或顺序逻辑 .时钟进程仅由主时钟信号触发,而不是在任何其他输入信号发生变化时触发。 时钟逻辑的基本构建块是一个称为触发器的组件 .它有不同的变体,在本教程中,我们将重点介绍带负复位的正沿触发触发器: 触发器是一个采样保持电路,这意味着它会在时钟信号的上升沿到达时将值从输入复制到输出。然后输出保持稳定在采样值,直到时钟的下一个上升沿,或直到产生复位信号。 这篇博文是基本 VHDL 教程系列的一部分。 所有时钟进程同时触发,并将立即读取它们的输入。同时,他们将输出上一次迭代的结果。时钟信号有效地在数据流中创建时间步长。这使得设
完成基本 VHDL 教程系列中的教程 12-17 后,通过此 VHDL 测验测试您的进度! 关于签名类型,哪项陈述是正确的? 他们可以表示比无符号类型更高的值 如果最左边的位是 1 值必须是负数 溢出是运行时错误 正确的!错误的! - 哪个相当于这个并发进程? 正确的!错误的! - 运行此代码后,Output 将具有什么值? 0000 0001 UUUU XXXX 正确的!错误的! - 哪个是关于港口申报的? 端口仅用于验证目的 端口可以同时包含信号和变量 端口
在之前的教程中,我们使用了 wait for 在模拟中延迟时间的声明。但是生产模块呢? wait for 声明不能用于此。这仅在模拟中有效,因为我们不能只告诉电路中的电子暂停给定时间。那么我们如何在设计模块中跟踪时间呢? 答案只是简单地计算时钟周期。每个数字设计都可以访问以固定的已知频率振荡的时钟信号。因此,如果我们知道时钟频率为 100 MHz,我们可以通过计算一亿个时钟周期来测量一秒。 这篇博文是基本 VHDL 教程系列的一部分。 要在 VHDL 中计算秒数,我们可以实现一个计数器来计算经过的时钟周期数。当这个计数器达到时钟频率的值时,例如 1 亿,我们知道已经过了一秒钟,是时候增
程序是 VHDL 中的一种子程序,可以帮助我们避免重复代码。有时需要在整个设计中的多个位置执行相同的操作。虽然创建一个模块对于小操作来说可能是多余的,但过程通常是你想要的。 可以在任何声明区域内声明过程。该过程的范围将仅限于它被声明的地方、架构、包或流程。每当您调用该过程时,它的行为就像该过程的代码插入到调用它的位置一样。 过程不像函数那样返回值,但您可以通过声明 out 来返回值 或 inout 参数列表中的信号。 这篇博文是基本 VHDL 教程系列的一部分。 创建过程的基本语法是:procedure <procedure_name> (signal|variable|
有限状态机(FSM)是一种机制,其输出不仅取决于输入的当前状态,还取决于过去的输入和输出值。 每当你需要在 VHDL 中创建某种时间相关的算法,或者遇到在 FPGA 中实现计算机程序的问题时,通常可以使用 FSM 来解决。 VHDL 中的状态机是时钟进程,其输出由状态信号的值控制。状态信号用作上一次迭代中发生的事情的内部记忆。 这篇博文是基本 VHDL 教程系列的一部分。 考虑这个路口的红绿灯状态: 交通信号灯有有限数量的状态,我们已经给了可识别的名称。我们的示例状态机没有控制输入,输出是北/南和西/东方向的灯光状态。推进这个状态机的是经过的时间和输出的先前状态。 我们可以
函数是 VHDL 中的子程序,可用于实现常用算法。一个函数接受零个或多个输入值,它总是返回一个值。除了返回值之外,函数与过程的不同之处在于它不能包含等待语句。这意味着函数总是消耗零仿真时间。 如果你熟悉其他编程语言的函数或方法,VHDL函数应该很容易掌握。在VHDL中,我们不能省略返回值或返回void,函数总是要返回一些东西,返回值必须分配给一些东西。 这篇博文是基本 VHDL 教程系列的一部分。 在 VHDL 中,有两种类型的函数,纯 和不纯 功能。一个函数是纯的意味着它不会被允许修改或读取任何外部信号。我们可以肯定,当我们调用带有特定参数的纯函数时,它总是会返回相同的值。我们说这个
不纯函数可以读取或写入其范围内的任何信号,包括那些不在参数列表中的信号。我们说这个函数有副作用 . 我们所说的副作用的意思是,不能保证每次使用相同的参数调用函数时都会返回相同的值。如果函数可以读取不在参数列表中的信号,则返回值也可能取决于这些影子参数。此外,该函数可能正在更改未从其返回值分配的外部信号。 这篇博文是基本 VHDL 教程系列的一部分。 尽管我们可以在任何可以声明普通纯函数的地方声明不纯函数,但只有在进程中使用它们才有意义。当在我们通常声明信号的架构中声明时,在编译时没有任何信号在其范围内。因此,在架构或包中声明时,不纯函数只能做纯函数所能做的事情。 使用不纯函数的动机主
可以从程序驱动外部信号。只要信号在过程范围内,就可以对其进行读写访问,即使它没有在参数列表中列出。 在体系结构的声明区域中声明的过程不能驱动任何外部信号。这仅仅是因为在编译时其范围内没有信号。另一方面,在进程中声明的过程将可以访问该进程可以看到的所有信号。 这篇博文是基本 VHDL 教程系列的一部分。 此类程序可用于在多次发生相同操作的过程中对算法进行整理。我们可以使用一个正常的过程,当你调用它时,所有的输入和输出都分配给本地信号,但这不是重点。通过在过程调用中省略输入和输出信号,我们必须减少输入,更重要的是,我们使代码更具可读性。 想象一个实现复杂通信协议的进程。如果把一些操作换成
完成基本 VHDL 教程系列的第 4 部分后,通过此 VHDL 测验测试您的进度! 我们如何在 VHDL 中测量实时? 通过使用“等待 1 ns”语句 通过计数时钟周期 通过利用传播延迟 正确的!错误的! - 哪种说法正确 过程不能包含等待语句 程序参数总是输入 使用时在过程中,return 关键字必须没有值 正确的!错误的! - 哪项陈述描述了该火控系统的根本缺陷? 缺少重置状态信号的 缺少其他-case 语句中的子句 状态信号一旦进入 Armed 状态就会卡住 初始state 将是随机的,因为没有为 State 信号分配默
链表是一种动态数据结构。当事先不知道元素的总数时,可以使用链表。它在内存中的增长和收缩,相对于它包含的项目数。 使用面向对象编程语言中的类最方便地实现链表。 VHDL 具有一些面向对象的特性,可用于从用户那里抽象出实现的复杂性。 在本文中,我们将使用访问类型、记录和受保护类型在 VHDL 中实现链表。我们将创建一个新的 VHDL 包,我们将在其中编写所有链表代码。 包 我们要做的第一件事是声明一个包含我们代码的包。 VHDL 包是可以导入另一个 VHDL 文件的类型、对象或子程序的集合。大多数 VHDL 模块从 IEEE 库中导入 std_logic_1164 包。我们正在创建自己的包,
自检测试台是一个 VHDL 程序,它可以验证被测设备 (DUT) 的正确性,而无需操作员手动检查输出。自检测试台完全独立运行,最后打印“OK”或“Failed”消息。 每个 VHDL 模块都应该有一个相关的自检测试平台。能够随时验证所有模块是否具有预期行为非常重要。例如,当您对 DUT、子模块或接口模块进行更改时。我们都知道东西会坏掉,而解决这些问题的最佳工具就是自检测试台。 被测设备 让我们直接进入并创建一个自检测试平台的示例。首先,我们需要测试的东西,一个 DUT。为此,我在下面的代码中创建了模块。这是一个二进制到格雷码的转换器。 library ieee;use ieee.std_l
交互式测试台是一种模拟器设置,其中在测试台运行时由操作员提供对被测设备 (DUT) 的输入。大多数情况下,这意味着您在模拟器控制台中输入命令来为 DUT 提供激励。 虽然您应该始终创建一个自检测试平台,但交互式测试平台可能是一个很好的补充。使用手头的交互式测试台进行临时测试比更改自检测试台的代码更容易。 很多时候,您会在实验室中发现您想在测试平台中尝试的问题。使用交互式测试平台,只需键入已观察到的输入序列即可复制模拟器中的不良行为。 Tcl 与 VHDL 交互 大多数 VHDL 模拟器使用 Tcl 作为它们的控制台语言。模拟器有一堆特定于供应商的命令,但好消息是它们可以被视为任何其他 T
循环缓冲区是用于在顺序编程语言中创建队列的流行结构,但它们也可以在硬件中实现。在本文中,我们将在 VHDL 中创建一个环形缓冲区,以在 Block RAM 中实现一个 FIFO。 在实现 FIFO 时,您必须做出许多设计决策。你需要什么样的接口?你受资源限制吗?它应该能够适应过度读取和覆盖吗?延迟可以接受吗?这些是我在被要求创建 FIFO 时出现的一些问题。 在线存在许多免费的 FIFO 实现,以及 Xilinx LogiCORE 等 FIFO 生成器。但是,许多工程师仍然喜欢实现自己的 FIFO。因为即使它们都执行相同的基本队列和出队任务,但考虑到细节时它们可能会有很大的不同。 环形缓冲
约束随机验证是一种测试平台策略,它依赖于为被测设备 (DUT) 生成伪随机事务。目标是通过与 DUT 的随机交互来实现对许多预定义事件的功能覆盖。 开源 VHDL 验证方法 (OSVVM) 是一个免费的 VHDL 库,其中包括许多用于创建受限随机测试平台的便捷包。我们对 RandomPkg 和 CoveragePck 特别感兴趣,我们将在本文中使用它们。我建议访问 OSVVM GitHub 页面以了解有关此库的更多功能。 被测设备 我将深入研究一个示例,以更好地解释受约束的随机测试平台与使用定向测试的经典测试平台有何不同。我们在本博客上一篇文章中创建了环形缓冲区 FIFO,但我们没有创建自
我很高兴地宣布,我过去六个月一直在学习的 VHDL 和 FPGA 课程开始完成。该课程目前处于测试阶段,我计划在今年秋季首次推出。 FPGA 课程适合谁? FPGA 课程面向具有其他编程语言知识但不熟悉 VHDL 和 FPGA 的开发人员。本课程将带您从初级或中级到能够理解和使用高级 VHDL 编码结构。 该课程非常适合负责 FPGA 开发的专业软件工程师。它也适合对硬件设计感兴趣的学生或自由职业者,或许正在考虑转行到 FPGA 开发。 任何具有基本编程技能的人都可以从本课程教给您的实践方法中受益。我们正在从头开始开发一个真实的实体产品。我正在向您展示如果我作为 FPGA 工程师提出要求
VHDL