
一、实验目的和要求
掌握典型同步时序电路的工作原理和设计方法
掌握时序电路的激励函数、状态图、状态方程的运用
掌握用Verilog进行有限状态机的设计、调试、仿真
掌握用FPGA实现时序电路功能
二、实验内容和原理
2.1 实验内容
任务1:原理图方式设计4位同步二进制计数器
任务2:以Verilog行为描述方式设计16位可逆二进制同步计数器
2.2 实验原理
2.2.1 4位二进制同步计数器
1. 根据 D 触发器原理,在 clk 作用下 Q = D,4位计数器的 Q 和 D 关系如下表所示:

4位计数器 D、Q关系表
2. 激励函数如下表所示:

4位二进制同步计数器激励函数
3. 进位 RC 的输出函数

进位 RC 输出函数
4. 具体原理图设计方式如下图所示:

5. 具体代码如下所示:
module counter_4bit(clk, Qa, Qb, Qc, Qd, Rc);
input wire clk;
output wire Qa, Qb, Qc, Qd, Rc;
wire Nor_nQa_nQb, Nor_nQa_nQb_nQc;
FD FD_A(.C(clk), .D(Da), .Q(Qa)),
FD_B(.C(clk), .D(Db), .Q(Qb)),
FD_C(.C(clk), .D(Dc), .Q(Qc)),
FD_D(.C(clk), .D(Dd), .Q(Qd));
defparam FD_A.INIT = 1'b0, FD_B.INIT = 1'b0;
defparam FD_C.INIT = 1'b0, FD_D.INIT = 1'b0;
INV nQa_L(.I(Qa), .O(nQa)), nQb_L(.I(Qb), .O(nQb)),
nQc_L(.I(Qc), .O(nQc)), nQd_L(.I(Qd), .O(nQd));
assign Da = nQa;
XNOR2 Db_L(.I0(Qa), .I1(nQb), .O(Db)),
Dc_L(.I0(Nor_nQa_nQb), .I1(nQc), .O(Dc)),
Dd_L(.I0(Nor_nQa_nQb_nQc), .I1(nQd), .O(Dd));
NOR4 Rc_L(.I0(nQa), .I1(nQb), .I2(nQc), .I3(nQd), .O(Rc));
NOR2 Nor_nQa_nQb_L (.I0(nQa), .I1(nQb), .O(Nor_nQa_nQb));
NOR3 Nor_nQa_nQb_nQc_L(.I0(nQa), .I1(nQb), .I2(nQc), .O(Nor_nQa_nQb_nQc));
2.2.2 4位可逆二进制同步计数器
1. 可逆二进制同步计数器通过控制端S选择正向或者反向计数
S = 1时,正向计数,各触发器逻辑表达式同前面
S = 0时,反向计数,各触发器逻辑表达式如下式

各触发器逻辑表达式
2. 具体代码如下所示:
module counter_4bit_rev(clk, s, cnt, Rc);
input wire clk, s;
output reg [3:0] cnt;
output wire Rc;
Initial begin cnt = 0;
assign Rc = (~s & (~|cnt)) | (s & (&cnt));
always @ (posedge clk) begin
if (s)
cnt <= cnt + 1;
else
cnt <= cnt - 1;
end
endmodule 2.2.3 分频器
1. 50 MHz信号通过 25,000,000 次分频后,得到 1 Hz 的秒脉冲方波,作为计数器的脉冲输入
2. 具体代码如下所示:
module counter_1s(clk, clk_1s);
input wire clk;
output reg clk_1s;
reg [31:0] cnt;
always @ (posedge clk) begin
if (cnt < 25_000_000) begin
cnt <= cnt + 1;
end else begin
cnt <= 0;
clk_1s <= ~clk_1s;
end
end
endmodule
三、主要仪器设备
实验设备:装有 Xilinx ISE 14.7 的计算机 1 台,SWORD开发板 1 套
实验材料:无
四、操作方法和实验步骤
4.1 设计4位同步二进制计数器
4.1.1 原理图设计计数器
1. 新建工程,名为 MyCounter_3190103044,Top Level Source Type 为 HDL
2. 新建类型为 schematic 的源文件,命名为 MyCounter4b
3. 用原理图方式设计,具体如下所示:

4位同步二进制计数器原理图
4. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol,在工程文件夹里可以找到相应的.sym文件
5. 进行波形仿真,具体代码如下:
`timescale 1ns / 1ps
module MyCounter4b_MyCounter4b_sch_tb();
// Inputs
reg ck;
// Output
wire Rc;
wire Qb;
wire Qc;
wire Qa;
wire Qd;
// Bidirs
// Instantiate the UUT
MyCounter4b UUT (
.ck(ck),
.Rc(Rc),
.Qb(Qb),
.Qc(Qc),
.Qa(Qa),
.Qd(Qd)
);
// Initialize Inputs
initial forever begin
ck = 1'b0; #10;
ck = 1'b1; #10;
end
endmodule
4.1.2 Verilog 代码设计时钟
1. 新建类型为 verilog module 的源文件,命名为 clk_1s
2. 用 verilog 代码设计,具体如下所示:
module clk_1s(clk, clk_1s);
input wire clk;
output reg clk_1s;
reg [31:0] cnt;
always @ (posedge clk) begin
if (cnt < 25_000_000) begin
cnt <= cnt + 1;
end
else begin
cnt <= 0;
clk_1s <= ~clk_1s;
end
end
endmodule 3. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol
4.1.3 Verilog 代码设计顶层模块 top
1. 新建类型为 verilog module 的源文件,命名为 top,并右键 Set as Top Module
2. 用 verilog 代码设计,具体如下所示:
module Top(
input wire clk,
output wire buzzer,
output wire LED,
output wire [7:0] SEGMENT,
output wire [3:0] AN
);
wire clk_1s;
wire [3:0] num;
clk_1s m0(.clk(clk), .clk_1s(clk_1s));
MyCounter4b m1(.ck(clk_1s), .Qa(num[0]), .Qb(num[1]), .Qc(num[2]),
.Qd(num[3]), .Rc(LED));
Disp_num m2( clk, {4'b0000, num[3:0], 4'b0000, 4'b1111}, 1'b0, AN, SEGMENT);
endmodule
3. Check Syntax 无误后,点击 Process 窗口下 Design Utilities -> Create schematic symbol生成逻辑符号和.vf文件
4. 进行引脚约束,下载到 SWORD 板进行验证。新建类型为 Implementation constraints file 的源文件,命名为 k7.ucf,具体代码如下所示:
NET "clk" LOC = AC18 | IOSTANDARD = LVCMOS18;
NET "SEGMENT[0]" LOC = AB22 | IOSTANDARD = LVCMOS33 ;#a
NET "SEGMENT[1]" LOC = AD24 | IOSTANDARD = LVCMOS33 ;#b
NET "SEGMENT[2]" LOC = AD23 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[3]" LOC = Y21 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[4]" LOC = W20 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[5]" LOC = AC24 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[6]" LOC = AC23 | IOSTANDARD = LVCMOS33 ;#g
NET "SEGMENT[7]" LOC = AA22 | IOSTANDARD = LVCMOS33 ;#point
NET "AN[3]" LOC = AC22 | IOSTANDARD = LVCMOS33 ;
NET "AN[2]" LOC = AB21 | IOSTANDARD = LVCMOS33 ;
NET "AN[1]" LOC = AC21 | IOSTANDARD = LVCMOS33 ;
NET "AN[0]" LOC = AD21 | IOSTANDARD = LVCMOS33 ; 4.2 设计16位可逆同步二进制计数器
4.2.1 Verilog 设计计数器
1. 新建工程,名为 myRevCounter,Top Level Source Type 为 HDL
2. 新建类型为 verilog module 的源文件,命名为 RevCounter
3. 用 verilog 代码设计,具体代码如下所示:
module RevCounter(clk, s, cnt, Rc);
input wire clk, s;
output reg [15:0] cnt;
output wire Rc;
assign Rc = (~s & (~|cnt)) | (s & (&cnt));
initial begin
cnt = 0;
end
always@(posedge clk) begin
if (s)
cnt <= cnt + 1;
else
cnt <= cnt - 1;
end
endmodule
4. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol,在工程文件夹里可以找到相应的.sym文件
5. 进行波形仿真,具体代码如下:
module RevCounter_sym;
// Inputs
reg clk;
reg s;
// Outputs
wire [15:0] cnt;
wire Rc;
// Instantiate the Unit Under Test (UUT)
RevCounter uut (
.clk(clk),
.s(s),
.cnt(cnt),
.Rc(Rc)
);
initial forever begin
s = 1'b1; // 正向计数为 s = 1'b0
clk = 1'b0; #10;
clk = 1'b1; #10;
end
endmodule 4.2.2 Verilog 代码设计时钟
1. 新建类型为 verilog module 的源文件,命名为 clk_100ms
2. 用 verilog 代码设计,具体如下所示:
module clk_100ms(clk, clk_1s);
input wire clk;
output reg clk_1s;
reg [31:0] cnt;
always @ (posedge clk) begin
if (cnt < 25_000_000) begin
cnt <= cnt + 1;
end else begin
cnt <= 0;
clk_1s <= ~clk_1s;
end
end
endmodule 3. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol
4.2.3 Verilog 代码设计顶层模块 top
1. 新建类型为 verilog module 的源文件,命名为 top,并右键 Set as Top Module
2. 用 verilog 代码设计,具体如下所示:
module Top(
input wire clk,
input wire SW,
output wire [7:0] SEGMENT,
output wire [3:0] AN,
output wire Rc
);
wire clk_100ms;
wire [15:0] num;
clk_100ms m0(.clk(clk), .clk_1s(clk_1s));
RevCounter m1(.clk(clk_1s), .s(SW), .cnt(num), .Rc(Rc));
Disp_num m2(clk, num, 1'b0, AN, SEGMENT);
endmodule
3. Check Syntax 无误后,点击 Process 窗口下 Design Utilities -> Create schematic symbol生成逻辑符号和.vf文件。
4. 进行引脚约束,下载到 SWORD 板进行验证。新建类型为 Implementation constraints file 的源文件,命名为 k7.ucf,具体代码如下所示:
NET "clk" LOC = AC18 | IOSTANDARD = LVCMOS18;
NET "SEGMENT[0]" LOC = AB22 | IOSTANDARD = LVCMOS33 ;#a
NET "SEGMENT[1]" LOC = AD24 | IOSTANDARD = LVCMOS33 ;#b
NET "SEGMENT[2]" LOC = AD23 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[3]" LOC = Y21 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[4]" LOC = W20 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[5]" LOC = AC24 | IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[6]" LOC = AC23 | IOSTANDARD = LVCMOS33 ;#g
NET "SEGMENT[7]" LOC = AA22 | IOSTANDARD = LVCMOS33 ;#point
NET "AN[3]" LOC = AC22 | IOSTANDARD = LVCMOS33 ;
NET "AN[2]" LOC = AB21 | IOSTANDARD = LVCMOS33 ;
NET "AN[1]" LOC = AC21 | IOSTANDARD = LVCMOS33 ;
NET "AN[0]" LOC = AD21 | IOSTANDARD = LVCMOS33 ;
NET "Rc" LOC = AF24 | IOSTANDARD = LVCMOS33; #GPIOf0[0]
NET "SW" LOC = AA10 | IOSTANDARD = LVCMOS15;
五、实验结果和分析
5.1 波形仿真结果
1. 同步正向计数器
具体仿真结果如下图所示,与理论预估结果一致,故元件逻辑功能正确。

同步正向计数器波形仿真图
2. 同步正逆向计数器
具体仿真结果如下图所示,与理论预估结果一致,故元件逻辑功能正确。
逆向技术:

同步正逆向计数器逆向计数波形仿真图
正向计数:

同步正逆向计数器正向计数波形仿真图
5.2 物理验证结果
物理验证部分图片如下所示:


六、讨论和心得
6.1 数码管显示模块
七段数码管需要分频时钟信号逐个读入数字,实现视觉暂留。如果输入的分频时钟信号间隔过大则只能看到一个数字。同时,调用模块时切记声明接口、按照顺序接入,减少语法错误。
6.2 时钟分频
正逆向计数中使用的时钟是100ms而不是1s,这个时钟分频并不影响逻辑功能的实现。但如果增减速度 过慢,实验现象不是很明显,需要很久才能达到FFFF。