3.3 信号定义
下面需要将 module 补充完整,首先要做的是定义信号的类型。在判断信号类型时会感到很困惑,搞不清楚如何确定 reg 和 wire。其实大多数的困惑是因为联想的太多,例如认为 reg 就是寄存器,wire 是线,或者认为 reg 类型会综合成寄存器,wire 类型不会综合成寄存器,然而实际上这些与信号是reg 型还是 wire 型都并无关系。至简设计法建议不要进行任何联想,只遵从一个规则“用 always 实
现的是 reg 型,其他都是 wire 型”。进行信号定义时,除了信号的类型,还需要确定信号的位宽。至简设计法在这里分享一个非常实
用的获取信号位宽的技巧:打开计算器,点击“查看”,选择“程序员”模式,在“十进制”下输入数字后就会获得对应的信号位宽。
cnt0 是用 always 产生的信号,因此类型为 reg。根据前文计算可知 cnt0 计数的最大值为 500_000_000,根据至简设计法的实用技巧,打开计算器后在程序员模式十进制下输入 500_000_000,如下图所示。可以看出,信号的位宽为 29。
综上所述 cnt0 的定义代码如下:
同样的,cnt1 也是用 always 产生的信号,因此类型为 reg。cnt1 计数的最大值为 8,需要用 4根线表示,即位宽是 4 位。编辑模式下输入“Reg4”调用至简设计法模板,补充完整后得到代码表示如下:
add_cnt0 和 end_cnt0 都是用 assign 方式设计的,因此类型为 wire。其值是 0 或者 1,用 1 根线表示即可,即位宽为 1。编辑模式下输入“Wire1”调用至简设计法模板,补充完整后得到代码表示如下:
同样的,add_cnt1 和 end_cnt1 也是用 assign 方式设计的,类型为 wire。其值是 0 或者 1,位宽为 1。编辑模式下输入“Wire1”调用至简设计法模板,补充完整后得到代码表示如下:
led 是用 always 方式设计的,因此类型为 reg。led 信号值是 0 或者 1,1 根线表示即可。编辑模式下输入“Reg1”调用至简设计法模板,补充完整后得到代码表示如下:
x 是用 always 方式设计的,因此类型为 reg。其最大值为 500_000_000,需要用 29 根线表示,即位宽为 29。需要注意的是:这里的 x 是使用组合逻辑设计的,综合结果也不会有寄存器,但是遵循刚刚提到的信号判断原则,x 是用 always 设计出来的,所以依旧使用 reg 型来进行定义。代码表示如下:
至此,整个代码的设计工作已经完成。完整版的工程代码如下:
module mdyBookMyLed( clk, rst_n, led ); input clk; input rst_n; output led; reg [28:0] cnt0; reg [3:0] cnt1; wire add_cnt0; wire end_cnt0; wire add_cnt1; wire end_cnt1; reg led; reg [28:0]x; /***计数器cnt0计算时间***/ always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = 1; assign end_cnt0 = add_cnt0&&cnt0==x-1; /***第二个计数器计数次数***/ always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt1<=0; end else if(add_cnt1)begin if(end_cnt1) cnt1<=0; else cnt1<=cnt1+1; end end assign add_cnt1 = end_cnt0; assign end_cnt1 = add_cnt1 && cnt1==9-1; /***led亮灭信号控制****/ always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led<=1; end else if(add_cnt0&&cnt0==50_000_000-1)begin led<=0; end else if(end_cnt0)begin led<=1; end end /****变量x控制*****/ always @(*)begin if(cnt1==0)begin x=100_000_000; end else if(cnt1==1)begin x=150_000_000; end else if(cnt1==2)begin x=200_000_000; end else if(cnt1==3)begin x=250_000_000; end else if(cnt1==4)begin x=300_000_000; end else if(cnt1==5)begin x=350_000_000; end else if(cnt1==6)begin x=400_000_000; end else if(cnt1==7)begin x=450_000_000; end else begin x=500_000_000; end end /******至此程序已经结束****/
第四节 综合和上板
上一节完成了代码的设计,接下来需要对其进行综合以及上板调试。
4.1 新建工程
打开软件 Quartus Ⅱ,点击 File 下拉列表中的 New Project Wzard…新建工程选项,如图 3.1- 57 所示。
随后如下图所示的 Quartus 新建工程介绍,直接点击“Next”。
此时会出现工程文件夹、工程名、顶层模块名设置界面,如错误!未找到引用源。11 所示。
注意目录为:D:/mdy_book/mdyBookMyLed,工程名和顶层名为 mdyBookMyLed。
这里再次进行强调,为了避免初学者使用过程中出现报错情况,强烈建议按照本书的工程名和文件名进行设置,设置完成后点击 Next。
新建工程类型设置选择“Empty project”,如下图所示,然后点击“Next”。
文件添加界面如图 3.1-61 所示,此时添加之前写的“mdyBookMyLed.v”文件,点击右侧的“Add”按钮后文件会在下方显示出来,随后点击“Next”。
文件添加界面如图 3.1-61 所示,此时添加之前写的“mdyBookMyLed.v”文件,点击右侧的“Add”按钮后文件会在下方显示出来,随后点击“Next”。
芯片型号选择界面如图 3.1-62 所示,选择“Cyclone ⅣE”,在芯片型号选择处选择“EP4CE15F23C8”,然后点击“Next”。
QUARTUS 设置工具界面如图 3.1-63 所示,不必要修改,直接点击“Next”。
图 3.1-65 中可以看到新建工程的汇总情况,点击“Finish”,完成新建工程。
4.2 综合
新建工程步骤完成后,QUARTUS 界面如下图所示。
点击编译按钮,可以对整个工程进行编译,编译成功后的界面如图 3.1-66 所示。
4.3 配置管脚
下面需要对相应管脚进行配置。如图 3.1-67 所示,在菜单栏中选中 Assignments 后选择 Pin Planner,随后配置管脚的窗口就会弹出。
在配置窗口最下方中的 location 一列,按照表 3.1-2 中最右两列进行 FPGA 管脚的配置。此处配置管理来源的选择在最开始的管脚配置设计环节中有进行讲解,最终配置的结果见图 3.1-68。
配置完成后关闭“Pin Planner”,软件自动会保存管脚配置信息。
4.4 再次综合
再次打开“QUARTUS”软件,在菜单栏中选中“Processing”,然后选择“Start Compilation”,再次对整个工程进行编译和综合,如图 3.1-69 所示。
当出现图 3.1-70 时说明编译综合成功。
4.5 连接开发板
完成编译后开始进行上板调试操作,首先进行开发板的连接。按照图 3.1-71 中的方式将下载器接入电脑 USB 接口,接上开发板电源后按下开发板下方蓝色开关。
4.6上板
单击图 3.1-72QUARTUS 界面中的
按钮,弹出配置界面。
随后点击 add file 后添加.sof 文件,之后点击“Start”,在“Progress”会显示出进度。
如图 3.1-73 所示,“Progress”进度条中提示成功后即可在开发板上观察到相应的现象。可以看到开发板上的 LED 灯开始闪烁,并且按照亮一秒灭一秒,亮两秒灭一秒的规律进行循环闪烁。当观察到开发板上的 LED 灯可以照常闪烁,并且在亮九秒灭一秒后又回到亮一秒灭一秒的循环时就可以判断此次实验成功。如果出现 LED 灯不亮或者不能按照规律进行闪烁等情况时,需要回头思考检查问题的出现点,建议可以多进行几遍操作,不要粗心,找到错误点后进行改正。
第五节 modelsim仿真
编写测试代码如下:
module tb_my_led; parameter CYCLE = 20; reg clk; reg rst_n; wire led; my_led uut( . clk (clk), . rst_n (rst_n), . led (led) ); initial begin clk = 0; forever#(CYCLE/2)begin clk=~clk; end end initial begin #1; rst_n = 0; #(10*CYCLE); rst_n = 1; end endmodule
用Modelsim去添加文件仿真得结果:
找到编写文件的并加载。