接前文《【学习笔记】4、组合逻辑电路(上)》
半加器:只考虑两个加数本身,不考虑低位进位。
A、B是两个加数
S表示和数
C表示进位
列出真值表:
A | B | C | S |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 |
1 | 0 | 0 | 1 |
1 | 1 | 1 | 0 |
A加数1 | B加数2 | C i 低位进位 C_i低位进位 Ci低位进位 | C o 进位 C_o进位 Co进位 | S和 |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 1 |
1 | 0 | 0 | 0 | 1 |
1 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 0 | 1 |
0 | 1 | 1 | 1 | 0 |
1 | 0 | 1 | 1 | 0 |
1 | 1 | 1 | 1 | 1 |
S
=
A
‾
⋅
B
‾
⋅
C
i
+
A
‾
⋅
B
⋅
C
i
‾
+
A
⋅
B
‾
⋅
C
i
‾
+
A
B
C
i
=
A
⊕
B
⊕
C
i
S=\overline{A}·\overline{B}·C_i+\overline{A}·B·\overline{C_i}+A·\overline{B}·\overline{C_i}+ABC_i=A⊕B⊕C_i
S=A⋅B⋅Ci+A⋅B⋅Ci+A⋅B⋅Ci+ABCi=A⊕B⊕Ci//异或
C
o
=
A
‾
⋅
B
⋅
C
i
+
A
⋅
B
‾
⋅
C
i
+
A
⋅
B
=
(
A
⊕
B
)
⋅
C
i
+
A
⋅
B
C_o = \overline{A}·B·C_i+A·\overline{B}·C_i+A·B=(A⊕B)·C_i+A·B
Co=A⋅B⋅Ci+A⋅B⋅Ci+A⋅B=(A⊕B)⋅Ci+A⋅B
74HC283
考虑到全加器组成的“并行相加,串行进位”的缺点,设计了新的多位加法逻辑电路。
这里的超前,指的是 各个位加法不用等低1位的进位信号,提前进行加法。
每位的进位,只由加数和被加数决定,与低位的进位无关。
前文的全加器逻辑表达式:
为了只观察进位
C
i
C_i
Ci,定义中间变量
G
i
=
A
i
B
i
,
P
i
=
A
i
⊕
B
i
G_i=A_iB_i,P_i=A_i⊕B_i
Gi=AiBi,Pi=Ai⊕Bi,这两个中间变量,在计算一开始,就已经固定了。
这里重点关注 C i = P i ⋅ C i − 1 + G i C_{i} =P_i·C_{i-1}+G_i Ci=Pi⋅Ci−1+Gi,一个迭代函数。
逻辑图。
下图是猜测的74HC283逻辑图。
串联进位,级联。
超前进位产生器(并不是一个完整的加法器)
分类 | 元件符号 | 功能说明 |
---|---|---|
多输入门 | and | 与门 |
多输入门 | nand | 与非门 |
多输入门 | or | 或门 |
多输入门 | nor | 或非门 |
多输入门 | xor | 异或门 |
多输入门 | xnor | 异或非门 |
------------ | ---------- | ------------------------------------------ |
多输出门 | buf | 缓冲器 |
多输出门 | not | 反相器 |
------------ | ---------- | ------------------------------------------ |
三态门 | bufif1 | 三态缓冲器,if-如果,控制信号为1-高电平,输出有效 (in->out) |
三态门 | bufif0 | 三态缓冲器 ,if-如果,控制信号为0-低电平,输出有效(in->out) |
三态门 | notif1 | 三态反相器,if-如果,控制信号为1-高电平,输出有效(in->out) |
三态门 | notif0 | 三态反相器,if-如果,控制信号为0-低电平,输出有效 (in->out) |
and、nand、or、nor、xor、xnor
只允许一个输出,但允许有多个输入。
多输入门的输出端out,不可能为高阻状态z。
列出真值表,以2输入为例。
and 与门 | i n 1 = 0 in_1=0 in1=0 | i n 1 = 1 in_1=1 in1=1 | i n 1 = x in_1=x in1=x | i n 1 = z ( 高阻 ) in_1=z(高阻) in1=z(高阻) |
---|---|---|---|---|
i n 2 = 0 in_2=0 in2=0 | 0 | 0 | 0 | 0 |
i n 2 = 1 in_2=1 in2=1 | 0 | out=1 | x | x |
i n 2 = x in_2=x in2=x | 0 | x | x | x |
i n 2 = z ( 高阻 ) in_2=z(高阻) in2=z(高阻) | 0 | x | x | x |
nand 与非门 | i n 1 = 0 in_1=0 in1=0 | i n 1 = 1 in_1=1 in1=1 | i n 1 = x in_1=x in1=x | i n 1 = z ( 高阻 ) in_1=z(高阻) in1=z(高阻) |
---|---|---|---|---|
i n 2 = 0 in_2=0 in2=0 | out=1 | out=1 | out=1 | out=1 |
i n 2 = 1 in_2=1 in2=1 | out=1 | 0 | x | x |
i n 2 = x in_2=x in2=x | out=1 | x | x | x |
i n 2 = z ( 高阻 ) in_2=z(高阻) in2=z(高阻) | out=1 | x | x | x |
or 或门 | i n 1 = 0 in_1=0 in1=0 | i n 1 = 1 in_1=1 in1=1 | i n 1 = x in_1=x in1=x | i n 1 = z ( 高阻 ) in_1=z(高阻) in1=z(高阻) |
---|---|---|---|---|
i n 2 = 0 in_2=0 in2=0 | 0 | out=1 | x | x |
i n 2 = 1 in_2=1 in2=1 | out=1 | out=1 | out=1 | out=1 |
i n 2 = x in_2=x in2=x | x | out=1 | x | x |
i n 2 = z ( 高阻 ) in_2=z(高阻) in2=z(高阻) | x | out=1 | x | x |
xor 异或门 | i n 1 = 0 in_1=0 in1=0 | i n 1 = 1 in_1=1 in1=1 | i n 1 = x in_1=x in1=x | i n 1 = z ( 高阻 ) in_1=z(高阻) in1=z(高阻) |
---|---|---|---|---|
i n 2 = 0 in_2=0 in2=0 | 0 | out=1 | x | x |
i n 2 = 1 in_2=1 in2=1 | out=1 | 0 | x | x |
i n 2 = x in_2=x in2=x | x | x | x | x |
i n 2 = z ( 高阻 ) in_2=z(高阻) in2=z(高阻) | x | x | x | x |
buf缓冲器、not反相器
只能有一个输入,但允许多个输出。
列出1个输出的真值表
buf 缓冲器 | i n = 0 in=0 in=0 | i n = 1 in=1 in=1 | i n = x in=x in=x | i n = z ( 高阻 ) in=z(高阻) in=z(高阻) |
---|---|---|---|---|
输出out1 | 0 | 1 | x | x |
not 反相器 | i n = 0 in=0 in=0 | i n = 1 in=1 in=1 | i n = x in=x in=x | i n = z ( 高阻 ) in=z(高阻) in=z(高阻) |
---|---|---|---|---|
输出out1 | 1 | 0 | x | x |
bufif1、bufif0、notif1、notif0
有一个输出,一个输入,一个控制。
当控制信号为无效时,三态门输出高阻状态z。
if1表示,高电平时允许输出(in->out),低电平时,输出高阻状态。
if0表示,低电平时允许输出(in->out),高电平时,输出高阻状态。
列出真值表
bufif1 缓冲器 | 控制信号 c t r l = 0 控制信号ctrl=0 控制信号ctrl=0 | 控制信号 c t r l = 1 控制信号ctrl=1 控制信号ctrl=1 | 控制信号 c t r l = x 控制信号ctrl=x 控制信号ctrl=x | 控制信号 c t r l = z ( 高阻 ) 控制信号ctrl=z(高阻) 控制信号ctrl=z(高阻) |
---|---|---|---|---|
数据输入 i n = 0 数据输入in=0 数据输入in=0 | out=z(高阻) | out=0 | out=0或者z | out=0或者z |
数据输入 i n = 1 数据输入in=1 数据输入in=1 | out=z(高阻) | out=1 | out=1或者z | out=1或者z |
数据输入 i n = x 数据输入in=x 数据输入in=x | out=z(高阻) | x | x | x |
数据输入 i n = z ( 高阻 ) 数据输入in=z(高阻) 数据输入in=z(高阻) | out=z(高阻) | x | x | x |
notif1 缓冲器 | 控制信号 c t r l = 0 控制信号ctrl=0 控制信号ctrl=0 | 控制信号 c t r l = 1 控制信号ctrl=1 控制信号ctrl=1 | 控制信号 c t r l = x 控制信号ctrl=x 控制信号ctrl=x | 控制信号 c t r l = z ( 高阻 ) 控制信号ctrl=z(高阻) 控制信号ctrl=z(高阻) |
---|---|---|---|---|
数据输入 i n = 0 数据输入in=0 数据输入in=0 | out=z(高阻) | out=1 | out=1或者z | out=1或者z |
数据输入 i n = 1 数据输入in=1 数据输入in=1 | out=z(高阻) | out=0 | out=0或者z | out=0或者z |
数据输入 i n = x 数据输入in=x 数据输入in=x | out=z(高阻) | x | x | x |
数据输入 i n = z ( 高阻 ) 数据输入in=z(高阻) 数据输入in=z(高阻) | out=z(高阻) | x | x | x |
//门级Gate-Level
//2线-4线译码器 2-to-4 line decoder
module _2to4decoder(A1,A0,E,Y);
input A1,A0,E; //定义输入信号
output [3:0]Y;//定义输出信号
wire A1not,A0not,Enot;//内部节点信号
//非门
not n1(A1not,A1),
n2(A0not,A0),
n3(Enot,E);
//与非门
nand n4(Y[0],A1not,A0not,Enot),
n5(Y[1],A1not,A0 ,Enot),
n6(Y[2],A1 ,A0not,Enot),
n7(Y[3],A1 ,A0 ,Enot);
endmodule
`timescale 1ns / 1ns //时间单位和时间精度一般是1、10和100这三种整数,单位有s、ms、us、ns、ps和fs;
module _2to4decoder_TB;
reg [1:0]a; //输入信号(激励信号)必须定义为reg类型,用来保持信号值;
reg e;
wire [3:0]lout; //输出信号(显示信号)必须定义为wire类型;
parameter DELAY=50; //设置延迟参数为50
_2to4decoder fun(.A1(a[1]), .A0(a[0]), .E(e), .Y(lout));
initial //使用initial过程快定义激励信号波形
begin //使用begin-end控制语句
e=1'b1; a[1] = 1'b0; a[0] = 1'b0;
#DELAY e=1'b0; a[1] = 1'b0; a[0] = 1'b0; //50ns
#DELAY e=1'b0; a[1] = 1'b0; a[0] = 1'b1; //100ns
#DELAY e=1'b0; a[1] = 1'b1; a[0] = 1'b0; //150ns
#DELAY e=1'b0; a[1] = 1'b1; a[0] = 1'b1; //200ns
#DELAY $stop; //200ns,执行$stop系统任务,停止仿真
end
initial $monitor($time,,,"/E=%b,A1=%b,A1=%b,Y",e,a[1],a[0],~lout);
//执行monitor系统任务,设置显示结果的格式
endmodule
使用了三态门缓冲器bufif0,bufif1。
重点:L同时受两路信号驱动。在多驱动元的情况下逻辑值会发生冲突,从而产生不确定值。类似于竞争冒险。
在Verilog中:
//门级Gate-Level
//2线-1线数据选择器 2-to-1-line multiplexer
module _2to1muxtri(A,B,SEL,L)
input A,B,SEL;
output L; //定义输出信号
tri L;//tri数据类型(三态线网),多驱动网络类型。
bufif1(L,B,SEL);
bufif0(L,A,SEL);
endmodule
//2线-1线数据选择器 2-to-1-line multiplexer
module _2to1muxtri_TB;
reg SEL,A,B;
wire L;
parameter DELAY=50; //设置延迟参数为50
_2to1muxtri fun(.A(A),.B(B),.SEL(SEL),.L(L));
always #10 A=~A;
always #20 B=~B;
initial //使用initial过程快定义激励信号波形
begin
A=1;
B=1;
SEL = 1'b0;
#DELAY SEL = 1'b1; //50ns
#DELAY SEL = 1'b0; //100ns
#DELAY SEL = 1'b1; //150ns
#DELAY SEL = 1'b0; //200ns
#DELAY $stop; //200ns,执行$stop系统任务,停止仿真
end
initial $monitor($time,,,"SEL=%b,A=%b,B=%b,Y=%d",SEL,A,B,L);
endmodule
自顶而下(top-down):先定义顶层模块,再定义顶层模块用到的子模块。
自底向上(bottom-up):先定义底层的各个子模块,再将子模块组合起来,构成顶层模块。
上层模块调用下层模块时,通过模块名完成调用过程,调用名不能省略。
//半加器
module halfadder(S,C,A,B);
input A,B;
output S,C;
//和
xor(S,A,B);//S=A⊕B
//进位
and(C,A,B);//C=AB
endmodule
//全加器
module fulladder(S,CO,A,B,CI);
input A,B,CI;
output S,CO;
wire S1,D1,D2;
//计算中间值S1,D1
halfadder HA1(S1,D1,A,B);
//和
halfadder HA2(S,D2,S1,CI);
//进位
or g1(CO,D2,D1);
endmodule
module _4bit_adder(S,C3,A,B,C_1);
input [3:0]A,B;
input C_1;
output [3:0]S;
output C3;
wire C0,C1,C2;//内部进位信号
fulladder FA0(S[0],C0,A[0],B[0],C_1),
FA1(S[1],C1,A[1],B[1],C0),
FA2(S[2],C2,A[2],B[2],C1),
FA3(S[3],C3,A[3],B[3],C2);
endmodule
module _4bit_adder_TB;
reg [3:0]A,B;
reg C_1;
wire [3:0]S;
wire C3;
parameter DELAY=50; //设置延迟参数为50
_4bit_adder fun(.A(A),.B(B),.C_1(C_1),.S(S),.C3(C3));
initial
begin
C_1 = 0;A = 4'b0101;B = 4'b0001;
#DELAY C_1 = 1;A = 4'b0101; B = 4'b0001;
#DELAY C_1 = 0;A = 4'b0101; B = 4'b1010;
#DELAY C_1 = 1;A = 4'b0101; B = 4'b1010;
#DELAY $stop;
end
initial $monitor($time,,,"A=%b,B=%b,S=%b,C=%d",A,B,S,C3);
endmodule
类型 | 分类 | 符号 | 功能说明 |
---|---|---|---|
算术运算符 | 双目运算符 | + | 二进制加 |
算术运算符 | 双目运算符 | - | 二进制减 |
算术运算符 | 双目运算符 | * | 二进制乘 |
算术运算符 | 双目运算符 | / | 二进制除 |
算术运算符 | 双目运算符 | % | 求模 |
------------ | ---------- | ----------------- | ----------------- |
关系运算符 | 双目运算符 | > | 大于 |
关系运算符 | 双目运算符 | < | 小于 |
关系运算符 | 双目运算符 | >= | 大于等于 |
关系运算符 | 双目运算符 | <= | 小于等于 |
关系运算符 | 双目运算符 | == | 等于 |
关系运算符 | 双目运算符 | != | 不等于 |
关系运算符 | 双目运算符 | === | 全等于 |
关系运算符 | 双目运算符 | !== | 不全等于 |
------------ | ---------- | ----------------- | ----------------- |
位运算符 | 双目运算符 | ~ | 按位取反 |
位运算符 | 双目运算符 | & | 按位与 |
位运算符 | 双目运算符 | | | 按位或 |
位运算符 | 双目运算符 | ^ | 按位异或 |
位运算符 | 双目运算符 | ^~ 或 ~^ | 按位同或 |
------------ | ---------- | ----------------- | ----------------- |
缩位运算符 | 单目运算符 | & | 缩位与 |
缩位运算符 | 单目运算符 | ~& | 缩位与非 |
缩位运算符 | 单目运算符 | | | 缩位或 |
缩位运算符 | 单目运算符 | ~| | 缩位或非 |
缩位运算符 | 单目运算符 | ^ | 缩位异或 |
缩位运算符 | 单目运算符 | ^~ 或 ~^ | 缩位同或 |
------------ | ---------- | ----------------- | ----------------- |
逻辑运算符 | - | ! | 逻辑非 |
逻辑运算符 | - | && | 逻辑与 |
逻辑运算符 | - | || | 逻辑或 |
------------ | ---------- | ----------------- | ----------------- |
移位运算符 | 双目运算符 | >> | 右移 |
移位运算符 | 双目运算符 | << | 左移 |
------------ | ---------- | ----------------- | ----------------- |
位拼接运算符 | - | { , } { { } } | 将多个操作数拼接成一个操作数 |
------------ | ---------- | ----------------- | ----------------- |
条件运算符 | 三目运算符 | ?: | 如果真,则,否,则 |
wire A,B,SEL,L;//4个连线型变量
assign L = (A&~SEL)|(B&SEL);//连续赋值
module decoder_df(A1,A0,E,Y);
input A1,A0,E;
output [3:0]Y;
assign Y[0] = ~(~A1 & ~A0 & ~E);//000
assign Y[1] = ~(~A1 & A0 & ~E);//010
assign Y[2] = ~( A1 & ~A0 & ~E);//100
assign Y[3] = ~( A1 & A0 & ~E);//110
endmodule
module decoder_df_TB;
reg [1:0]a;
reg e;
wire [3:0]Y;
parameter DELAY=50; //设置延迟参数为50
decoder_df fun(.A1(a[1]),.A0(a[0]),.E(e),.Y(Y));
initial //使用initial过程快定义激励信号波形
begin //使用begin-end控制语句
e=1'b1; a[1] = 1'b0; a[0] = 1'b0;
#DELAY e=1'b0; a[1] = 1'b0; a[0] = 1'b0; //50ns
#DELAY e=1'b0; a[1] = 1'b0; a[0] = 1'b1; //100ns
#DELAY e=1'b0; a[1] = 1'b1; a[0] = 1'b0; //150ns
#DELAY e=1'b0; a[1] = 1'b1; a[0] = 1'b1; //200ns
#DELAY $stop; //200ns,执行$stop系统任务,停止仿真
end
initial $monitor($time,,,"/E=%b,A1=%b,A1=%b,Y",e,a[1],a[0],~Y);
//执行monitor系统任务,设置显示结果的格式
endmodule
module binary_adder(A,B,Cin,SUM,Cout);
input [3:0]A,B;
input Cin;
output [3:0]SUM;
output Cout;
assign {Cout,SUM} = A+B+Cin;
endmodule
数据流与门级建模对比
例如3,2选1数据选择器
使用连续赋值语句
module mux2x1_df(A,B,SEL,L);
input A,B,SEL;
output L;
assign L=SEL?A:B;
endmodule
module mux2x1_df_TB;
reg SEL,A,B;
wire L;
parameter DELAY=50; //设置延迟参数为50
mux2x1_df fun(.A(A),.B(B),.SEL(SEL),.L(L));
always #10 A=~A;
always #20 B=~B;
initial //使用initial过程快定义激励信号波形
begin
A=1;
B=1;
SEL = 1'b0;
#DELAY SEL = 1'b1; //50ns
#DELAY SEL = 1'b0; //100ns
#DELAY SEL = 1'b1; //150ns
#DELAY SEL = 1'b0; //200ns
#DELAY $stop; //200ns,执行$stop系统任务,停止仿真
end
initial $monitor($time,,,"SEL=%b,A=%b,B=%b,Y=%d",SEL,A,B,L);
endmodule
描述数字逻辑电路的功能和算法。
always是一个循环执行语句,后面跟着循环执行条件。
在always结构中,逻辑表达式就是一种过程赋值语句。
always @( 循环执行的条件 ) //不加分号“;”
//括号里的任何一个变量发生变化时,都会触发执行后面的过程赋值语句。
//执行完最后一句后,执行挂起,always语句再次等待变量发生变化。
//因此,循环执行条件被称为,“敏感变量”。
always @( 敏感变量 )
//敏感变量之间,使用关键词or,代替逻辑或运算“|”
always结构,过程赋值语句,只能给reg类型的变量赋值。
条件语句(if-else)
多路分支语句(case-endcase)
if(condition_expr) true_statement;
if(condition_expr) true_statement;
else fale_statement;
if(condition_expr1) true_statement1;
else if(condition_expr2)true_statement2;
else if(condition_expr3)true_statement3;
......
else default_statement;
case(case_expr)
item_expr1: statement1;
item_expr2: statement2;
......
default: default_statement;//可以省略
endcase
module mux2to1_bh(A,B,SEL,L);
input A,B,SEL;
output L;
reg L; //
always @(SEL or A or B) //敏感变量,任何一个变化,都会触发执行
if(SEL == 1)L=B; //if(SEL) L=B;
else L=A;
endmodule
module mux2to1_bh_TB;
reg SEL,A,B;
wire L;
parameter DELAY=50; //设置延迟参数为50
mux2to1_bh fun(.A(A),.B(B),.SEL(SEL),.L(L));
always #10 A=~A;
always #20 B=~B;
initial //使用initial过程快定义激励信号波形
begin
A=1;
B=1;
SEL = 1'b0;
#DELAY SEL = 1'b1; //50ns
#DELAY SEL = 1'b0; //100ns
#DELAY SEL = 1'b1; //150ns
#DELAY SEL = 1'b0; //200ns
#DELAY $stop; //200ns,执行$stop系统任务,停止仿真
end
initial $monitor($time,,,"SEL=%b,A=%b,B=%b,Y=%d",SEL,A,B,L);
endmodule
module mux4to1_bh(A,SEL,E,L);
input [3:0]A;
input [1:0]SEL;
input E;
output L;
reg L;
always @( A or SEL or E) //敏感变量,任何一个变化,都会触发执行
begin
if(E==1) L=0;
else
case(SEL)
2'd0: L=A[0];
2'd1: L=A[1];
2'd2: L=A[2];
2'd3: L=A[3];
endcase
end
endmodule
module mux4to1_bh_TB;
reg E;
reg [3:0]A;
reg [1:0]SEL;
wire L;
parameter DELAY=50; //设置延迟参数为50
mux4to1_bh fun(.A(A),.E(E),.SEL(SEL),.L(L));//(A,SEL,E,L);
always #2 A[3]=~A[3];
always #5 A[2]=~A[2];
always #10 A[1]=~A[1];
always #14 A[0]=~A[0];
initial //使用initial过程快定义激励信号波形
begin
A=0;
E =1 ;SEL = 2'b00;
#DELAY E =0 ;SEL = 2'b00; //50ns
#DELAY E =0 ;SEL = 2'b01; //100ns
#DELAY E =0 ;SEL = 2'b10; //150ns
#DELAY E =0 ;SEL = 2'b11; //200ns
#DELAY $stop; //200ns,执行$stop系统任务,停止仿真
end
endmodule