本篇内容来源于中国大学mooc《计算机组成与CPU设计实验》 (江苏大学)中的课程视频、PPT等相关资料。
本篇内容为《计算机组成与CPU设计实验》——三态门和多路器
参考视频:
计算机组成与CPU设计实验_江苏大学_中国大学MOOC(慕课) (icourse163.org)
组合逻辑Combinational Logic
Sequential Logic
assign A = B;
//等号左边的值始终跟随右边改变
例子:使用Verilog描述与非门
module nand(
input wire a, // wire可以省略
input wire b,
output wire c
);
assign c = ~(a&b); //等号左边的值始终跟随右边改变
endmodule
多个assign语句并行执行
例子:使用Verilog描述下面电路
module circuit(
input a,
input b,
output c,
output c
);
assign c = ~(a&b);
assign d = a^b ;
endmodule
举例:按位与
注意:逻辑运算符与位运算符的区别
逻辑运算符:
举例:逻辑与
三态门的输出端除了0和1两种状态外,还有第三种状态,称为高阻态(z)。在这种状态下,输出端相当于断开。也称三态缓冲器。
三态门使能端EN=1时,才有有效输出
module tribuffer(
input Din,
input En,
output Dout,
);
assign Dout = En ? Din:1'bz;//z(或者Z)为高阻态
endmodule
//? :为条件运算符
三态门的用途:输出到总线
普通逻辑门的输出不能连到一起,三态门通过使能端控制同一时刻只有一个输出
module mux2(
input A,
input B,
input S,
output Y
);
assign Y = S? B:A;
endmodule
module ADDER(
input [3:0] a,
input [3:0] b,
input CI,
output [3:0] S ,
output CO
);
//方法1:
wire[4:0] ADD;
assign ADD = a+b+CI;
assign S = ADD[3:0];
assign CO = ADD[4];
//方法2:直接使用拼接运算符
assign {CO,S[3:0]} = a+b+CI;
endmodule
将若干个信号的某些位拼接起来,如:
{CO, S[3:0]}
拼接的每个部分必须有确定的位宽完整域选择可以省略,如:
{CO,S} //{CO, S[3:0]},省略S的位宽
常数必须显式指定位宽,例:
{1'b0,S}
复制拼接
{3{a}}//等价于{a, a, a}
{2{a,b}}//等价于 {{a,b}, {a,b}}//等价于 {a,b,a,b}
过程块中的输出变量必须声明为reg,但并不意味着它是寄存器。
例子:使用always块描述下面电路
module circuit(
input wire a,
input wire b,
output reg c ,
output reg d
);
//always(敏感列表(Sensitivity list))
always(a or b)//或者always(*) 如果a或者b信号发生变化,输出的值c、d就会发生改变
begin
assign c = ~(a&b);
assign d = a^b;
end
endmodule
推荐使用SystemVerilog新的logic类型
为什么建议使用logic类型
reg容易被误解为“寄存器”,大部分场合logic类型可取代wire类型和reg类型
module circuit(
input wire a,
input wire b,
output logic c ,
output logic d
);
always(a or b)
begin
assign c = ~(a&b);
assign d = a^b;
end
endmodule
组合逻辑的敏感列表应包含所有输入
问题:如果敏感列表不完整,会出现什么问题?
例子:与非门
与非门的输入a或者b变化,输出c也跟着变化
如果敏感列表里面没有b。
下面代码的逻辑功能是,
所以当只有 b发生变化时不会影响输出。代码的逻辑功能和与非门的逻辑功能不一致。
module circuit(
input wire a,
input wire b,
output logic c ,
);
always(a)//敏感列表里面没有b
begin
assign c = ~(a&b);
end
endmodule
使用always(*)
module circuit(
input wire a,
input wire b,
output logic c
);
always(*)
begin
assign c = ~(a&b);
end
endmodule
强烈推荐always_comb (systemVerilog)
module circuit(
input wire a,
input wire b,
output logic c
);
always_comb
assign c = ~(a&b);
endmodule
例子:2选1多路选择器
module mux2(
input A,
input B,
input S,
output Y
);
// assign Y = S? B:A;
always_comb
if(S==1)
Y = B;
else
Y = A;
endmodule
可用于比较的运算符
例子:四选一多路选择器
module mux4(
input In0,In1,In2,In3,
input [1:0] Sel,
output Out
);
always_comb
case(Sel)
2'b00: Out = In0;
2'b01: Out = In1;
2'b10: Out = In2;
2'b11: Out = In3;
default:Out = 1'bx;
endcase
endmodule
//Verilog的逻辑值有高电平1、低电平0,高阻态z、不确定值x,四个逻辑值
//所以对于两位的Sel有2^4=16种逻辑值。
//对于其他不需要的逻辑值,需要使用default。否则会综合后的电路会出现latch,
//即,取到其他逻辑值,数据不发生变化来保存
使用if-else语句写4-1多路选择器
module mux4(
input In0,In1,In2,In3,
input [1:0] Sel,
output Out
);
always_comb
if(Sel==00)
Out = In0;
else if(Sel==01)
Out = In1;
else if(Sel==10)
Out = In2;
else if(Sel==11)
Out = In3;
else
Out = 1'bx;
endmodule
if-else和case生成的多路选择器的区别