本节摘要:VHDL 与软件语言的根本差异在于并发——代码描述的是同时存在的电路结构,而不是逐条执行的指令。本节用对照代码建立"实体管接口、架构管内部、信号是连线"的核心心智模型,为整本教程的动手路线打好思维底子。
写过 C 或 Python 的人看到下面两行,会本能地认为"先执行第一行,再执行第二行":
y <= a and b; y <= a or c;
在 VHDL 里这个本能是错的。这两行是并发信号赋值,各自描述一根组合逻辑的连线:一根接的是与门输出,一根接的是或门输出。两根线同时驱动同一个信号 y,在真实的电路上这叫多驱动冲突,仿真器会直接把 y 驱动成 'X'(冲突值)警告你。它不是"后一行覆盖前一行",而是"两根线打架"。
这不是语法细节,这是世界观。软件语言的世界里时间是串行的:一条语句执行完才有下一条。硬件的世界里时间是并行的:上电的一瞬间,所有门电路同时开始工作。VHDL 作为硬件描述语言,用文本去刻画这个并行世界,所以它的基本单位不是"语句流",而是"同时存在的结构"。

把世界观落成代码,只需要三块积木。**实体(entity)**描述电路的外观:有哪些输入输出端口、每个端口是什么方向、什么类型。它相当于芯片的封装俯视图,只管引脚不管内部。**架构(architecture)**描述电路的内脏:端口之间怎么连、有哪些中间信号、有没有寄存器和状态机。一个实体可以配多个架构,比如一个行为级描述用于仿真、一个门级描述用于综合。**信号(signal)**是架构内部的连线,声明在 architecture 与 begin 之间。
看一个最小的完整例子,一个二选一数据选择器:
library ieee; use ieee.std_logic_1164.all; -- 实体:只描述接口,不涉及任何实现 entity mux2 is port ( a, b : in std_logic; -- 两路数据输入 sel : in std_logic; -- 选择信号 y : out std_logic -- 数据输出 ); end entity mux2; -- 架构:描述 a、b、sel 到 y 的连接关系 architecture dataflow of mux2 is begin y <= a when sel = '0' else b; end architecture dataflow;
逐行拆开看。library ieee; use ieee.std_logic_1164.all; 引入标准逻辑包,std_logic 这个类型就住在里面,几乎所有设计的第一行都是它。实体部分三个输入一个输出,in/out 是端口方向——这个方向约束是认真的:输入端口不能被赋值,输出端口不能被读取,违反了编译器直接报错。架构里的核心只有一句条件信号赋值:sel 为 '0' 时 y 接到 a,否则接到 b。注意 '0' 带单引号,它是 std_logic 类型的字面量,不是整数。
光看不动手,思维切换不会发生。把上面这个选择器存成你的第一个源文件,然后做两个实验。实验一:把架构里的语句复制成两行不同目标——
architecture dataflow of mux2 is signal tmp : std_logic; begin tmp <= a when sel = '0' else b; y <= tmp nand sel; -- 故意再接一级逻辑 end architecture dataflow;
编译、仿真,你会看到 y 比 sel 变化晚了一瞬间(仿真里的 delta 延迟),因为信号经过了 tmp 这根中间连线。实验二:把两句的书写顺序对调,波形完全不变。这两个实验合起来说明一件事:架构里的并发语句描述的是拓扑,拓扑与书写顺序无关。
⚠️ 常见坑:从软件转过来的人最爱上溯输出端口,比如想在架构里读 y 的值参与运算。VHDL 不允许直接读 out 端口,标准做法是声明一个内部信号算好,再赋给端口,或者把端口声明成
buffer方向(综合器支持,但可读性差,不推荐)。
真实工程的源文件里还有几类常驻成员,先混个脸熟。库与包(library / package):std_logic、numeric_std 这些类型与函数都住在标准包里,文件开头那两行 use 就是进口手续;自己反复使用的类型、常量与子程序也可以打成私有包,多个设计共用一份。配置(configuration):当一个实体挂了多个架构时,配置决定这次仿真或综合用哪一个,相当于给实现"点名",第 2 章会再遇到它。测试台(testbench):给设计喂输入、检查输出的顶层壳子,第 1.3 节马上动手写。一个典型工程的文件构成大致是:设计文件若干、私有包零到若干、测试台若干、顶层测试台一个。现在只需要记住这个目录骨架,每个成员都会在后续章节亲手写一遍。
还有一件小事值得从第一天养成:注释与命名的纪律。VHDL 的注释由双横线开始到行尾,本节代码里的每条注释都在示范"注释写意图、不写翻译"——-- 两路数据输入 说的是这根线的角色,而不是把 port 翻译成中文。信号名、架构名同理:dataflow 说明这是数据流风格,rtl 说明这是可综合实现。硬件代码的第一读者是几个月后的你,其次才是综合器,顺序别弄反。
下一节解决"在哪写、在哪编译、在哪看波形"的问题——三条工具路线,总有一条适合你的电脑和板卡。