当前位置: 首页 > news >正文

新手入门 Makefile:FPGA 项目实战教程(三)

新手入门 Makefile:FPGA 项目实战教程(三)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


系列文章目录

1、VMware Workstation Pro安装指南:详细步骤与配置选项说明
2、VMware 下 Ubuntu 操作系统下载与安装指南
3、基于 Ubuntu 的 Linux 系统中 Vivado 2020.1 下载安装教程
4、利用 Makefile 高效启动 VIVADO 软件:深入解析与实践
5、新手入门 Makefile:FPGA 项目实战教程(一)
6、新手入门 Makefile:FPGA 项目实战教程(二)

引言

在上一篇6、新手入门 Makefile:FPGA 项目实战教程(二)文章中,介绍了大概的项目结构和基础知识内容,接下来这一章我们将结合实际的工程。


文章目录

  • 新手入门 Makefile:FPGA 项目实战教程(三)
  • 系列文章目录
    • 引言
    • 五、FPGA 项目实战:LED 闪烁示例
      • 5.1 项目需求和设计概述
      • 5.2 编写 RTL 代码
      • 5.3 编写约束文件
      • 5.4 编写 Makefile
        • 变量定义
        • 目标定义
      • 5.5 编写 Tcl 脚本
        • 变量设置
        • 项目创建与设置
        • 文件添加
        • 综合与实现
        • 报告生成与比特流导出
        • 项目关闭
      • 5.6 实战操作步骤
      • 准备工作
      • 执行 Makefile
      • 清理项目
      • 5.7 以太网接口项目(高级案例)
        • 5.7.1 项目结构
        • 5.7.2 Makefile 特点
    • 未完待续。。。。


五、FPGA 项目实战:LED 闪烁示例

5.1 项目需求和设计概述

我们将通过一个简单的 LED 闪烁项目来演示如何使用 Makefile 进行 FPGA 项目开发。这个项目的目标是在 FPGA 开发板上实现一个 LED 以约 1Hz 的频率闪烁。

设计概述

  • 使用 25 位计数器对系统时钟进行分频。

  • 当计数器达到最大值时,翻转 LED 输出状态。

  • 系统时钟频率假设为 100MHz,因此计数器最大值设为 25,000,000(产生约 1Hz 的闪烁频率)。

5.2 编写 RTL 代码

创建文件src/rtl/top.v,内容如下:

module top (input clk,output reg led
);reg [24:0] counter;always @(posedge clk) beginif (counter == 25'd25000000) begincounter <= 25'd0;led <= ~led;end else begincounter <= counter + 1'b1;end
endendmodule

这个模块实现了一个简单的 LED 闪烁功能,使用 25 位计数器对系统时钟进行分频,产生约 1Hz 的闪烁频率。

5.3 编写约束文件

创建文件src/constraints/led.xdc,内容如下:

# 时钟约束
create_clock -name clk -period 10.000 [get_ports clk]
set_property PACKAGE_PIN R4 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]# LED输出约束
set_property PACKAGE_PIN U18 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports led]

这些约束指定了时钟频率和 LED 输出的物理引脚。请根据实际使用的 FPGA 开发板调整PACKAGE_PIN的值。

5.4 编写 Makefile

创建文件scripts/Makefile,内容如下:

# Makefile for Vivado automation
PROJECT_NAME ?= led_blink
VIVADO_VERSION ?= 2020.1
VIVADO_PATH ?= /tools/Xilinx/Vivado/2020.1/bin
BUILD_TCL ?= /home/zfj/fpga_project/led_blink/build_project.tclall:@echo "Starting Vivado batch mode..."@mkdir -p build && cd build && ${VIVADO_PATH}/vivado -mode batch -source ${BUILD_TCL} -tclargs $(PROJECT_NAME)@echo "Bitstream generation completed. Output files in build/ directory."clean:@echo "Cleaning project files..."@rm -rf build .Xil@rm -f ${PROJECT_NAME}.bit@echo "Clean complete.".PHONY: all clean
变量定义
  • PROJECT_NAME:定义项目名称,默认值为led_blink。这里使用了?=条件赋值运算符,表示如果该变量未被定义过,则使用后面的值进行赋值。

  • VIVADO_VERSION:指定 Vivado 版本,默认值为2020.1

  • VIVADO_PATH:指定 Vivado 安装路径下的bin目录,默认值为/tools/Xilinx/Vivado/2020.1/bin

  • BUILD_TCL:指定 Vivado 项目构建脚本的路径,默认值为/home/zfj/fpga_project/led_blink/build_project.tcl

目标定义
  • all目标:

    • 首先输出提示信息Starting Vivado batch mode...,表示开始 Vivado 批处理模式。

    • 使用mkdir -p build创建build目录(-p选项表示如果父目录不存在则一并创建),然后进入build目录。

    • 执行${VIVADO_PATH}/vivado -mode batch -source ${BUILD_TCL} -tclargs $(PROJECT_NAME)命令,以批处理模式运行 Vivado,并指定构建脚本${BUILD_TCL}以及传递项目名称参数$(PROJECT_NAME)。这一步会根据构建脚本的内容创建项目、添加源文件、约束文件,进行综合、实现等操作,最终生成比特流文件。

    • 最后输出提示信息Bitstream generation completed. Output files in build/ directory.,表示比特流文件生成完成,输出文件在build目录中。

  • clean目标:

    • 输出提示信息Cleaning project files...,表示开始清理项目文件。

    • 使用rm -rf build删除build目录及其所有内容(-rf选项表示强制递归删除),rm -rf .Xil删除.Xil目录(该目录通常包含 Vivado 相关的缓存文件),rm -f ${PROJECT_NAME}.bit删除生成的比特流文件(-f选项表示强制删除,不提示)。

    • 最后输出提示信息Clean complete.,表示清理完成。

5.5 编写 Tcl 脚本

创建文件scripts/build_project.tcl,内容如下:

# /home/zfj/fpga_project/led_blink/build_project.tcl
set project_name [lindex $argv 0]# 设置项目路径
set project_dir [file normalize [file dirname [info script]]]
set src_dir ${project_dir}/src
set constr_dir ${project_dir}/constraints# 创建项目在build目录
create_project -force $project_name ${project_dir}/build -part xc7z020clg400-1
set_property target_language Verilog [current_project]# 添加源文件
add_files -norecurse [glob -nocomplain ${src_dir}/*.v ${src_dir}/*.vhd]# 添加约束文件
if {[file exists ${constr_dir}/top.xdc]} {add_files -fileset constrs_1 -norecurse ${constr_dir}/top.xdc
} else {puts "WARNING: Constraint file not found at ${constr_dir}/top.xdc"
}# 设置实现策略
set_property strategy Performance_Explore [get_runs impl_1]# 运行综合与实现
launch_runs synth_1
wait_on_run synth_1launch_runs impl_1 -to_step write_bitstream
wait_on_run impl_1# 生成报告
open_run impl_1
report_utilization -file ${project_dir}/build/${project_name}_utilization.rpt
report_timing_summary -file ${project_dir}/build/${project_name}_timing.rpt# 导出比特流
set bitstream_path ${project_dir}/build/${project_name}.runs/impl_1/*.bit
if {[llength [glob -nocomplain $bitstream_path]] > 0} {file copy -force [lindex [glob $bitstream_path] 0] ${project_dir}/${project_name}.bitputs "Bitstream copied to: ${project_dir}/${project_name}.bit"
} else {puts "ERROR: Bitstream file not found!"
}# 关闭项目
close_project
exit
变量设置
  • project_name:通过[lindex $argv 0]获取命令行传递的第一个参数,作为项目名称。

  • project_dir:通过[file normalize [file dirname [info script]]]获取当前脚本所在目录的规范化路径,作为项目目录。

  • src_dir:定义源文件目录为${project_dir}/src

  • constr_dir:定义约束文件目录为${project_dir}/constraints

项目创建与设置
  • create_project -force $project_name ${project_dir}/build -part xc7z020clg400 - 1:在${project_dir}/build目录下创建名为$project_name的项目,并指定芯片型号为xc7z020clg400 - 1-force选项表示如果项目已存在则强制覆盖。

  • set_property target_language Verilog [current_project]:设置当前项目的目标语言为 Verilog。

文件添加
  • add_files -norecurse [glob -nocomplain ${src_dir}/*.v ${src_dir}/*.vhd]:添加src_dir目录下所有的.v.vhd文件作为源文件,-norecurse表示不递归查找子目录,[glob -nocomplain ${src_dir}/*.v ${src_dir}/*.vhd]使用glob命令匹配指定的文件。

  • if {[file exists ${constr_dir}/top.xdc]} {... } else {... }:检查${constr_dir}目录下是否存在top.xdc约束文件,如果存在则使用add_files -fileset constrs_1 -norecurse ${constr_dir}/top.xdc将其添加到constrs_1文件集中,否则输出警告信息。

综合与实现
  • set_property strategy Performance_Explore [get_runs impl_1]:设置impl_1运行的实现策略为Performance_Explore,用于优化性能。

  • launch_runs synth_1:启动综合过程,生成网表文件。

  • wait_on_run synth_1:等待综合过程完成。

  • launch_runs impl_1 -to_step write_bitstream:启动实现过程,直到write_bitstream步骤,即生成比特流文件。

  • wait_on_run impl_1:等待实现过程完成。

报告生成与比特流导出
  • open_run impl_1:打开impl_1运行结果。

  • report_utilization -file ${project_dir}/build/${project_name}_utilization.rpt:生成资源利用率报告,并保存到${project_dir}/build/${project_name}_utilization.rpt文件中。

  • report_timing_summary -file ${project_dir}/build/${project_name}_timing.rpt:生成时序总结报告,并保存到${project_dir}/build/${project_name}_timing.rpt文件中。

  • set bitstream_path ${project_dir}/build/${project_name}.runs/impl_1/*.bit:设置比特流文件路径。

  • if {[llength [glob -nocomplain $bitstream_path]] > 0} {... } else {... }:检查是否生成了比特流文件,如果生成了则将其复制到项目目录下,并命名为${project_dir}/${project_name}.bit,同时输出提示信息;如果未找到比特流文件,则输出错误信息。

项目关闭
  • close_project:关闭当前项目。

  • exit:退出 TCL 脚本。

5.6 实战操作步骤

准备工作

确保已经安装了 Vivado 软件,并且其版本与 Makefile 中指定的VIVADO_VERSION一致。同时,将 FPGA 项目的源文件、约束文件等按照上述项目结构放置在相应目录下。

执行 Makefile

  1. 打开终端,进入 FPGA 项目所在目录。

  2. 执行make all PROJECT_NAME=led_blink命令,Makefile 会按照定义的规则,调用 Vivado 以批处理模式运行build_project.tcl脚本,完成项目的创建、源文件添加、约束文件添加、综合、实现、报告生成以及比特流导出等一系列操作。在执行过程中,终端会输出相应的提示信息,可以根据这些信息了解构建过程的进展情况。
    在这里插入图片描述

  3. 如果构建过程中出现错误,根据错误提示检查源文件、约束文件以及 Makefile 和build_project.tcl脚本的配置是否正确。常见的错误可能包括文件路径错误、语法错误、芯片型号不匹配等。

  4. bit流文件的生成:
    在这里插入图片描述

清理项目

当需要重新构建项目或者清理生成的文件时,可以执行make clean命令。该命令会删除build目录及其所有内容、.Xil目录以及生成的比特流文件,确保项目处于初始状态,以便进行下一次构建。

生成比特流后,可以使用 Vivado 的硬件管理器将其下载到 FPGA 板卡上,观察 LED 是否开始闪烁。

5.7 以太网接口项目(高级案例)

对于更复杂的项目,例如以太网接口设计,可以采用类似的方法进行 Makefile 和 Tcl 脚本的编写。

5.7.1 项目结构

以太网接口项目的结构如下:

ethernet/
├── src/
│   ├── rtl/
│   │   ├── eth_mac.v     # 以太网MAC模块
│   │   └── eth_top.v     # 顶层模块
│   ├── constraints/
│   │   └── eth.xdc       # 约束文件
│   └── ip/
│       └── clk_wiz.xci   # 时钟IP核
├── scripts/
│   ├── build_project.tcl # Tcl脚本
│   └── Makefile         # Makefile文件
└── output/              # 生成的输出文件
5.7.2 Makefile 特点

以太网接口项目的 Makefile 与 LED 项目类似,但可能需要更多的目标和更复杂的 Tcl 脚本,以处理 IP 核和更复杂的约束:

# 以太网接口项目的Makefile可能包含以下目标:# 生成IP核
ipgen:@echo "Generating IP cores..."$(VIVADO) -mode batch -source $(TCL_SCRIPT) ipgen# 综合设计
synth: ipgen@echo "Synthesizing design..."$(VIVADO) -mode batch -source $(TCL_SCRIPT) synth# 实现设计
impl: synth@echo "Implementing design..."$(VIVADO) -mode batch -source $(TCL_SCRIPT) impl

在这个例子中,ipgen目标用于生成 IP 核,synth目标依赖于ipgen,确保在综合前已经生成了必要的 IP 核。

未完待续。。。。

在这里插入图片描述

http://www.dtcms.com/a/333712.html

相关文章:

  • Android - 动态切换桌面图标
  • Rubber Band Optimation算法python实现
  • linux-----------------锁
  • [Chat-LangChain] 会话图(LangGraph) | 大语言模型(LLM)
  • 第二十四天:虚函数与纯虚函数
  • 速卖通平台关键字搜索商品列表列表接口实现指南:从接口分析到代码落地
  • Linux之高可用集群实战(二)
  • Tokenizer(切词器)的不同实现算法
  • 异步任务执行顺序
  • DC6v-36V转3.2V1A恒流驱动芯片WT7017
  • 【嵌入式C语言】五
  • 如何一个响指删除计算机里的一半文件?(二)
  • 【工具】多图裁剪批量处理工具
  • 基于element-plus和IndexedDB数据库的基础表单
  • 嵌入式:Linux软件编程:线程
  • 深入浅出的 RocketMQ-面试题解析
  • AI架构师生存手册:图解避坑MCP工具链/智能体RAG/推理蒸馏实战
  • TF 上架协作实战,跨部门配合下的内测发布节奏管理
  • Cursor CLI 技术解析:免费调用 GPT-5 的命令行方案
  • 工控机的用途与介绍:工业自动化的重要引擎
  • [激光原理与应用-287]:理论 - 波动光学 - 电磁波既能承载能量,又能承载信息?
  • Systemd Service 文件详解
  • 反射和类加载机制
  • Leetcode 最小生成树系列(2)
  • 深入解析 Monkey OCR:本地化、多语言文本识别的利器与实践指南
  • 德州扑克游戏术语
  • 什么是Redis的哨兵模式
  • 针对前面2篇文章的一个细节的修订(UAC ADC/DAC录音播放,以及UAC ADC/PWM录音播放)
  • const修饰指针用法详解
  • libdrm 和 libgbm