浅谈《数字逻辑设计》课程中一种轻量化的Verilog编写环境配置
浅谈《数字逻辑设计》课程中一种轻量化的Verilog编写环境配置
副标题:并以此为例探讨大AI时代学生的AI使用素养
更新
- 改变了一些格式以及用语
- 增加了一些提示
- 列出了相关网站、下载链接等
- 更改文件结构将 powershell 代码存为 .ps1 文件并存入
\scripts文件夹内,文件结构更为合理。并修改了相关表述。 - Github : https://github.com/zsj6315/-CS-Logic-and-Computer-Design-Fundamentals-Labs
0 前言
好吧其实本文并没有这么严肃... qwq
背景1:数逻课程提供的 ISE 写 verilog 代码难用的要似... 于是想转到 VScode 这种熟悉的平台上写,最好能编写仿真实现烧录全覆盖就好了wow
背景2:FDS 课不是要写 project 并互评嘛,看了一下三个给我评分的老哥,有点绷不住 lmao。第一个人一眼AI,评语像是骈体文,也没啥营养... 第二个人用眼过度视觉疲劳看不到我的 readme.md 和复杂度分析部分就说我没写;还有第三位更是重量级,不会怎么运行我的代码,开始隔空压力我,还说了一句:
In fact when I unified compilated the files in the given way, the code didn't output in the ans.out, but created some .o files, which may indicated something wrong.
很难想象这位是怎么过 C 语言基础的。大家可以搜搜 .o 文件是啥,反正 which may indicated something wrong 这句话承包了我一天的笑点。本来想笑话第一位老哥只会用 AI 的,emm... 后二位还不如用 AI 检查/帮助一下呢。
乐子归乐子,其实这三位老哥无非是当下某些现象的缩影:面对强大的新技术 AI,有的同学食髓知味,不料沉沦于此,反而阻碍了思考;有的同学嗤之以鼻,认为 AI 不过玩具尔,何以辅助学习?殊不知自己不足之处仍然很多,用 AI 辅助大有裨益。
很不幸,我也常有以上之时刻,究其原因,人之惰性使然尔。于此反思,与诸位共勉...
言归正传,近日内成功用 AI 辅助探究解决了背景1里的需求,希望能和大家探讨一下心路历程,顺便分享一下我使用 AI 的一些感触awa
注:本文中使用 DeepSeek,其他的通用大模型 AI 也可以类似分析。对 AI 的回答进行了简化,但意思基本一致。
1 简谈 AI 的搜索
这部分大家比我会用好吧~主要分享一下何时使用 AI 去搜索比较合适呢?
我的观点是:当你觉得这个问题问一个(有相关经验的)人比问搜索引擎答案更加准确的时候,你就主动地使用 AI 的联网搜索而非浏览器。
这是因为这种问题往往是宽泛的,多解的,甚至问题本身可以质疑。
例如:在 XX 地方旅游,我想住酒店,推荐?
问题指向不明(时间价位没讲),多解(价格、位置、环境等各有优势),甚至问题本身可以质疑(会不会民宿更好呢)。这种问题你问浏览器,一定不会有顺心的答案的(还有极多广告)。问 AI 必然客观全面很多。
M(Me) : 我想上海一日游,外滩附近酒店推荐
D(DeepSeek) : 外滩附近是上海的核心区域,酒店选择丰富,适合不同预算和需求。以下根据位置、性价比和特色推荐几家酒店,涵盖高端、中端和经济型,方便你的一日游行程:...
M : 果然 AI 建议更全面,还有各种小 tips
例如:天气预报 / 实时股价
这种确定性的问题,答案要求准确无误,当然直接查浏览器啦。
向 AI 提问的风格我会直接体现在下文。
2 泛选提问:确定方向
不知道大家又没有和我一样讨厌图形化界面的呢... 总感觉还是直接写代码好,感觉对项目的掌控感更强,心里更踏实qaq
于是向 AI 问询:
M: 我想使用 verilog 代码进行编写代码,仿真,实现以及烧录,请你推荐轻量化的平台,不需要图形化界面。每一步可以分别来。
D: 轻量化文本编辑器推荐
Vim、Emacs以及VS Code,仿真验证:Icarus Verilog+GTKWave,综合实现:Vivado Tcl命令行自动化
我一直使用的代码编辑器是 VS Code,于是便确认了大致方向:
VSC + Iverilog + Vivado(tcl)
以下的例子参看:前辈的力量
以此实验为例进行讲解,大家可以收藏数逻实验。(我是宝藏矿工)
3 漫长探索:耐心考验
当然写本文时已经大功告成啦,然而中间的试错真的要命啊qwq
诚然 AI 也有犯错误,但是大部分时间是自己降智了,不过成功时获得感很足(
本文给出的代码都是验证过正确性并下板过的,大家放心食用~
Hint:如果想要跟着本文做到底的话,建议先完成 3.3.1 的安装操作,等待安装时再回来做 3.1 等,因为 vivado 安装很耗时间。
3.1 VS Code
这部分网上的教程太多了,VSC 的单独配置就不另外说啦。
需要注意 VSC 与其他东西结合的时候大部分时间需要自己做一些配置,最常见的就是配置环境变量。
配置环境变量基本流程
通常是下载好一个东西之后,在它的文件夹里面找到 bin 这个文件夹,然后复制它的路径,系统设置里搜索环境变量,分别添加至系统变量和环境变量即可。以下为 AI 回答:
步骤 1:打开环境变量设置
- 右键点击 “此电脑” → “属性” → “高级系统设置” → “环境变量”。
步骤 2:编辑用户或系统变量
- 用户变量:仅对当前用户生效。
- 系统变量:对所有用户生效(需管理员权限)。
- 操作示例(添加 Python 到 PATH):
- 选中
Path→ “编辑” → “新建” → 输入路径(如C:\Python39\)。 - 点击 “确定” 保存所有窗口。
- 选中
可以看到比较详尽。网上教程也多,不再赘述。
配置环境变量完成后,最好命令行内输出版本信息以验证下载完毕。
还有就是 VS code 要重启一次,安装的东西才能加载到终端。
3.2 Iverilog
发现网上已有了详尽的教程,这时果断放弃 AI,选择跟上大佬的脚步。
文章比较详细,不过我自己使用的时候有条件取舍了一些。第二篇文章我只跟着做了第一章的内容,已经够用了。
跟着做比较轻松,这里就不再赘述。直接看例子:
建立文件夹如下:
LAB7
├── build
├── constraints
│ └── fpga.xdc
├── scripts
| ├── simul.ps1
| ├── build.ps1
│ ├── build.tcl
| ├── program.ps1
│ └── program.tcl
└── src
├── clkdiv.v
├── createnumber.v
├── display.v
├── MUX41.v
├── MyMC14495.v
├── testbench_MUX41.v
├── testbench_top.v
└── top.v
文件内容在最后。如果你是在博客园中浏览,请点击右侧大纲跳转到 “4 源码” 部分。
注意:仿真时top.v 中第 23 行 .clk(clkd[17]) 改为 .clk(clkd[3]),第 25 行 .scan(clkd[18 : 17]) 改为 .scan(clkd[8 : 7])。实现时改回来。
保存所有代码后,打开 powershell 脚本文件 simul.ps1 并学习以下代码:
iverilog -o .\build\wave.out .\src\MUX41.v .\src\MyMC14495.v .\src\clkdiv.v .\src\top.v .\src\display.v .\src\createnumber.v .\src\testbench_top.v
vvp -n .\build\wave.out
其意思是 iverilog 将 src\ 中的以上 .v 文件中所有 module 综合在一起,并进行仿真,结果存放在 wave.out 内。随后 vvp 将仿真信息可视化为波形图。
powershell 内运行以下代码:
.\scripts\simul.ps1
输出:
VCD info: dumpfile .\build\wave.vcd opened for output.
提示 vcd 波形图文件生成成功。
这时运行:
gtkwave .\build\wave.vcd
即可查看波形图。以上步骤需要确认 iverilog 已经安装以及配置完毕。配置示例在 3.3.1。其中 vvp 和 gtkwave 都是配套下载好的,无需另外安装。powershell 输入以下代码以检测安装完毕:
iverilog -v
iverilog -help
vvp -help
gtkwave -help
我的做法是 VScode 里下载 WaveTrace 插件,双击 .vcd 文件就可以在 VSC 中直接看,会美观很多。但是只能同时看 8 个元件,完整版要买。
3.3 vivado tcl
3.3.1 安装 vivado 以及配置
实际上我仅使用 VScode + Iverilog 也做了两个 lab,因为可以做到仿真,最后的综合实现依赖 ISE 也不是不能做,但是要抢着用实验室的清朝老电脑,于是还是寻求了一个替代。
首先通过简单的搜索发现下载 vivado 需要注册 amd 的账号,去英文官网注册即可。
这一步有若干问题:
- recaptcha 连不上:别连校园网 WIFI,且使用英文官网即可。
- 注册邮箱有问题:我自己使用的是 163 没问题,可以多个邮箱都试试。
其余的都跟着填,个人信息好像也不用填准确的。他会给邮箱发一个令牌,从邮件那里跳转就可以注册啦。
接下来就可以用中文官网。
登录后选择界面左上角的 产品 > 软件、工具和应用 > 自适应 Soc 和 FPGA > Vivado。
点进去选择 download,进去选 Vivado(硬件开发者),下拉到 2024.2 的 windows,下载即可。
或者直接点这个。
运行下好的 exe,按提示来操作,选择都按默认,需填写 amd 账号密码。
发现应用占 23G 空间,安装时需要预留 80 G(说好的轻量化呢 qwq)。不过貌似可以选一些不安装,具体的上网搜一下。
安装好之后找到 bin,配置好环境变量。我按默认地址安装的,地址在 "C:\Xilinx\Vivado\2024.2\bin"。
设置里搜索环境变量,点“编辑系统环境变量”,点环境变量。下方系统变量点新建,变量名叫 vivado,值为 C:\Xilinx\Vivado\2024.2\bin。系统变量中选中 Path 这项点编辑,跳出新窗口点新建,输入 C:\Xilinx\Vivado\2024.2\bin。当然路径因人而异,我这个是默认安装的路径,建议按上面的方法确认一下 bin 在哪里。确认输入完后一路点确定。
重启 VScode,在其中运行终端(应该是 PowerShell),输入以下代码确认配置成功:
vivado -version
输出应该有版本号等等。我的输出:
vivado v2024.2 (64-bit)
Tool Version Limit: 2024.11
SW Build 5239630 on Fri Nov 08 22:35:27 MST 2024
IP Build 5239520 on Sun Nov 10 16:12:51 MST 2024
SharedData Build 5239561 on Fri Nov 08 14:39:27 MST 2024
Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
Copyright 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
这样就算配置好了。
3.3.2 综合与实现
问 AI 要代码,中间的过程太过拉扯,就不看了。简单来说就是 vivado 有一个 tcl 控制台可以不开图形界面来做 vivado 的各种操作。
直接解析代码:(跟后面是一样的,已经建好文件夹就不用管了)
# build.tcl
# 1. create project
create_project -help
create_project -force -name fpga_project -dir vivado_project -part xc7k160t
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]
# 2. add files
add_files [list \
src/clkdiv.v \
src/createnumber.v \
src/display.v \
src/MUX41.v \
src/MyMC14495.v \
src/top.v \
]
# 3. constraints
add_files -fileset constrs_1 constraints/fpga.xdc
# get_files -filter {FILE_TYPE == "XDC"}
# 4. syn & imp
launch_runs synth_1 -jobs 4
wait_on_run synth_1
launch_runs impl_1 -jobs 4
wait_on_run impl_1
open_run impl_1
puts "\nChecking Port Constraints:"
foreach port [get_ports *] {
set loc [get_property PACKAGE_PIN $port]
set iostd [get_property IOSTANDARD $port]
if {$loc == ""} {
puts "ERROR: Port $port has no LOC constraint!"
} else {
puts "OK: Port $port -> LOC: $loc | IOSTANDARD: $iostd"
}
}
# 5. create .bit
launch_runs impl_1 -to_step write_bitstream -jobs 4
wait_on_run impl_1
# 6. close project
close_project
exit
保存以上代码在 .\scripts 里后,打开 powershell 脚本文件 build.ps1 并学习以下代码:
vivado -mode batch -source scripts/build.tcl
其意思是 vivado 这个软件以 batch 模式运行,tcl 控制台运行 build.tcl 内的全部代码。
powershell 里运行如下指令:
.\scripts\build.ps1
等待代码的运行,最后应该成功执行所有指令并正常 exit,则生成 bit 文件成功。
解析:
create_project -force -name fpga_project -dir vivado_project -part xc7k160t
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]
-part xc7k160t 是实验板子的型号,一定要写!!!型号具体因人而异,建议看自己的课件。同一个学校应该差不多
下面两行是说引脚的约束绑定可以放宽松一些。
foreach 那里是检查引脚有没有一一对应,如果 #5 run 出了 error,可以注释掉 #5 部分再跑 tcl 代码,来查看引脚的绑定情况。
后面基本看名字都懂,不懂问问 AI 吧 qwq
成功后当前项目文件夹里找到 vivado_project\fpga_project.runs\impl_1\top.bit,说明实现成功。
3.3.3 烧录
# program.tcl
open_hw_manager
connect_hw_server
# find
set hw_targets [get_hw_targets]
if {[llength $hw_targets] == 0} {
puts "ERROR: No JTAG cables detected!"
exit
}
# check the first
set hw_target [lindex $hw_targets 0]
current_hw_target $hw_target
open_hw_target
# get device
set hw_devices [get_hw_devices]
if {[llength $hw_devices] == 0} {
puts "ERROR: No FPGA devices found on the JTAG chain!"
exit
}
set hw_device [lindex $hw_devices 0] ;
# copy .bit path
set bitstream_file "vivado_project/fpga_project.runs/impl_1/top.bit"
if {![file exists $bitstream_file]} {
puts "ERROR: Bitstream file not found: $bitstream_file"
exit
}
# program
puts "Programming device: $hw_device"
set_property PROGRAM.FILE $bitstream_file $hw_device
program_hw_devices $hw_device
close_hw_target
disconnect_hw_server
close_hw
exit
也是让 AI 写就行。报错就给信息让它改。
set bitstream_file "vivado_project/fpga_project.runs/impl_1/top.bit"
其中的路径是上面提到的 bit 文件的相对路径。
保存以上代码在 .\scripts 里后,打开 powershell 脚本文件 program.ps1 并学习以下代码:
vivado -mode batch -source scripts/program.tcl
powershell 里运行如下指令:
.\scripts\program.ps1
最后应该正常 exit,实验板上实现了通过按钮计分的功能,提示烧录 bit 文件成功。
我在实验室已经验证过本流程完全可行。如果有偏差的问问 AI 吧qaq
3.3.4 彩蛋
拉扯的过程如下:
M:vivado可以不依赖图形编辑界面而直接用代码控制数据流生成和烧录,请你举例说明
D:给代码
M:命令行如何检查vivado_lab是否安装好
D:vivado -version
M:我已经添加了环境变量但仍然显示找不到命令
D:检查环境变量路径是否正确、确认环境变量已生效、...
M:找到问题了,bash命令应该是vivado_lab -version
D:服务器繁忙,请稍后再试。
M:我有一个项目由 a.v b.v c.v 以及 top.v 组成,请你示例如何用 vivado 命令配合 tcl 实现 bit 流的生成以及烧录。
D:给代码
M:我用的是 ucf 文件绑定引脚,请你更改相应部分
D:改代码
M:我已经在 VScode 上建好文件结构了,还需要以 tcl 脚本建立吗?如果确实需要,它建立的文件目录在哪里?
D:分步解答
M:在 build.tcl 中是怎么确定我要下板验证的是哪个模块?
D:通过代码结构隐式指定 / tcl 中显式指定顶层模块
M:这个 tcl 控制台又是什么?在哪里打开,可以直接运行 tcl 代码吗?
D:Vivado 的 Tcl 控制台 是一个内置的交互式命令行工具,...
M:直接在系统内运行 PowerShell,输入 vivado_lab -version 可以正常输出版本信息,但在 VScode 的 PS 中无法识别vivado_lab 指令,是何问题?
D:逐步排查解决
M:(报错信息)运行 build.tcl 报错如上,请你看看怎么回事
D:你遇到的错误是因为命令的参数顺序不正确,应该...
M:ERROR: [Common 17-69] Command failed: File management TCL Commands are not supported
D:Vivado Lab Edition 的限制:...,下载并安装 Vivado Design Suite(非 Lab 版)。
M:绷不住了,就是为了省点空间才下的 Lab 版,还不能综合awa
M:不支持 ucf 了,把这个 ucf 文件转为 xdc 格式
D:OK,拿去运行
M:Unconstrained Logical Port 又是啥问题
D:部分顶层模块的 I/O 端口未在约束文件(XDC)中指定物理引脚位置(LOC)。
M:get_files 没有-fileset 参数啊,你再看看
D:替代方法:获取约束文件列表
M:invalid command name "report_port_status" 什么问题
D:未在正确的上下文中运行命令。应该...
M:你确定有这条指令吗,2024版按照以上运行仍然invalid
D:不行换一个。遍历所有端口并打印 LOC 和 IOSTANDARD(给代码)
M:(part 参数一直不对)SWORD 4.0 的对应 -part 参数是什么
D:(我不到啊)(开始一本正经地胡言乱语)
M:哦原来课件里面有,终于改对了
M:请把烧录指令给我看看
D:敲代码ing...关键说明:比特流文件路径:...
M:执行 build.tcl 后都成功了,bit 文件在哪里
D:服务器繁忙,请稍后再试。
M:?woc眼睛不要了
M:烧录又失败了,怎么回事呢?
D:(一通分析后)不如重写一份 tcl,拿去重新试试
M:。。。
以上。早知道就用 Vivado 图形化界面了...
不过:

4 源码
simul.ps1:
iverilog -o .\build\wave.out .\src\MUX41.v .\src\MyMC14495.v .\src\clkdiv.v .\src\top.v .\src\display.v .\src\createnumber.v .\src\testbench_top.v
vvp -n .\build\wave.out
clkdiv.v:
module clkdiv (
input wire clk, rst,
output reg [31 : 0] clkdiv
);
initial begin
clkdiv <= 0;
end
always @(posedge clk or posedge rst) begin
if(rst) clkdiv <= 0;
else clkdiv <= clkdiv + 1'b1;
end
endmodule
createnumber.v:
module pbdebounce (
input wire clk_1ms,
input wire I,
output reg O
);
reg [7 : 0] pbshift;
initial begin
O = 0;
end
always @(posedge clk_1ms) begin
pbshift = pbshift << 1;
pbshift[0] = I;
if(pbshift == 8'h00) O = 0;
if(pbshift == 8'hFF) O = 1;
end
endmodule
module create_number (
input wire clk,
input wire [3 : 0] btn,
output reg [3 : 0] n0, n1, n2, n3
);
wire [3 : 0] t0, t1, t2, t3;
assign t0 = n0 + 1'b1;
assign t1 = n1 + 1'b1;
assign t2 = n2 + 1'b1;
assign t3 = n3 + 1'b1;
wire [3 : 0] tbtn;
initial begin
{n3, n2, n1, n0} <= 16'b0001_0010_0011_0100;
end
pbdebounce db0(.clk_1ms(clk), .I(btn[0]), .O(tbtn[0]));
pbdebounce db1(.clk_1ms(clk), .I(btn[1]), .O(tbtn[1]));
pbdebounce db2(.clk_1ms(clk), .I(btn[2]), .O(tbtn[2]));
pbdebounce db3(.clk_1ms(clk), .I(btn[3]), .O(tbtn[3]));
always @(posedge tbtn[0]) n0 <= t0;
always @(posedge tbtn[1]) n1 <= t1;
always @(posedge tbtn[2]) n2 <= t2;
always @(posedge tbtn[3]) n3 <= t3;
endmodule
display.v:
module display_sync (
input wire [3 : 0] I0, I1, I2, I3, points, LES,
input wire [1 : 0] scan,
output wire [3 : 0] Hex, AN,
output wire p, LE
);
Mux_4_1_b4 Muxb4(.I0(I0), .I1(I1), .I2(I2), .I3(I3), .s(scan), .o(Hex));
wire [3 : 0] M;
decoder_2_4 d24_1(.s(scan), .outp(M));
assign p = (M[0] & points[0]) | (M[1] & points[1]) | (M[2] & points[2]) | (M[3] & points[3]);
assign LE = (M[0] & LES[0]) | (M[1] & LES[1]) | (M[2] & LES[2]) | (M[3] & LES[3]);
assign AN = ~M;
endmodule
MUX41.v:
module decoder_2_4 (
input wire [1 : 0] s,
output wire [3 : 0] outp
);
assign outp[0] = ~s[0] & ~s[1];
assign outp[1] = s[0] & ~s[1];
assign outp[2] = ~s[0] & s[1];
assign outp[3] = s[0] & s[1];
endmodule
module Mux_4_1_b4 (
input wire [1 : 0] s,
input wire [3 : 0] I0, I1, I2, I3,
output wire [3 : 0] o
);
wire [3 : 0] Muxer;
decoder_2_4 Decoder(.s(s), .outp(Muxer));
assign o[0] = (Muxer[0] & I0[0]) | (Muxer[1] & I1[0]) | (Muxer[2] & I2[0]) | (Muxer[3] & I3[0]);
assign o[1] = (Muxer[0] & I0[1]) | (Muxer[1] & I1[1]) | (Muxer[2] & I2[1]) | (Muxer[3] & I3[1]);
assign o[2] = (Muxer[0] & I0[2]) | (Muxer[1] & I1[2]) | (Muxer[2] & I2[2]) | (Muxer[3] & I3[2]);
assign o[3] = (Muxer[0] & I0[3]) | (Muxer[1] & I1[3]) | (Muxer[2] & I2[3]) | (Muxer[3] & I3[3]);
endmodule
MyMC14495.v:
module MyMC14495 (
input wire D0, D1, D2, D3,
input wire LE, point,
output wire a, b, c, d, e, f, g, p
);
assign D0n = ~D0;
assign D1n = ~D1;
assign D2n = ~D2;
assign D3n = ~D3;
assign a = LE | ((D3n & D2n & D1n & D0) | (D3n & D2 & D1n & D0n) | (D3 & D2n & D1 & D0) | (D3 & D2 & D1n & D0));
assign b = LE | ((D3n & D2 & D1n & D0) | (D2 & D1 & D0n) | (D3 & D2 & D0n) | (D3 & D1 & D0));
assign c = LE | ((D3n & D2n & D1 & D0n) | (D3 & D2 & D0n) | (D3 & D2 & D1));
assign d = LE | ((D3n & D2n & D1n & D0) | (D3n & D2 & D1n & D0n) | (D2 & D1 & D0) | (D3 & D2n & D1 & D0n));
assign e = LE | ((D3n & D0) | (D3n & D2 & D1n) | (D2n & D1n & D0));
assign f = LE | ((D3n & D2n & D0) | (D3n & D2n & D1) | (D3n & D1 & D0) | (D3 & D2 & D1n & D0));
assign g = LE | ((D3n & D2n & D1n) | (D3n & D2 & D1 & D0) | (D3 & D2 & D1n & D0n));
assign p = ~point;
endmodule
testbench_MUX41.v:
`timescale 1ns/1ns
module tb_MUX;
reg [3 : 0] I0, I1, I2, I3;
reg [1 : 0] s;
wire [3 : 0] o;
reg clk;
initial begin
I0 = 0;
I1 = 0;
I2 = 0;
I3 = 0;
s = 0;
clk = 0;
end
always begin
#50 clk = ~clk;
end
always @(posedge clk) begin
#1 I0 = {$random};
#3 I1 = {$random};
#3 I2 = {$random};
#3 I3 = {$random};
#2 s = {$random};
end
Mux_4_1_b4 Muxer(.s(s), .I0(I0), .I1(I1), .I2(I2), .I3(I3), .o(o));
initial begin
$dumpfile(".\\build\\wave.vcd");
$dumpvars(0, tb_MUX);
#10000 $finish;
end
endmodule
testbench_top.v:
`timescale 1ns/1ns
module uut;
reg [3 : 0] btn;
reg [7 : 0] SW;
reg clk;
wire [3 : 0] AN;
wire [7 : 0] SEGMENT;
wire BTNX4;
initial begin
btn = 0;
SW = 8'hFF;
clk = 0;
end
top uut0(.btn(btn), .clk(clk), .SW(SW), .AN(AN), .SEGMENT(SEGMENT), .BTNX4(BTNX4));
always begin
#5 clk = ~clk;
end
initial begin
#5000 btn = 4'b0001;
#10000 btn = 4'b0000;
#5000 btn = 4'b0001;
#10000 btn = 4'b0000;
#5000 btn = 4'b0010;
#10000 btn = 4'b0000;
end
initial begin
$dumpfile(".\\build\\wave.vcd");
$dumpvars(0, uut);
#1000000 $finish;
end
endmodule
top.v:
module top (
input wire [3 : 0] btn,
input wire clk,
input wire [7 : 0] SW,
output wire [3 : 0] AN,
output wire [7 : 0] SEGMENT,
output wire BTNX4,
output wire Ring
);
reg GND;
wire RST;
initial GND <= 0;
assign BTNX4 = GND;
assign RST = GND;
assign Ring = GND;
wire [3 : 0] I0, I1, I2, I3, Hex;
wire [31 : 0] clkd;
wire P, LE;
clkdiv cd(.clk(clk), .rst(RST), .clkdiv(clkd));
create_number numc(.clk(clkd[17]), .btn(btn), .n0(I0), .n1(I1), .n2(I2), .n3(I3));
display_sync ds(.I0(I0), .I1(I1), .I2(I2), .I3(I3), .Hex(Hex), .AN(AN), .scan(clkd[18 : 17]), .points(SW[3 : 0]), .LES(SW[7 : 4]), .p(P), .LE(LE));
MyMC14495 MyMc(.D0(Hex[0]), .D1(Hex[1]), .D2(Hex[2]), .D3(Hex[3]), .point(P), .LE(LE),
.a(SEGMENT[0]), .b(SEGMENT[1]), .c(SEGMENT[2]), .d(SEGMENT[3]), .e(SEGMENT[4]), .f(SEGMENT[5]), .g(SEGMENT[6]), .p(SEGMENT[7]));
endmodule
fpga.xdc:
# clocks
set_property PACKAGE_PIN AC18 [get_ports clk]
set_property IOSTANDARD LVCMOS18 [get_ports clk]
create_clock -period 10.000 -name clk [get_ports clk]
# SW[7:0]
set_property PACKAGE_PIN AA10 [get_ports {SW[0]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[0]}]
set_property PACKAGE_PIN AB10 [get_ports {SW[1]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[1]}]
set_property PACKAGE_PIN AA13 [get_ports {SW[2]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[2]}]
set_property PACKAGE_PIN AA12 [get_ports {SW[3]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[3]}]
set_property PACKAGE_PIN Y13 [get_ports {SW[4]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[4]}]
set_property PACKAGE_PIN Y12 [get_ports {SW[5]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[5]}]
set_property PACKAGE_PIN AD11 [get_ports {SW[6]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[6]}]
set_property PACKAGE_PIN AD10 [get_ports {SW[7]}]
set_property IOSTANDARD LVCMOS15 [get_ports {SW[7]}]
# SEGMENT[7:0]
set_property PACKAGE_PIN AB22 [get_ports {SEGMENT[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[0]}]
set_property PACKAGE_PIN AD24 [get_ports {SEGMENT[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[1]}]
set_property PACKAGE_PIN AD23 [get_ports {SEGMENT[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[2]}]
set_property PACKAGE_PIN Y21 [get_ports {SEGMENT[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[3]}]
set_property PACKAGE_PIN W20 [get_ports {SEGMENT[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[4]}]
set_property PACKAGE_PIN AC24 [get_ports {SEGMENT[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[5]}]
set_property PACKAGE_PIN AC23 [get_ports {SEGMENT[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[6]}]
set_property PACKAGE_PIN AA22 [get_ports {SEGMENT[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SEGMENT[7]}]
# AN[3:0]
set_property PACKAGE_PIN AC22 [get_ports {AN[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {AN[3]}]
set_property PACKAGE_PIN AB21 [get_ports {AN[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {AN[2]}]
set_property PACKAGE_PIN AC21 [get_ports {AN[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {AN[1]}]
set_property PACKAGE_PIN AD21 [get_ports {AN[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {AN[0]}]
# btn[3:0] and BTNX4
set_property PACKAGE_PIN V18 [get_ports {btn[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {btn[3]}]
set_property PACKAGE_PIN V19 [get_ports {btn[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {btn[2]}]
set_property PACKAGE_PIN V14 [get_ports {btn[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {btn[1]}]
set_property PACKAGE_PIN W14 [get_ports {btn[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {btn[0]}]
set_property PACKAGE_PIN W16 [get_ports BTNX4]
set_property IOSTANDARD LVCMOS18 [get_ports BTNX4]
set_property PACKAGE_PIN AF24 [get_ports Ring]
set_property IOSTANDARD LVCMOS33 [get_ports Ring]
build.ps1:
vivado -mode batch -source scripts/build.tcl
build.tcl:
# build.tcl
# 1. create project
create_project -help
create_project -force -name fpga_project -dir vivado_project -part xc7k160t
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]
# 2. add files
add_files [list \
src/clkdiv.v \
src/createnumber.v \
src/display.v \
src/MUX41.v \
src/MyMC14495.v \
src/top.v \
]
# 3. constraints
add_files -fileset constrs_1 constraints/fpga.xdc
# get_files -filter {FILE_TYPE == "XDC"}
# 4. syn & imp
launch_runs synth_1 -jobs 4
wait_on_run synth_1
launch_runs impl_1 -jobs 4
wait_on_run impl_1
open_run impl_1
puts "\nChecking Port Constraints:"
foreach port [get_ports *] {
set loc [get_property PACKAGE_PIN $port]
set iostd [get_property IOSTANDARD $port]
if {$loc == ""} {
puts "ERROR: Port $port has no LOC constraint!"
} else {
puts "OK: Port $port -> LOC: $loc | IOSTANDARD: $iostd"
}
}
# 5. create .bit
launch_runs impl_1 -to_step write_bitstream -jobs 4
wait_on_run impl_1
# 6. close project
close_project
exit
program.ps1:
vivado -mode batch -source scripts/program.tcl
program.tcl:
# program.tcl
open_hw_manager
connect_hw_server
# find
set hw_targets [get_hw_targets]
if {[llength $hw_targets] == 0} {
puts "ERROR: No JTAG cables detected!"
exit
}
# check the first
set hw_target [lindex $hw_targets 0]
current_hw_target $hw_target
open_hw_target
# get device
set hw_devices [get_hw_devices]
if {[llength $hw_devices] == 0} {
puts "ERROR: No FPGA devices found on the JTAG chain!"
exit
}
set hw_device [lindex $hw_devices 0] ;
# copy .bit path
set bitstream_file "vivado_project/fpga_project.runs/impl_1/top.bit"
if {![file exists $bitstream_file]} {
puts "ERROR: Bitstream file not found: $bitstream_file"
exit
}
# program
puts "Programming device: $hw_device"
set_property PROGRAM.FILE $bitstream_file $hw_device
program_hw_devices $hw_device
close_hw_target
disconnect_hw_server
close_hw
exit
以上。
5 附录
参考文献:
https://zhuanlan.zhihu.com/p/95081329
https://zhuanlan.zhihu.com/p/338497672
https://www.bilibili.com/opus/487517356911938825/?from=readlist
相关网站 / 下载链接:
真正的彩蛋:
你怎么穿着 VScode 的衣服
真真正正的彩蛋:
好吧用 AI 的心得也没有那么高妙,其实就是不要妄想用 AI 就能偷懒就行。也别见到错了就怀疑自己而盲从 AI,也别一直“俺寻思之力”自己乱搞,尽量多找几个细节问一问。越认真做的就会越快,这时用 AI 就有显著的优势了。
就酱,byebye啦~ 祝大家身体健康,学习进步哇

浙公网安备 33010602011771号