Vivado的使用
以实验书中给出的加法器文件为例
1. Design Source
中添加 adder.v
文件
-
打开 Vivado,创建一个新项目。
-
在项目中,右键点击
Design Sources
,选择Add Sources
,然后选择Add or create design sources
。 -
点击
Create File
,输入文件名adder.v
,点击OK
。 -
在
adder.v
文件中编写代码
添加好文件以后,文件会产生向导,输入输出向导。但是这部分代码最终的目的是在代码段中生成程序的输入输出端口,理论上来说代码处编写即可,在文件中添加下面的内容
module adder( input [31:0] operand1, //定义端口32位的输入 input [31:0] operand2, input cin, //来自低位的进位 output [31:0] result, output cout //向高位的进位 ); assign {cout,result} = operand1 + operand2 + cin; //输出形式 endmodule
2. 综合(Synthesis)
综合是将高层次的设计描述(如 Verilog 或 VHDL 代码)转换为低层次的逻辑门级网表(Gate-level Netlist)的过程。主要任务:
-
逻辑优化:将代码转换为逻辑单元
-
语法和逻辑的检查
-
生成网表:生成中间文件(EDIF或NGC格式)
3. 实现(Implementation)
实现是将综合生成的逻辑网表映射到具体的 FPGA 硬件资源上,并生成最终的比特流文件(Bitstream)的过程。主要任务是:
-
布局布线:将逻辑网表中的逻辑单元映射到 FPGA 的物理资源上(如 CLB、DSP、BRAM 等),并完成信号的路由。
-
时序优化:确保设计的布局仍能满足时序要求
-
生成比特流:生成可以下载到FPGA的配置文件
4. 检验逻辑是否正确的方式:
(1)仿真 创建虚拟信号(Simulation Sources)
-
右键点击
Simulation Sources
,选择Add Sources
,然后选择Add or create simulation sources
。 -
点击
Create File
,输入文件名testbench.v
,点击OK
。 -
在
testbench.v
文件中编写代码
添加仿真文件,默认文件名为testbench.v
.仿真文件也是Verilog文件,仿真文件自己内部构造输入,不需要对外添加。刚刚创建好以后,adder.v
是顶部文件,在testbench.v
文件中添加下面的内容:
`timescale 1ns / 1ps //仿真单位时间为1ns,精度为1ps 董老师给出的代码中没有这一行 module testbench; // Inputs 这里的reg定义的变量以及wire输出的变量是为了后续的 adder 模块的输入输出 reg [31:0] operand1; reg [31:0] operand2; reg cin; // Outputs wire [31:0] result; wire cout; // Instantiate the Unit Under Test (UUT) 给adder起了个别名 uut //这里的顺序要和adder中的一样 作用是实例化adder。 //语法 .port_name1(external_signal1) 。实例化的时候,如果实例化了多个对象,就要起别名。 //也可以位置端口连接,但是连接顺序必须与模块定义中的端口顺序完全一致 adder uut ( //模块定义的端口名称(外部信号(可以是reg、wire等信号)) operand1是之前adder文件中的,而括号内的是这个文件中的 .operand1(operand1), .operand2(operand2), .cin(cin), .result(result), .cout(cout) ); initial begin //寄存器中的一定要有值,因此要先初始化 // Initialize Inputs operand1 = 0; operand2 = 0; cin = 0; // Wait 100 ns for global reset to finish #100; // Add stimulus here end always #10 operand1 = $random; //$random为系统任务,产生一个随机的32位数 always #10 operand2 = $random; //#10 表示等待10个单位时间(10ns),即每过10ns,赋值一个随机的32位数 always #10 cin = {$random} % 2; //加了拼接符,{$random}产生一个非负数,除2取余得到0或1 endmodule
仿真文件编写完毕以后,Simulation Souces
变成了顶层模块,走仿真的时候一定要是顶层模块。
注意:每次写完一个文件都跑一遍综合和实现。运行完以后,点击Simulation
中的 Run Simulation
进行仿真,出现波形图。进行缩放,拖动滚轮,右键 Radix
选择展示的进制
(2)试验箱
根据曾经的描述,可以画出定点实验加法 顶层模块图
观察 lcd_module.v
文件
顶层模块文件
-
右键点击
Design Sources
,选择Add Sources
,然后选择Add or create design sources
。 -
点击
Create File
,输入文件名adder_display.v
,点击OK
。 -
在
adder_display.v
文件中编写代码
在 Design Source
中添加顶层模块文件。顶层模块代码如下,adder_display.v
代码,需要注意的是输入输出定义好,以及始终和 reset
信号。
module adder_display( //时钟与复位信号, input clk, input resetn, //后缀"n"表示低电平有效 //拨码开关,用于选择输入数和产生cin input input_sel, //0:输入为加数1(add_operand1);1:为加数2(add_operand2) input sw_cin, //led灯,用于显示cout output led_cout, //触摸屏相关接口,不需要更改 output lcd_rst, output lcd_cs, output lcd_rs, output lcd_wr, output lcd_rd, inout[15:0] lcd_data_io, output lcd_bl_ctr, inout ct_int, inout ct_sda, output ct_scl, output ct_rstn ); //上面的都是adder_display的对外端口,先买你的是内部的原理,这里是把加法器接好了 //-----{调用加法模块}begin reg [31:0] adder_operand1; reg [31:0] adder_operand2; wire adder_cin; wire [31:0] adder_result ; wire adder_cout; adder adder_module( .operand1(adder_operand1), .operand2(adder_operand2), .cin (adder_cin ), .result (adder_result ), .cout (adder_cout ) ); //输入的端口接到加法器的输入的端口上,输出接到输出的端口上,assign是接线 assign adder_cin = sw_cin; assign led_cout = adder_cout; //-----{调用加法模块}end //---------------------{调用触摸屏模块}begin--------------------// //-----{实例化触摸屏}begin //此小节不需要更改 reg display_valid; reg [39:0] display_name;//五个字符,带上了五个ASCII码,一个8位,一共40 reg [31:0] display_value;//数字都是32位的 wire [5 :0] display_number;//刷新0~44,则一共需要5个 wire input_valid; wire [31:0] input_value; //实例化LCD屏 lcd_module lcd_module( .clk (clk ), //10Mhz .resetn (resetn ), //调用触摸屏的接口 .display_valid (display_valid ), .display_name (display_name ), .display_value (display_value ), .display_number (display_number), .input_valid (input_valid ), .input_value (input_value ), //lcd触摸屏相关接口,不需要更改 .lcd_rst (lcd_rst ), .lcd_cs (lcd_cs ), .lcd_rs (lcd_rs ), .lcd_wr (lcd_wr ), .lcd_rd (lcd_rd ), .lcd_data_io (lcd_data_io ), .lcd_bl_ctr (lcd_bl_ctr ), .ct_int (ct_int ), .ct_sda (ct_sda ), .ct_scl (ct_scl ), .ct_rstn (ct_rstn ) ); //-----{实例化触摸屏}end //LCD屏和加法器连线 //-----{从触摸屏获取输入}begin //根据实际需要输入的数修改此小节, //建议对每一个数的输入,编写单独一个always块 //当input_sel为0时,表示输入数为加数1,即operand1 always @(posedge clk) //时钟触发 begin if (!resetn) //当前要不要清零 begin adder_operand1 <= 32'd0; end else if (input_valid && !input_sel) //检查当前的输入是否点了OK,是不是要输入第一个数 begin adder_operand1 <= input_value; //如果是,则传入到operand1中 end end //当input_sel为1时,表示输入数为加数2,即operand2 always @(posedge clk) begin if (!resetn) begin adder_operand2 <= 32'd0; end else if (input_valid && input_sel) begin adder_operand2 <= input_value; end end //-----{从触摸屏获取输入}end //输出到LCD屏上 //-----{输出到触摸屏显示}begin //根据需要显示的数修改此小节, //触摸屏上共有44块显示区域,可显示44组32位数据 //44块显示区域从1开始编号,编号为1~44, always @(posedge clk) begin case(display_number) //所有的44个位置,但是这次只用3个 6'd1 : //6表示位宽,d为十进制,2为常量2 begin display_valid <= 1'b1; display_name <= "ADD_1"; //五个字符 display_value <= adder_operand1; //第一个数 end 6'd2 : begin display_valid <= 1'b1; display_name <= "ADD_2"; display_value <= adder_operand2; end 6'd3 : begin display_valid <= 1'b1; display_name <= "RESUL"; display_value <= adder_result; end default : begin display_valid <= 1'b0; //1位宽的常量二进制数0 display_name <= 40'd0; //40位宽 display_value <= 32'd0; //32位宽 end endcase end //-----{输出到触摸屏显示}end //----------------------{调用触摸屏模块}end---------------------// endmodule
使用源代码的时候一定要用写字板打开,记事本会乱码,直接导入的时候会对别的项目直接进行更改。添加完文件并且保存以后,会发现顶层模块变成了 adder_display
,
LCD模块
此时缺少 lcd_module
模块,需要我们直接导入出来,因为此时这个模块是打包好的,因此要手动导入,添加模块,点击 add design source
结尾文件为.dcp
excel 中为接口对应的控制信号编号。
导入 lcd_module
模块后,进行综合和实现,实现结束以后,点击 Implemented Design
,可以看到设备的预览图,右上角的 Default Layout
布局改为 IO Planing
会更加的直观。可以看到每一个信号的横纵坐标,即为接口编号,接下来要做的就是让顶层模块的端口接入到试验箱上。去写约束文件
约束文件
-
右键点击
Constraints
,选择Add Sources
,然后选择Add or create constraints
。 -
点击
Create File
,输入文件名adder.xdc
,点击OK
。 -
在
adder.xdc
文件中编写以下代码,实现的时候,请将双斜杠注释删去
//对每个信号绑定实验向上的位置 set_property PACKAGE_PIN AC19 [get_ports clk] //将时钟信号,绑定到AC19信号当中 set_property PACKAGE_PIN H7 [get_ports led_cout] set_property PACKAGE_PIN Y3 [get_ports resetn] set_property PACKAGE_PIN AC21 [get_ports input_sel] set_property PACKAGE_PIN AD24 [get_ports sw_cin] //给每个信号定义标准电压为3.3伏 set_property IOSTANDARD LVCMOS33 [get_ports clk] set_property IOSTANDARD LVCMOS33 [get_ports led_cout] set_property IOSTANDARD LVCMOS33 [get_ports resetn] set_property IOSTANDARD LVCMOS33 [get_ports input_sel] set_property IOSTANDARD LVCMOS33 [get_ports sw_cin] //其他的内容直接复制过来 #lcd set_property PACKAGE_PIN J25 [get_ports lcd_rst] set_property PACKAGE_PIN H18 [get_ports lcd_cs] set_property PACKAGE_PIN K16 [get_ports lcd_rs] set_property PACKAGE_PIN L8 [get_ports lcd_wr] set_property PACKAGE_PIN K8 [get_ports lcd_rd] set_property PACKAGE_PIN J15 [get_ports lcd_bl_ctr] set_property PACKAGE_PIN H9 [get_ports {lcd_data_io[0]}] set_property PACKAGE_PIN K17 [get_ports {lcd_data_io[1]}] set_property PACKAGE_PIN J20 [get_ports {lcd_data_io[2]}] set_property PACKAGE_PIN M17 [get_ports {lcd_data_io[3]}] set_property PACKAGE_PIN L17 [get_ports {lcd_data_io[4]}] set_property PACKAGE_PIN L18 [get_ports {lcd_data_io[5]}] set_property PACKAGE_PIN L15 [get_ports {lcd_data_io[6]}] set_property PACKAGE_PIN M15 [get_ports {lcd_data_io[7]}] set_property PACKAGE_PIN M16 [get_ports {lcd_data_io[8]}] set_property PACKAGE_PIN L14 [get_ports {lcd_data_io[9]}] set_property PACKAGE_PIN M14 [get_ports {lcd_data_io[10]}] set_property PACKAGE_PIN F22 [get_ports {lcd_data_io[11]}] set_property PACKAGE_PIN G22 [get_ports {lcd_data_io[12]}] set_property PACKAGE_PIN G21 [get_ports {lcd_data_io[13]}] set_property PACKAGE_PIN H24 [get_ports {lcd_data_io[14]}] set_property PACKAGE_PIN J16 [get_ports {lcd_data_io[15]}] set_property PACKAGE_PIN L19 [get_ports ct_int] set_property PACKAGE_PIN J24 [get_ports ct_sda] set_property PACKAGE_PIN H21 [get_ports ct_scl] set_property PACKAGE_PIN G24 [get_ports ct_rstn] set_property IOSTANDARD LVCMOS33 [get_ports lcd_rst] set_property IOSTANDARD LVCMOS33 [get_ports lcd_cs] set_property IOSTANDARD LVCMOS33 [get_ports lcd_rs] set_property IOSTANDARD LVCMOS33 [get_ports lcd_wr] set_property IOSTANDARD LVCMOS33 [get_ports lcd_rd] set_property IOSTANDARD LVCMOS33 [get_ports lcd_bl_ctr] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[8]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[9]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[10]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[11]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[12]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[13]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[14]}] set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[15]}] set_property IOSTANDARD LVCMOS33 [get_ports ct_int] set_property IOSTANDARD LVCMOS33 [get_ports ct_sda] set_property IOSTANDARD LVCMOS33 [get_ports ct_scl] set_property IOSTANDARD LVCMOS33 [get_ports ct_rstn]
约束文件,建立好后就可以进行上箱了
生成位流文件
控制栏拉到最下面,看到 Generate Bitstream
生成位流文件,此时需要重新跑综合和实现。
准备试验箱
一定要将箱子里的线通过小口拉出来再连到电脑上,防止线被夹断。旁边的红色功能为开关。
-
试验箱供上电
-
USB插口插在自己的电脑上
一切准备就绪以后,让试验箱找位流文件,generate stream
下面有一个,open Hardware manager(打开文件管理器)
随后右上角会出现绿色的条,点击 Open target
便会自动开始连接试验箱。找不到的话,一定要断开链接以后,再去链接。