本文分为两个部分
第一部分 verilog知识点简要回顾
第二部分 数字时钟设计
第一部分:verilog知识点回顾
1,数值表示方法
verilog支持两种格式的数值表示方法: 指明位宽的数字(sized number)和不指明位宽
的数字(unsized number)。
指明位宽的数字的表示形式为:’
;
4’ b1001; //4 位宽的二进制数 1001
12’habc; // 12 位的十六进制数 abc
16’d255; //16 位十进制数
如果在数字说明中没有指定基数, 那么默认为十进制数; 如果没有指定位宽, 则默认的
位宽与仿真器、综合器使用的计算机有关(最小为 32 位)。举例如下:
23456; //32 位宽的十进制数 23456
’habc; // 32 位的十六进制数 abc
2,端口连接规则
3,向量
线网和寄存器类型的变量可以声明为向量(Vector)(位宽大于 1),如果声明中没有指定位
宽,则默认为标量(位宽为 1)。举例如下
wire a; //标量线网变量,默认
reg [n-1:0]busA,busB; //声明 busA 和 busB 为 n 位宽寄存器变量,
reg [0:n-1]busC; //声明 busC 为 n 位宽的寄存器变量
wire [n-1:0]busA,busB; //声明 busA 和 busB 为 n 位宽信号,
wire [0:n-1]busC; //声明 busC 为 n 位宽的信号
向量通过[high#:low#]或者[low#:high#]说明,方括号中左边数总是代表向量的最高有效
位(Most Significant Bit, MSB),在上面的例子中,向量 busA 的最高有效位为第 n-1 位
,向量busC 的最高有效位为第 0 位。
1、向量域选择
对于上面例子中声明的向量,可以指定它的某一位或若干个相邻位。举例如下
busA[0] //向量 busA 的第 0 位;
busA[2:0] //向量第 3 位;如果写成 busA[0:2]非法,高位应该写在范围说明的左侧;
busC[0:1] //向量 busC 的高 2 位;
2、可变的向量域选择
除了用常量指定向量域外, Verilog HDL 还允许指定可变的向量域选择。 这样使设计者可
以通过 for 循环动态地选取向量的各个域,下面是动态域选择的两个专用操作符
[ +: width]: 从起始位 starting_bit 开始递增,位宽为 width;
[ -: width]: 从起始位 starting_bit 开始递增,位宽为 width;
4,数组
在 Verilog HDL 中允许声明 reg 以及 wire 类型向量以及标量的数组,对数组的维数没有
限制。 线网数组也可用于连接连接实例的端口, 数组中的每个元素可以作为变量或者向量使
用。
reg [4:0]port_id[0:7] //由 8 个 5 位宽的向量组成的数组,数组的每个元素为 5 位宽变量
5 always语句
always@([sensitivity_list])
begin [optional_block_name]
[optional local variable declaration];
[procedural statement];
[procedural statement];
end
[sensitivity_list]称为敏感列表, 敏感列表是可选的, 有时也被称为事件控制表达式(event
control expression)。
规则
• always 只能赋值寄存器reg integer real time realtime 类型
• 启动仿真时所有always 都开始执行而且在仿真过程中持续执行当到达always 的最后一条
从仿真角度讲, 敏感信号值发生改变, always 块会对其改变做出
响应,即顺序执行 always 块中的所有语句。always 块如果包含多条语句,则需要将多个语句置于 begin 和 end 之间。如果只有 1 条语句,则可以省略 begin 和 end。注意:出于代码
可维护性的考虑,建议只有一条语句时也使用 begin 和 end。举例如下:
//电平敏感的敏感列表
always@(a or b or c) //always 块描述的组合逻辑电路的输入为 a,b 和 c。
always@(a, b, c) //另外一种形式的敏感列表, 敏感列表包含多个信号时可以采//
用关键字 or 分割,也可以采用逗号(;)分割;
always@* //另外一种形式的敏感列表,表示 always 块中所有赋值表达式
//中的所有变量都是敏感信号。
6,阻塞与非阻塞
过程赋值语句只能出现在 always 块或者 initial 块中,分为两种类型:阻塞赋值(blocking
assignment)和非阻塞赋值(non-blocking assignment)。其基本语法如下:
[variable_name1] = expression1; 阻塞赋值语句
[variable_name2] <= expression2; 非阻塞赋值语句
阻塞赋值语句中, 赋值表达式首先被计算, 之后将计算结果赋值给左侧变量。 此过程连续执行,在完成赋值前不能执行其后的其它任何语句(该赋值语句的执行“阻塞”其后其它语句的执行),其行为非常类似 C 语言中变量赋值过程。
无论是阻塞赋值还是非阻塞赋值都只能对寄存器类型(reg)的变量赋值。这里需要强调:虽然过程赋值语句只能对寄存器类型的变量赋值, 并不代表最终的综合结果一定包含寄存器。
非阻塞赋值语句执行时, 首先计算表达式的值, 但并不会立即将表达式的值赋予左侧变量,赋值操作会在 always 块所有语句执行完成之后再将表达式的值赋予左侧变量(赋值过程并不会“阻塞”其后的其它语句的执行)。
对于 Verilog HDL 的初学者,阻塞赋值语句和非阻塞语句的使用非常困难。如果不能理
解二者的区别往往导致最终的电路出现竞争和冒险。 这里给出 2 条经验规则(rules of thumb):
组合逻辑描述中使用阻塞赋值语句;
时序电路的描述中使用非阻塞赋值语句;
7,if else
//类型 1:只有 if 子句,不包含 else 分支
if(expression)
begin //expression 为真时,执行
true_statement1;
true_statement2;
…
end
//类型2
if(expression)
begin //expression 为真时,执行
true_statement1;
true_statement2;
…
end
else
begin //expression 为假时,执行
false_statement1;
false_statement2;
…
end
举例
always @*
if (en==1'b0) //等价于 if(~en)
y = 4'b0000;
else if (a==2'b00)
y = 4'b0001;
else if (a==2'b01)
y = 4'b0010;
else if (a==2'b10)
y = 4'b0100;
else
y = 4'b1000;
8,case 语句语法
case (case_expression)
alternative1:
begin
procedural_statement11;
procedural_statement12;
…
end
alternative2:
begin
procedural_statement21;
procedural_statement22;
…
end
…
alternativen:
begin
procedural_statementn1;
procedural_statementn2;
…
end
default:
begin
procedural_statement_1;
procedural_statement_2;
…
end
endcase
举例
always@*
begin
case(s)
2'b00: y=a;
2'b01: y=b;
2'b10: y=c;
2'b11: y=d;
default: y=8'bxxxxxxxx;
endcase
end
第二部分:数字时钟设计
设计思路
1,首先我们要让代表秒的led每秒闪烁一次
所以我们要设计一个2hz 的时钟来提供led闪烁
2,其次我们设计三个计数器 周期分别是60 60 24代表秒 分 时 计数满后向相邻计数器进1
3,数码管驱动程序每ms把计数器数据显示到数码管上即可
第二部分数字时钟设的
1,制作2hz时钟驱动led每秒亮一次
2,实现三个计数器 周期分别为24小时 60分 60秒
60=11 1100 6位
24= 1 1000 5位
3,实现每秒把计数器数据显示到数码管 可参考此设计思想
目前目测
2005jiangxu_694877046 2015-3-11 08:54
liang890319_284707880 2013-9-2 08:00
用户961355 2013-8-31 15:19