赞
踩
目录
在门级(低级)抽象层次上,电路是用表示门的术语来描述的,如用与门(and),与非门(nand)等来描述。这种设计方法对于具有数字逻辑设计基础知识的同学来说是很直观的。
基本的逻辑门分为两类:
基本门类别:and(与门),nand(与非门),or(或门),nor(或非门),xor(异或门),xnor(同伙们)。在verilog中这些们都具有一个标量输出端和多个标量输入端。
实例引用:门的端口列表第一个端口必定是输出端口,其后为输入。
- wire OUT, In1, In2;
- // 基本门实例引用
- and a1(OUT, In1, In2);
- nand na1(OUT, In1, In2);
- or or1(OUT, In1, In2);
- nor nor1(OUT, In1, In2);
- xor xo1(OUT, In1, In2);
- xnor nxo1(OUT, In1, In2);
-
- // 输入端超过两个
- and a2(OUT, In1, In2, In3);
-
- // 实例引用,不给实例名
- nand (OUT, In1, In2, In3);
基本门的真值表:
and | 0 | 1 | x | z |
0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | x | x |
x | 0 | x | x | x |
z | 0 | x | x | x |
nand | 0 | 1 | x | z |
0 | 1 | 1 | 1 | 1 |
1 | 1 | 0 | x | x |
x | 1 | x | x | x |
z | 1 | x | x | x |
or | 0 | 1 | x | z |
0 | 0 | 1 | x | x |
1 | 1 | 1 | 1 | 1 |
x | x | 1 | x | x |
z | x | 1 | x | x |
nor | 0 | 1 | x | z |
0 | 1 | 0 | x | x |
1 | 0 | 0 | 0 | 0 |
x | x | 0 | x | x |
z | x | 0 | x | x |
xor | 0 | 1 | x | z |
0 | 0 | 1 | x | x |
1 | 1 | 0 | x | x |
x | x | x | x | x |
z | x | x | x | x |
nxor | 0 | 1 | x | z |
0 | 1 | 0 | x | x |
1 | 0 | 1 | x | x |
x | x | x | x | x |
z | x | x | x | x |
两种基本门:缓冲器(buf);非门(not)。具有一个标量输入和多个标量输出。端口列表中最后一个终端连接至输入端口,其他连接至输出端口。
实例引用:
- buf b1(OUT, IN);
- not n1(OUT, IN);
-
- // 多输出端口
- buf b2(OUT1, OUT2, IN);
-
- // 不给实例名
- not (OUT1, OUT2, IN);
真值表:
buf | in | out | not | in | out | ||
0 | 0 | 0 | 1 | ||||
1 | 1 | 1 | 0 | ||||
x | x | x | x | ||||
z | z | z | x |
实例:四选一多路选择器
- module mux4to1(
- input i0, i1, i2, i3,
- input s1, s0,
- output out
- );
- wire s1n, s0n;
- wire y0, y1, y2, y3;
-
- not (s1n, s1);
- not (s0n, s0);
-
- and (y0, i0, s1n, s0n);
- and (y1, i1, s1n, s0 );
- and (y2, i2, s1 , s0n);
- and (y3, i3, s1 , s0 );
-
- or (out, y0, y1, y2, y3);
-
- endmodule
如果电路的逻辑功能复杂,包含逻辑门的个数很多,这时采用门级建模设计繁琐。这时采用更高抽象层次建模,Verilog允许用户从数据流的角度对电路建模。
数据流建模意味着根据数据在寄存器之间的流动和处理过程对电路进行描述。而后通过逻辑综合自动将电路的数据流设计转换为门级结构。
连续赋值语句是Verilog数据流建模的基本语句,用于对线网类型进行赋值。
- assign out = in1 & in2;
- assign {c_out, sum[3 : 0]} = a[3 : 0] + b[3 : 0] + c_in;
连续赋值语句的特点:
(1)左值必须是一个标量或向量线网,或是变量或向量线网的拼接,不能是寄存器;
(2)连续赋值语句总是处于激活状态,任意操作数变化,表达式立即重计算;
在线网声明同时对其赋值。由于线网只能被生命一次,因此对线网的隐式声明赋值只能有一次。
- // 普通的连续赋值
- wire out;
- assign out = in1 & in2;
-
- // 隐式连续赋值
- wire out = in1 & in2;
使用assign关键字,显式赋值。
实例:四选一多路选择器
- module mux4to1(
- input i0, i1, i2, i3,
- input s1, s0,
- output out
- );
- // 使用条件语句
- assign out = s1 ? (s0 ? i3 : i2) : (s0 ? i1 : i0);
-
- endmodule
Verilog还支持从电路外部形为的角度对其进行描述,即行为级建模。在这个层次上设计数字电路更类似于C语言。
Verilog中有两种结构化的过程语句,initial 语句和 always 语句,它们是行为级建模的两种基本语句。与 C 语言不同,Verilog在本质上是并发而非顺序执行的,每个 initial 和 always 语句代表一个独立的执行过程,每个执行过程从0时刻开始,产生独立的控制流,与其在模块之间的前后顺序没关系。并且两种语句不能嵌套使用。
initial语句
从0时刻开始执行,只执行一次。多个 initial 块间相互独立,如果一个模块中包含了多个 initial 块,则这些 initial 块从仿真0时刻开始并发执行。
initial 理论来讲不可综合,多用于初始化,信号检测,生成仿真波形等,
- initial begin
- #5 a = 1'b1;
- #5 a = 1'b0;
- #5 a = 1'n1;
- end
always语句
always 语句是重复执行的,从仿真0时刻开始按顺序执行其中语句,当执行完最后一条语句,便再次从语句中第一条语句开始执行,直至仿真结束。多用于时钟信号的产生。
- module clock_gen(
- output reg clk;
- );
- // 0时刻初始化低
- initial clk = 1'b0;
-
- // 每10个时间单位,clk翻转
- always begin
- #10;
- clk = ~clk;
- end
-
- // 停止
- always begin
- if ($time >= 100)
- $finish;
- end
-
- endmodule
过程赋值语句的更新对象是寄存器,整数,实数或时间变量。这些类型的变量在被赋值后,其值将保持不变,直到被其他过程赋值语句重新赋值。
Verilog 包括两种类型的过程赋值语句:阻塞赋值和非阻塞赋值
属于顺序执行,即下一条语句执行前,当前语句一定会被执行完毕,使用等号 = 作为赋值符。
属于并行执行,即下一条语句的执行和当前语句的执行是同时进行的。使用 小于等于号 <= 作为赋值符。
- `timescale 1ns/1ns
- module test ;
- reg [3:0] ai, bi ;
- reg [3:0] ai2, bi2 ;
- reg [3:0] value_blk ;
- reg [3:0] value_non ;
- reg [3:0] value_non2 ;
-
- initial begin
- ai = 4'd1; (1)
- bi = 4'd2; (2)
- ai2 = 4'd7; (3)
- bi2 = 4'd8; (4)
- #20; (5)
-
- ai = 4'd3; (6)
- bi = 4'd4; (7)
- value_blk = ai + bi; (8)
- value_non <= ai + bi; (9)
-
- ai2 <= 4'd5; (10)
- bi2 <= 4'd6; (11)
- value_non2 <= ai2 + bi2; (12)
- end
-
-
- endmodule
仿真结果(来源于www.runoob.com)
分析:
语句(1)-(8)都是阻塞赋值,按照顺序执行。
20ns 之前,信号 ai,bi 值改变。由于过程赋值的特点,value_blk = ai + bi 并没有执行到,所以 20ns 之前,value_blk 值为 X(不确定状态)。
20ns 之后,信号 ai,bi 值再次改变。执行到 value_blk = ai + bi,信号 value_blk 利用信号 ai,bi 的新值得到计算结果 7。
语句(9)-(12)都是非阻塞赋值,并行执行。
首先,(9)-(12)虽然都是并发执行,但是执行顺序也是在(8)之后,所以信号 value_non = ai + bi 计算是也会使用信号 ai,bi 的新值,结果为 7。
其次,(10)-(12)是并发执行,所以 value_non2 = ai2 + bi2 计算时,并不关心信号 ai2,bi2 的最新非阻塞赋值结果。即 value_non2 计算时使用的是信号 ai2,bi2 的旧值,结果为 4'hF。
有关时序控制,条件,分支,循环语句内容就不再赘述。
顺序块:使用关键字 behin 和 end 组成。
特点:(1)顺序块中的语句是一条条执行;前面的语句执行完后边的才能执行。当然,非阻塞赋值除外。
(2)顺序块中每条语句的时延总是与其前面语句执行的时间相关。
- initial begin
- x = 1'b0; // 在仿真0时刻完成
- #5; y = 1'b1; // 在仿真时刻5完成
- #10; z = {x, y}; // 在仿真时刻15完成
- #20; w = {y, x}; // 在仿真时刻35完成
- end
并行快:使用关键字 forl 和 join 组成。
特点:(1)并行快内语句并发执行。
(2)语句执行顺序是由各自语句中的延迟或事件控制决定。
(3)每条语句的时延都是相对于块语句开始执行的时刻而言。
- reg x, y;
- reg [1 : 0] z, w;
-
- initial fork
- x = 1'b0; // 仿真时刻0完成
- #5 y = 1'b1; // 仿真时刻5完成
- #10 z = {x, y}; // 仿真时刻10完成
- #15 w = {y, x}; // 仿真时刻15完成
- join
块语句可以嵌套;即在 begin end中嵌套 fork join;
实例:四选一多路选择器
- module mux4to1(
- input i0, i1, i2, i3,
- input s1, s0,
- output out
- );
- reg out;
-
- always @(*) begin
- case ({s1, s0})
- 2'b00: out = i0;
- 2'b01: out = i1;
- 2'b10: out = i2;
- 2'b11: out = i3;
- default: out = 1'bx;
- endcase
- end
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。