Quick Start
- 安装工具:下载并安装 ModelSim(Intel FPGA 版或 OEM 版)或 GHDL(Windows 下推荐 MSYS2 发行版,Linux 下用包管理器)。
- 创建工程目录:新建文件夹
vhdl_tutorial,内含src(源码)、sim(仿真脚本)、wave(波形输出)子目录。 - 编写 VHDL 源码:在
src下创建top.vhd(一个简单的 D 触发器)和tb_top.vhd(测试平台)。 - 编写仿真脚本:ModelSim 用
.do文件;GHDL 用Makefile或 Shell 脚本。 - 编译与运行:
— ModelSim:vlib work; vcom src/*.vhd; vsim work.tb_top; run 100 ns
— GHDL:ghdl -a --std=08 src/*.vhd; ghdl -e --std=08 tb_top; ghdl -r --std=08 tb_top --vcd=wave/tb_top.vcd - 查看波形:ModelSim 内置波形窗口;GHDL 用 GTKWave 打开
.vcd文件。 - 验收:波形中 clk 上升沿后 q 跟随 d 变化,仿真无错误/警告。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件/板卡 | Intel Cyclone V (5CSEMA5U23C8) | 用于上板验证(可选) | Xilinx Artix-7 / 纯仿真无需板卡 |
| EDA 版本 | ModelSim Intel FPGA Starter Edition 2024.1 | 免费版,支持 VHDL-2008 | ModelSim PE/DE(付费) |
| 仿真器 | GHDL 4.0.0 (2025-12 发布) | 开源,支持 VHDL-2008 大部分特性 | NVC(另一开源仿真器) |
| 波形查看 | GTKWave 3.3.120 | 配合 GHDL 使用 | ModelSim 内置波形 |
| 时钟/复位 | 100 MHz 时钟 (周期 10 ns),异步低电平复位 | 测试平台中生成 | 可调频率 |
| 接口依赖 | 无(纯 RTL 仿真) | 无需外部 IP 或硬件 | — |
| 约束文件 | 无(仿真不需要 .sdc) | 上板时才需要 | — |
| 操作系统 | Windows 10/11 或 Ubuntu 22.04/24.04 | GHDL 跨平台一致 | macOS (Homebrew) |
目标与验收标准
- 功能点:用 VHDL 实现一个 4 位计数器(带异步复位和使能),仿真验证计数行为正确。
- 性能指标:仿真运行时间 < 5 秒(1000 个时钟周期),无时序违例(仿真中无 setup/hold 检查,但 ModelSim 可报 warning)。
- 资源/Fmax:纯仿真不涉及;若综合,目标 Fmax > 200 MHz(以 Cyclone V 为例)。
- 验收方式:
— ModelSim:Transcript 窗口无 Error,波形中 q 从 0 递增到 15 后回绕。
— GHDL:终端无错误输出,GTKWave 波形与 ModelSim 一致。
实施步骤
工程结构
vhdl_tutorial/
├── src/
│ ├── counter.vhd # 4位计数器实体与架构
│ └── tb_counter.vhd # 测试平台
├── sim/
│ ├── modelsim_run.do # ModelSim 脚本
│ └── Makefile # GHDL 构建脚本
└── wave/ # 波形文件输出目录逐行说明
- 第 1 行:
src/目录存放所有 VHDL 源文件,便于管理。 - 第 2–3 行:
counter.vhd是设计模块,tb_counter.vhd是测试平台。 - 第 5–6 行:仿真脚本与 Makefile 放在
sim/下,与源码分离。 - 第 7 行:
wave/用于存放 GHDL 生成的 .vcd 文件。
关键模块:counter.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity counter is
generic (
WIDTH : integer := 4
);
port (
clk : in std_logic;
rst_n : in std_logic;
en : in std_logic;
q : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;
architecture rtl of counter is
signal count : unsigned(WIDTH-1 downto 0);
begin
process(clk, rst_n)
begin
if rst_n = '0' then
count <= (others => '0');
elsif rising_edge(clk) then
if en = '1' then
count <= count + 1;
end if;
end if;
end process;
q <= std_logic_vector(count);
end architecture;逐行说明
- 第 1–3 行:引入标准库和数值运算库,
numeric_std提供unsigned类型和算术运算。 - 第 5–7 行:实体声明,使用
generic定义位宽WIDTH,默认 4,便于参数化。 - 第 8–12 行:端口定义——时钟、异步复位(低有效)、使能、输出。
- 第 14 行:架构体开始,命名为
rtl。 - 第 15 行:内部信号
count为unsigned类型,用于计数。 - 第 17 行:进程敏感列表包含
clk和rst_n,实现异步复位。 - 第 19–20 行:复位时
count清零,使用(others => '0')可适应任意位宽。 - 第 21–24 行:时钟上升沿且使能有效时,
count递增。 - 第 26 行:将
unsigned转换为std_logic_vector赋值给输出端口。
关键模块:tb_counter.vhd
library ieee;
use ieee.std_logic_1164.all;
entity tb_counter is
end entity;
architecture sim of tb_counter is
constant WIDTH : integer := 4;
signal clk : std_logic := '0';
signal rst_n : std_logic := '0';
signal en : std_logic := '1';
signal q : std_logic_vector(WIDTH-1 downto 0);
constant CLK_PERIOD : time := 10 ns;
begin
-- 实例化 DUT
uut : entity work.counter
generic map (WIDTH => WIDTH)
port map (
clk => clk,
rst_n => rst_n,
en => en,
q => q
);
-- 时钟生成
clk <= not clk after CLK_PERIOD / 2;
-- 激励过程
stim_proc : process
begin
rst_n <= '0';
wait for 20 ns;
rst_n <= '1';
wait for 200 ns;
en <= '0';
wait for 50 ns;
en <= '1';
wait for 300 ns;
wait;
end process;
end architecture;逐行说明
- 第 1–2 行:引入标准库。
- 第 4–5 行:测试平台实体无端口。
- 第 7 行:架构体开始,命名为
sim。 - 第 8 行:定义常量
WIDTH,与 DUT 的 generic 匹配。 - 第 9–12 行:声明内部信号,
clk初始化为 '0',rst_n初始为 '0'(复位状态),en初始为 '1'。 - 第 13 行:时钟周期常量 10 ns(100 MHz)。
- 第 15–21 行:实例化 DUT,使用
entity work.counter直接引用。 - 第 24 行:时钟生成语句,每半个周期翻转一次。
- 第 27–36 行:激励过程——先复位 20 ns,然后释放复位;200 ns 后拉低使能 50 ns,再拉高;300 ns 后结束仿真。
仿真脚本:ModelSim (.do)
vlib work
vmap work work
vcom -2008 ../src/counter.vhd
vcom -2008 ../src/tb_counter.vhd
vsim work.tb_counter
add wave sim/*
run 600 ns逐行说明
- 第 1 行:创建库目录
work。 - 第 2 行:映射逻辑库
work到物理目录。 - 第 3–4 行:编译 VHDL 源文件,
-2008指定 VHDL-2008 标准。 - 第 5 行:启动仿真,顶层为
tb_counter。 - 第 6 行:将
sim作用域下所有信号添加到波形窗口。 - 第 7 行:运行 600 ns 后停止。
仿真脚本:GHDL (Makefile)
GHDL=ghdl
GHDLFLAGS=--std=08
all: compile elaborate run
compile:
t$(GHDL) -a $(GHDLFLAGS) ../src/counter.vhd ../src/tb_counter.vhd
elaborate:
t$(GHDL) -e $(GHDLFLAGS) tb_counter
run:
t$(GHDL) -r $(GHDLFLAGS) tb_counter --vcd=../wave/tb_counter.vcd --stop-time=600ns
clean:
t$(GHDL) --clean
trm -f ../wave/*.vcd逐行说明
- 第 1–2 行:定义 GHDL 命令和通用编译选项
--std=08(VHDL-2008)。 - 第 4 行:默认目标
all依次执行编译、细化、运行。 - 第 6–7 行:
compile目标调用ghdl -a分析所有源文件。 - 第 9–10 行:
elaborate目标调用ghdl -e细化顶层tb_counter。 - 第 12–13 行:
run目标运行仿真,输出 VCD 波形文件,并设置停止时间 600 ns。 - 第 15–17 行:
clean目标清理中间文件。
常见坑与排查
- GHDL 编译错误 “cannot find entity”:检查文件路径和
--std版本;确保ghdl -a时文件顺序正确(依赖的包先编译)。 - ModelSim 仿真无波形:确认
add wave sim/*作用域正确;或在 GUI 中手动添加。 - GHDL 运行后 .vcd 为空:仿真时间太短未产生信号变化;检查
--stop-time是否足够。 - VHDL-2008 特性在 ModelSim 免费版不支持:若使用
std_logic_vector的to_01等函数,需确认版本;改用 VHDL-1993 兼容写法。
原理与设计说明
为什么选择 GHDL vs ModelSim?
- GHDL 优势:完全免费开源,跨平台一致,脚本化友好,适合 CI/CD 集成;支持 VHDL-2008 大部分特性(截至 4.0.0 版本)。劣势:波形查看需外部工具(GTKWave),调试能力弱于 ModelSim;不支持混合语言仿真(VHDL+Verilog)原生。
- ModelSim 优势:集成波形查看、信号驱动列表、Tcl 脚本调试,生态成熟;Intel 免费版已能满足大多数教学需求。劣势:免费版有性能限制(编译速度慢于 GHDL),商业版价格高。
关键 trade-off:
- 资源 vs Fmax:仿真不涉及资源与 Fmax,但代码风格会影响综合结果。本计数器使用
unsigned加法,综合工具会推断出加法器,位宽越大延迟越高。若追求 Fmax,可改用二进制序列计数器(如 Johnson 计数器)。 - 吞吐 vs 延迟:本设计每个时钟周期计数一次,吞吐为 1 计数/周期,延迟为 0(组合输出)。若需更高吞吐,可考虑流水线结构。
- 易用性 vs 可移植性:使用
numeric_std是标准做法,可移植到任何 VHDL 仿真器;避免使用std_logic_arith(非 IEEE 标准)。
验证与结果
| 项目 | ModelSim (Intel FPGA 2024.1) | GHDL 4.0.0 + GTKWave |
|---|---|---|
| 编译时间(2 个文件) | ~1.2 s | ~0.3 s |
| 仿真时间(600 ns) | ~0.8 s | ~0.2 s |
| 波形查看 | 内置,即时刷新 | 需手动打开 GTKWave |
| VCD 文件大小 | N/A(内部格式) | ~4 KB |
| 错误/警告数 | 0 Error, 0 Warning | 0 Error, 0 Warning |
| 功能正确性 | 计数 0→15→0,使能暂停 | 与 ModelSim 一致 |
测量条件:Windows 11, Intel i5-12400, 16 GB RAM;GHDL 通过 MSYS2 安装;ModelSim 为 Intel FPGA Starter Edition。数值为示例典型值,以实际工程与数据手册为准。
故障排查(Troubleshooting)
原因</
- 现象:GHDL 编译报错 “error: cannot find entity ‘counter’”。
原因:文件未正确包含或编译顺序错误。
检查点:确认counter.vhd在src/下,且先于tb_counter.vhd编译。
修复:调整 Makefile 中文件列表顺序。 - 现象:ModelSim 仿真时波形显示 “#” 或 “U”。
原因:信号未初始化或复位未正确施加。
检查点:检查rst_n是否在仿真开始后拉高。
修复:在测试平台中先保持复位 20 ns 再释放。 - 现象:GHDL 运行后无 .vcd 文件生成。
原因:未指定--vcd选项或路径错误。
检查点:检查 Makefile 中--vcd=../wave/tb_counter.vcd。
修复:确保wave/目录存在。 - 现象:GTKWave 打开 .vcd 后信号名显示为
tb_counter.uut.count等长名称。
原因:GHDL 默认使用层次化路径。
检查点:无问题,可正常查看。
修复:可在 GTKWave 中右键重命名。 - 现象:ModelSim 编译报错 “vcom: Error: … (vcom-1136) Unknown identifier ‘std_logic’”。
原因:未正确使用ieee.std_logic_1164库。
检查点:检查源码中是否有use ieee.std_logic_1164.all;。
修复:添加缺失的 use 语句。 - 现象:GHDL 仿真速度极慢(>10 s 对于小设计)。
原因:可能使用了--std=93且代码中有非标准写法。
检查点:尝试--std=08或检查是否有无限循环。
修复:改用--std=08并避免wait for 0 ns等语句。 - 现象:ModelSim 仿真时波形中
q一直为 0。
原因:使能信号en未拉高。
检查点:检查测试平台中en的赋值。
修复:确保en <= '1'在复位释放后有效。 - 现象:GHDL 编译时警告 “warning: use of deprecated package ‘std_logic_arith’”。
原因</



