规划一款电子表芯片,能够显示年月日,星期,并且实现闰年的自动调整,钟振32768Hz。
要求:增加测试设计,快速覆盖400年周期
目的:
- 掌握Verilog语言对组合逻辑的描述
- 学习testbench的设计方法
- 掌握仿真器(modelsim/Verilog/VCS)的仿真、调试、波形输出等常用技巧
- 掌握DC约束规划方法、综合器使用、结果查看、后仿真等
- 熟悉简单芯片从规划到实现方法
设计思路:
assign year_4 = (year[1:0]==2'b0);
assign year_100 = (year == 1900)||(year == 2100)||(year == 2200);
assign year_400 = (year == 2000);
if((year_4&&!year_100)||year_400)
number=29;
else
number=28;
文件代码如下:
module calendar(
// 时钟、复位、设置时间
input clk , rst , time_set,
// 设置时间的4个参数
input[11:0] year_set,
input[3:0] mon_set,
input[2:0] week_set,
input[4:0] day_set,
// 输出显示日历,年份最大是2299年,因此使用2^12 = 4096,12位寄存器存储年份信息
output reg[11:0] year,
output reg[3:0] mon,
output reg[2:0] week,
output reg[4:0] day,
// 月进位和年进位
output reg mon_carry , year_carry
);
// 设置每个月的天数
reg[4:0] number;
wire year_4;
wire year_100;
wire year_400;
// 判断是否闰年
assign year_4 = ( year[1:0]==2'b0 );
assign year_100 = ( year == 1900 ) || ( year == 2100 ) || ( year == 2200 );
assign year_400 = ( year == 2000 );
// 每当设置时间或时钟上升沿到来,以天为单位,天数+1,加到这个月的天数,输出月进位信号
always@(posedge time_set or posedge clk or negedge rst)
begin
if(rst)
begin
day<=1;
end
else if(time_set)
begin
day<=day_set;
mon_carry<=0;
end
else if(day==number)
begin
day<=1;
mon_carry<=1;
end
else
begin
day<=day+1;
mon_carry<=0;
end
end
// 星期数逐天增加,到星期日后回到星期一
always@(posedge time_set or posedge clk or negedge rst)
begin
if(rst)
begin
week<=6;
end
else if(time_set)
begin
week<=week_set;
end
else if(week==7)
begin
week<=1;
end
else
begin
week<=week+1;
end
end
// 每当月进位信号来临,月份+1
always@(posedge mon_carry or posedge time_set or negedge rst)
begin
if(rst)
begin
mon<=1;
end
else if(time_set)
begin
mon<=mon_set;
year_carry<=0;
end
else if(mon==12)
begin
mon<=1;
year_carry<=1;
end
else
begin
mon<=mon+1;
year_carry<=0;
end
end
// 每当年进位信号来临,年份+1
always@(posedge year_carry or posedge time_set or negedge rst)
begin
if(rst)
begin
year<=1900;
end
else if(time_set)
begin
year<=year_set;
end
else if(year==2299)
begin
year<=1900;
end
else
begin
year<=year+1;
end
end
// 每当月份发生变化,将每个月的天数赋值给number
always@(*)
begin
case(mon)
1 : number=31;
2 :
begin
if ( ( year_4 && ! year_100 ) || year_400 )
number=29;
else
number=28;
end
3 : number=31;
4 : number=30;
5 : number=31;
6 : number=30;
7 : number=31;
8 : number=31;
9 : number=30;
10 : number=31;
11 : number=30;
12 : number=31;
default: number=31;
endcase
end
endmodule
测试代码如下:
// 仿真测试时间间隔和真实时间没有任何关系,可以随便设置
`timescale 1ns/1ns
module calendar_tb;
reg clk , rst , time_set;
reg[11:0] year_set;
reg[3:0] mon_set;
reg[2:0] week_set;
reg[4:0] day_set;
wire[11:0] year;
wire[3:0] mon;
wire[2:0] week;
wire[4:0] day;
wire mon_carry,year_carry;
// 实例化
calendar v1(
.clk(clk),
.time_set(time_set),
.rst(rst),
.year_set(year_set),
.mon_set(mon_set),
.week_set(week_set),
.day_set(day_set),
.year(year),
.mon(mon),
.week(week),
.day(day),
.year_carry(year_carry),
.mon_carry(mon_carry)
);
// 开始测试,#10=1天,#300=1月,#100 = 一周多
initial
begin
clk=0;
forever #5 clk=~clk;
end
initial
begin
time_set=0;
rst=0;
#10 rst=1;
#10 rst=0;
#300 time_set=1;
#1 time_set=0;
#300 time_set=1;
#1 time_set=0;
#300 time_set=1;
#1 time_set=0;
#300 time_set=1;
#1 time_set=0;
end
initial
begin
year_set=1900;
mon_set=1;
week_set=1;
day_set=1;
#320;
year_set=1900;
mon_set=2;
week_set=3;
day_set=28;
#300;
year_set=2000;
mon_set=2;
week_set=1;
day_set=28;
#300;
year_set=2100;
mon_set=12;
week_set=5;
day_set=31;
#300;
year_set=2299;
mon_set=12;
week_set=5;
day_set=31;
#300;
$stop;
end
endmodule
贴出首次仿真图,测试时间为:
本次实验目标前三点基本达成,本帖完结,功能仿真结束后的代码覆盖率仿真和综合工作内容见下帖。
本文代码参考自https://blog.csdn.net/limanjihe/article/details/46942265
相关文章:
利用Verilog HDL规划一款电子表芯片(万年历)
在modelsim中对万年历进行代码覆盖率仿真
在CentOS中使用Design Compiler (DC) 图形界面/tcl脚本进行电路综合
在DC中使用tcl脚本综合和Formality一致性检查
使用VCS对电路进行后仿真