【HDLbits--Comb组合逻辑】
HDLbits--Comb组合逻辑
- 1.5 组合逻辑
- 1.5 Demo
在 Verilog 中,组合逻辑(Combinational Logic)是指输出仅依赖于当前输入的逻辑电路,没有记忆功能(即没有状态存储)。组合逻辑的特点是:
- 无时钟信号:不依赖于时钟边沿触发。
- 即时响应:输入变化时,输出立即更新(在仿真中表现为零延迟,实际硬件中有传播延迟)。
1.5 组合逻辑
组合逻辑的实现方式
在 Verilog 中,组合逻辑通常通过以下方式实现:
- assign 语句
用于简单的组合逻辑表达式。
语法:
assign output_signal = expression;
示例:
wire a, b, c;
assign c = a & b; // c 是 a 和 b 的按位与
- always 块
用于描述更复杂的组合逻辑。
必须使用 always @(*) 或 always @(sensitivity_list) 来触发。
注意:在 always 块中赋值的信号必须声明为 reg 类型。
示例:
reg c;
always @(*) begin
c = a & b; // c 是 a 和 b 的按位与
end
- 条件运算符(三元运算符)
用于简单的条件逻辑。
语法:
assign output_signal = condition ? value_if_true : value_if_false;
示例:
wire a, b, sel, c;
assign c = sel ? a : b; // 如果 sel 为 1,c = a;否则 c = b
- case 语句
用于多路选择逻辑。
必须在 always 块中使用。
示例:
reg [1:0] sel;
reg [3:0] out;
always @(*) begin
case (sel)
2'b00: out = 4'b0001;
2'b01: out = 4'b0010;
2'b10: out = 4'b0100;
2'b11: out = 4'b1000;
default: out = 4'b0000;
endcase
end
- if-else 语句
用于条件逻辑。
必须在 always 块中使用。
示例:
reg a, b, sel, c;
always @(*) begin
if (sel)
c = a;
else
c = b;
end
组合逻辑的设计规则
避免锁存器(Latch):
在 always 块中,必须为所有可能的输入条件明确赋值,否则会推断出锁存器。
示例:
always @(*) begin
if (sel)
c = a;
// 缺少 else 分支,会推断出锁存器
end
敏感列表:
在 always 块中,敏感列表必须包含所有影响输出的信号。
使用 always @(*) 可以自动推断敏感列表,避免遗漏。
避免组合逻辑环路:
组合逻辑的输出不能直接或间接反馈到输入,否则会导致环路。
示例:
assign a = a + 1; // 组合逻辑环路,非法
组合逻辑的示例
以下是一个 4:1 多路选择器的 Verilog 实现:
module mux4to1 (
input [3:0] data, // 4 位输入
input [1:0] sel, // 2 位选择信号
output reg out // 输出
);
always @(*) begin
case (sel)
2'b00: out = data[0];
2'b01: out = data[1];
2'b10: out = data[2];
2'b11: out = data[3];
default: out = 1'b0; // 避免锁存器
endcase
end
endmodule
总结
- 组合逻辑的输出仅依赖于当前输入,没有记忆功能。
- 可以通过 assign 语句、always 块、条件运算符、case 语句和 if-else 语句实现。
- 设计时需避免锁存器和组合逻辑环路。
- 组合逻辑是数字电路设计的基础,广泛应用于多路选择器、加法器、译码器等电路中。
1.5 Demo
组合逻辑电路:主要是包括条件组合、算数运算,卡诺真值表运算;
题目:计算模式
module top_module (
input too_cold,
input too_hot,
input mode,
input fan_on,
output heater,
output aircon,
output fan
);
assign heater = (mode == 1'b1) && (too_cold==1'b1);
assign aircon = (mode == 1'b0) && (too_hot==1'b1);
assign fan = (heater || aircon) || (fan_on);
endmodule
题目:计算输入向量中的1数量;
module top_module(
input [2:0] in,
output [1:0] out );
always @(*) begin
case(in[2:0])
3'b001,3'b010,3'b100: out[1:0] = 1;
3'b011,3'b101,3'b110: out[1:0] = 2;
3'b111: out[1:0] = 3;
default: out[1:0] = 0;
endcase
end
endmodule
题目:计算向量中的index和他相邻位置的关系
module top_module(
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );
assign out_both[2:0] = {{in[3] & in[2]},{in[2] & in[1]}, {in[1] & in[0]}};
assign out_any[3:1] = {{in[3] | in[2]}, {in[2] | in[1]}, {in[1] | in[0]}};
assign out_different[3:0] = {{in[3] ^ in[0]}, {in[3] ^ in[2]}, {in[2] ^ in[1]}, {in[1] ^ in[0]}};
endmodule
题目:全加器–多位全加器例化低全加器
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
fadd u0_fadd(a[0],b[0],cin,cout[0],sum[0]);
fadd u1_fadd(a[1],b[1],cout[0],cout[1],sum[1]);
fadd u2_fadd(a[2],b[2],cout[1],cout[2],sum[2]);
endmodule
module fadd(
input a, b, cin,
output cout, sum );
assign cout = a&b|a&cin|b&cin;
assign sum = a^b^cin;
endmodule
//==变式
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum);
wire [2:0] cout;
wire cin;
assign cin = 1'b0;
fadd fadd0 (x[0],y[0],cin,cout[0],sum[0]);
fadd fadd1 (x[1],y[1],cout[0],cout[1],sum[1]);
fadd fadd2 (x[2],y[2],cout[1],cout[2],sum[2]);
fadd fadd3 (x[3],y[3],cout[2],sum[4],sum[3]);
endmodule
module fadd(
input a, b, cin,
output cout, sum );
assign cout = a&b|a&cin|b&cin;
assign sum = a^b^cin;
endmodule