Design Name:嵌入式环境搭建
Project Name:实现二分频电路
Tool Version:ISE 14.3 + Win7 64位 + 12G内存
里面包含了一些平常用到的实例,然后自己加的备注
1 首先是设计文件和激励文件的撰写
1.1 首先是设计文件
module top(clk,rst,clk_div2)//这里定义了一个名为top的模块
input clk,rst;//定义:clk、rst为输入
output clk_div2;//定义:clk_div2为输出
reg[15:0] count = 1'b0;//定义了一个大小为16位的计数器count
assign clk_div2 = count[0];//分配count[0]给clk_div2f
always @(posedge clk)//一旦clk信号的上升沿出现,则执行下面
begin //begin end 相当于花括号,把多条语句包含进来
if(!rst) //如果rst是0则执行"count <= 1'b0"
count <=1'b0;
else //否则的话,执行"count <=count + 1'b1"
count <=count + 1'b1;
endendmodule
module top(clk59m,rst,txd,rxd,send_over,dout);
endmodule
1.1.1 关于assign
语法:
assign <寄存器类型变量> = <赋值表达式>;
比如:
assign clk_div2=count[0]
表示把count[0]中的数赋值给clk_div2
1.1.2 关于always
always所包括的所有的行为语句共同构成了一个always语句块,这个语句块从仿真的0时刻开始执行其中的行为语句,当最后一条语句执行完毕之后,重新从第一条语句开始读取,像这样循环往复,直到整个仿真的结束。所以,always常常用于一组需要反复运行的活动,比如时间信号的发生,或者是每半个时钟周期时钟信号翻转一次这样的。
因此:
从c语言的角度看,always就像是for循环一样。
1.1.3 书上说的
always过程快是由always过程语句以及语句块组成的,语法格式如下
always @ <敏感信号表达式>
语句块
其中语句块的格式为:
<块定义语句1>
时间控制1 行为语句1;
...
时间控制n 行为语句n;
<块定义语句2>
其中,@ <敏感信号表达式>
可有可无,如果有敏感事件的话,就可以加上,表示这个always语句是由这个敏感事件所触发的。
<块定义语句1>和<块定义语句2>构成了一组块定义语句,它们可以是“begin-end”或者是“fork-join”
行为语句包括:
- 过程赋值语句
- 过程连续赋值语句
- if条件分支语句
- case条件分支语句
- 循环控制语句(forever、repeat、while、for循环控制语句)
- wait等待语句
- disable中断语句
- 事件触发语句
- 任务调用语句 下面对于上面这个程序进行大致说明
首先我们定义了3个参数,clk,rst,clk_div2,然后我们定义clk和rst为输入,clk_div2为输出,然后定义一个大小为16位的计数器,将这个计数器的最末位赋值给clk_div2,接着如果clk信号的上升沿出现了,就执行always中的语句,即如果rst为0的话,将0赋给count,如果rst为1的话,就让count+1,事实上,count的初始值为0,加了一次之后,变为1,再加一次之后变为10,此时因为clk_div2的值是count的第一位,所以此时clk_div2为0.
1.2 下面是第一个实例的激励文件
下面就是第一个实例的激励文件:
module top1;
// Inputs
reg clk;
reg rst;
// Outputs
wire clk_div2;
// Instantiate the Unit Under Test (UUT)
top uut (
.clk(clk),
.rst(rst),
.clk_div2(clk_div2)
);
initial
begin
// Initialize Inputs
clk = 0;
rst = 0;
// 从这里往下是自己写的
#30 rst = 1; //30个时间单位之后,rst为1
forever //然后一直保持
#20 clk = ~clk; //20个单位之后clk翻转
end
always #20 clk = ~clk;//这一句和前面的forever #20 clk=~clk;是实现的相同的功能endmodule
首先解释一下什么是激励文件
根据书上的定义:在完成工程的设计后,通常要对设计的正确性进行测试,这就需要对设计文件施加激励,通过检查其输出来验证功能的正确性。完成测试功能的模块称为激励文件
通常需要将激励文件与设计文件分开设计。激励文件一般称为测试台testbench。
讲一下里面的一些关键词的用法
1.2.1 initial
initial里面的语句是顺序运行的
1.2.2 always与initial的不同点
always和initial的不同点在于,initial语句只执行一次,而always语句则是不断地重复执行,直到仿真过程结束。
1.2.3 forever
forever与always这两者的功能其实是差不多的,比如说用这两个关键词生成时钟
首先是forever
initial
foreverbegin
#0 clk <= 0;
#5 clk <= 1;
#5 clk <= 0;
end
然后是always
initialbegin
clk = 0;
endalwaysbegin
#5 clk=~clk;
end
说明: forever 意思为保持,它所保持的是它下面的那一条语句,而不是说上面那条语句完了,然后一直保持。但是他与always还是有区别的,forever循环语句常用于产生周期性的波形,用来作为仿真测试信号。它与always语句不同之处在于不能独立写在程序中,而必须写在initial块中。
1.2.4 testbench的基本结构
module test_bench;
信号或变量定义说明;
使用initial或always语句来产生激励波形;
实例化设计模块;
监控和比较输出响应;
endmodule
常用的激励信号通常会包括:时钟信号和复位信号
1.2.5 普通时钟信号
普通时钟信号就是占空比为50%的时钟信号。
(1) 使用initial生成时钟信号
parameter period = 20;
reg clk;
initial //产生时钟信号,并且每隔10个时间单位就翻转一次begin
clk = 1'b0;
forever
#(period/2) clk=~clk;
end
(2) 使用always生成时钟信号
parameter period = 20;
reg clk;
initial clk=1'b0;
always #(peiod/2) clk=~clk;
一定要给时钟信号赋初值,因为信号的默认值为z
2 TOP文件和UCF文件的生成
按照培训大纲上所说:
连接FPGA 仿真器,打开ISE软件,进行连接测试,如果下载线正常识别FPGA 型号,表示硬件开发环境搭建成功。新建工程,然后选择FPGA型号、系列、编程语言、速度等选项,添加TOP文件和UCF文件,Verilog逻辑实现二分频电路,即CLK_OUT=CLK_IN/2,编译程序并生成BIT 文件,在线烧写BIT文件,使用示波 器测量时钟输出频率,并与晶振始终比对。
2.1 首先是TOP文件
TOP文件就是顶层文件,也就是之前的那个设计文件.v
2.2 然后是UCF文件
FPGA中的约束文件共有三种:
- 用户设计文件(UCF文件)
- 网表约束文件(NCF文件)
- 物理约束文件(PCF文件)
这三者的关系为:用户在设计输入阶段编写UCF文件,然后UCF文件和设计文件综合后生成NCF文件,最后再经过实现后生成PCF文件。UCF是用户输入的,而NCF是由综合工具自动生成的,当两者发生冲突时,以UCF为准。
约束文件的建立有两种,一种是通过新建方式,一种是利用过程管理器完成。
UCF中描述引脚分配的语法是
verilog NET "端口名称" LOC = pin num;//pin num是引脚编号
2.2.1 通过新建方式
在sources窗口,单击鼠标右键,选择New Source,然后选择Implementation Constraints File,之后输入UCF的文件名,比如ceshi_ucf,然后点击next按钮、finish即可完成UCF文件的创建。
2.2.2 通过过程管理器
在Sources for窗口的下拉菜单选择 Synthesis/Implementation ,然后在Processes窗口展开User Constraints,双击下面的Create Timing Constraints,这样就可以打开Constraints Editor约束文件编辑器。打开之后,就可以直接输入引脚编号进行引脚分配了。
UCF其实就是将之前top文件中写的那些输入、输出端口与实际的PCB板中的FPGA引脚对应起来。比如这个二分频,UCF文件中一共需要写三个。输入、输出、重置。
下面是该UCF内的三行语句:
NET "clkout" LOC = AC6;// 将FPGA的AC6引脚分配给clkout,作为输出引脚NET "clk" LOC = C14;// C14是时钟:PCB上写着CLKINNET "rst" LOC = D2;// 这是复位按钮
写UCF文件的思想就是,首先找到FPGA中的时钟,本次用的时钟是59MHz,找到时钟对应的引脚之后,将它与我之前写的那个TOP文件中的clk(时钟输入)对应起来,时钟的输入解决之后,再解决输出问题,这里我随便选了一个引脚AC6(也就是PCB图左下角的那一排口)作为输出引脚,然后与TOP文件中的clkout对应起来,这样如果二分频实现了之后,就可以将分完的频(59除以2)通过clkout引脚显示出来,那么怎么显示呢,由于选择了AC6引脚作为输出,将探针一端接入示波器,另一端放到AC6的位置,这样就会发现分完的频率通过AC6在示波器上显示了出来。
2.3 BIT文件生成
在语法检查没有错误之后,双击Processes窗口下的:Generate Programming File选项,就会在项目的目录下面生成.bit文件。
生成完.bit文件之后,就可以按照培训大纲中所说的,在线烧写BIT文件,然后可以通过示波器测量时钟的输出频率了。
2.4 如何烧写
从开始菜单找到iMPACT,单击打开,出现下图:
点击OK,进入下一步:
添加Bit 文件,右键单击xc4vsx55,选中Program 即可完成烧写。
至此,第一个实验结束