组合逻辑设计
组合逻辑电路的输出只取决于当前输入,不包含记忆元件。本章介绍如何使用 Verilog 描述组合逻辑电路。
连续赋值
连续赋值(continuous assignment)是描述组合逻辑最基本的方式。
assign 语句
使用 assign 语句描述组合逻辑:
wire [7:0] a, b;
wire [7:0] sum;
assign sum = a + b;
assign 语句的特点:
- 左侧必须是 wire 类型
- 右侧可以是任意表达式
- 只要右侧操作数变化,立即重新计算
多个 assign 语句
多个 assign 语句是并行执行的:
wire [7:0] a, b;
wire [7:0] sum, diff, product;
assign sum = a + b;
assign diff = a - b;
assign product = a * b;
条件赋值
使用条件运算符实现条件赋值:
wire [7:0] a, b;
wire sel;
wire [7:0] result;
assign result = sel ? a : b;
复杂表达式
wire [7:0] a, b, c;
wire [7:0] result;
assign result = (a & b) | c;
基本门电路
与门
module and_gate(
input a,
input b,
output y
);
assign y = a & b;
endmodule
或门
module or_gate(
input a,
input b,
output y
);
assign y = a | b;
endmodule
非门
module not_gate(
input a,
output y
);
assign y = ~a;
endmodule
异或门
module xor_gate(
input a,
input b,
output y
);
assign y = a ^ b;
endmodule
多输入门
module and4(
input [3:0] a,
output y
);
assign y = &a; // 归约与
endmodule
多路选择器
2 选 1 多路选择器
module mux2(
input [7:0] in0,
input [7:0] in1,
input sel,
output [7:0] out
);
assign out = sel ? in1 : in0;
endmodule
4 选 1 多路选择器
module mux4(
input [7:0] in0,
input [7:0] in1,
input [7:0] in2,
input [7:0] in3,
input [1:0] sel,
output [7:0] out
);
assign out = (sel == 2'b00) ? in0 :
(sel == 2'b01) ? in1 :
(sel == 2'b10) ? in2 : in3;
endmodule
使用 case 语句的多路选择器
module mux4_case(
input [7:0] in0,
input [7:0] in1,
input [7:0] in2,
input [7:0] in3,
input [1:0] sel,
output reg [7:0] out
);
always @(*) begin
case (sel)
2'b00: out = in0;
2'b01: out = in1;
2'b10: out = in2;
2'b11: out = in3;
endcase
end
endmodule
译码器
2-4 译码器
module decoder2_4(
input [1:0] in,
output [3:0] out
);
assign out = (in == 2'b00) ? 4'b0001 :
(in == 2'b01) ? 4'b0010 :
(in == 2'b10) ? 4'b0100 : 4'b1000;
endmodule
使用 case 语句
module decoder2_4_case(
input [1:0] in,
output reg [3:0] out
);
always @(*) begin
case (in)
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
endmodule
3-8 译码器
module decoder3_8(
input [2:0] in,
input en,
output [7:0] out
);
assign out = en ? (1 << in) : 8'b0;
endmodule
编码器
4-2 编码器
module encoder4_2(
input [3:0] in,
output [1:0] out
);
assign out = (in == 4'b0001) ? 2'b00 :
(in == 4'b0010) ? 2'b01 :
(in == 4'b0100) ? 2'b10 : 2'b11;
endmodule
优先编码器
module priority_encoder4_2(
input [3:0] in,
output reg [1:0] out,
output valid
);
assign valid = |in;
always @(*) begin
casez (in)
4'b1???: out = 2'b11;
4'b01??: out = 2'b10;
4'b001?: out = 2'b01;
4'b0001: out = 2'b00;
default: out = 2'b00;
endcase
end
endmodule
比较器
相等比较器
module comparator_eq(
input [7:0] a,
input [7:0] b,
output eq
);
assign eq = (a == b);
endmodule
大小比较器
module comparator(
input [7:0] a,
input [7:0] b,
output gt,
output lt,
output eq
);
assign gt = (a > b);
assign lt = (a < b);
assign eq = (a == b);
endmodule
加法器
半加器
module half_adder(
input a,
input b,
output sum,
output cout
);
assign sum = a ^ b;
assign cout = a & b;
endmodule
全加器
module full_adder(
input a,
input b,
input cin,
output sum,
output cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (b & cin) | (a & cin);
endmodule
行波进位加法器
module ripple_carry_adder(
input [7:0] a,
input [7:0] b,
input cin,
output [7:0] sum,
output cout
);
wire [7:0] carry;
assign carry[0] = cin;
genvar i;
generate
for (i = 0; i < 8; i = i + 1) begin : adder_stage
full_adder fa(
.a(a[i]),
.b(b[i]),
.cin(carry[i]),
.sum(sum[i]),
.cout(carry[i+1])
);
end
endgenerate
assign cout = carry[8];
endmodule
超前进位加法器
module carry_lookahead_adder(
input [3:0] a,
input [3:0] b,
input cin,
output [3:0] sum,
output cout
);
wire [3:0] g, p;
wire [4:0] c;
assign g = a & b;
assign p = a | b;
assign c[0] = cin;
assign c[1] = g[0] | (p[0] & c[0]);
assign c[2] = g[1] | (p[1] & (g[0] | (p[0] & c[0])));
assign c[3] = g[2] | (p[2] & (g[1] | (p[1] & (g[0] | (p[0] & c[0])))));
assign c[4] = g[3] | (p[3] & c[3]);
assign sum = a ^ b ^ c[3:0];
assign cout = c[4];
endmodule
减法器
半减器
module half_subtractor(
input a,
input b,
output diff,
output borrow
);
assign diff = a ^ b;
assign borrow = ~a & b;
endmodule
全减器
module full_subtractor(
input a,
input b,
input bin,
output diff,
output bout
);
assign diff = a ^ b ^ bin;
assign bout = (~a & b) | (~(a ^ b) & bin);
endmodule
乘法器
组合乘法器
module multiplier(
input [7:0] a,
input [7:0] b,
output [15:0] product
);
assign product = a * b;
endmodule
移位加法乘法器
module shift_add_multiplier(
input [7:0] a,
input [7:0] b,
output [15:0] product
);
wire [15:0] partial [7:0];
genvar i;
generate
for (i = 0; i < 8; i = i + 1) begin : partial_product
assign partial[i] = b[i] ? (a << i) : 16'b0;
end
endgenerate
assign product = partial[0] + partial[1] + partial[2] + partial[3] +
partial[4] + partial[5] + partial[6] + partial[7];
endmodule
always 块组合逻辑
基本语法
使用 always @(*) 描述组合逻辑:
always @(*) begin
// 组合逻辑
end
完整敏感列表
确保敏感列表包含所有右侧信号:
// 正确:使用 @(*) 自动推断
always @(*) begin
if (sel)
out = a;
else
out = b;
end
// 不推荐:手动列出敏感信号
always @(a or b or sel) begin
if (sel)
out = a;
else
out = b;
end
阻塞赋值
组合逻辑使用阻塞赋值(=):
always @(*) begin
temp = a & b;
out = temp | c;
end
条件语句
if-else 语句
module mux_if(
input [7:0] in0,
input [7:0] in1,
input sel,
output reg [7:0] out
);
always @(*) begin
if (sel)
out = in1;
else
out = in0;
end
endmodule
if-else if-else 语句
module priority_arbiter(
input [3:0] request,
output reg [3:0] grant
);
always @(*) begin
if (request[3])
grant = 4'b1000;
else if (request[2])
grant = 4'b0100;
else if (request[1])
grant = 4'b0010;
else if (request[0])
grant = 4'b0001;
else
grant = 4'b0000;
end
endmodule
避免锁存器
不完整的赋值会产生锁存器:
// 错误:产生锁存器
always @(*) begin
if (sel)
out = a;
// 缺少 else 分支
end
// 正确:避免锁存器
always @(*) begin
if (sel)
out = a;
else
out = out; // 或使用默认值
end
// 更好的做法:使用默认值
always @(*) begin
out = 8'b0; // 默认值
if (sel)
out = a;
end
case 语句
基本 case 语句
module alu(
input [7:0] a,
input [7:0] b,
input [1:0] op,
output reg [7:0] result
);
always @(*) begin
case (op)
2'b00: result = a + b;
2'b01: result = a - b;
2'b10: result = a & b;
2'b11: result = a | b;
endcase
end
endmodule
casez 和 casex
// casez:忽略 z 位(? 表示任意值)
always @(*) begin
casez (sel)
4'b1???: out = in3;
4'b01??: out = in2;
4'b001?: out = in1;
4'b0001: out = in0;
default: out = 8'b0;
endcase
end
// casex:忽略 x 和 z 位
always @(*) begin
casex (sel)
4'b1xxx: out = in3;
4'b01xx: out = in2;
4'b001x: out = in1;
4'b0001: out = in0;
default: out = 8'b0;
endcase
end
避免锁存器
case 语句必须有 default 分支:
// 错误:可能产生锁存器
always @(*) begin
case (op)
2'b00: result = a + b;
2'b01: result = a - b;
endcase
end
// 正确:包含 default
always @(*) begin
case (op)
2'b00: result = a + b;
2'b01: result = a - b;
default: result = 8'b0;
endcase
end
三态缓冲
单向三态缓冲
module tri_state_buffer(
input [7:0] data_in,
input enable,
output [7:0] data_out
);
assign data_out = enable ? data_in : 8'bz;
endmodule
双向总线
module bidirectional_bus(
inout [7:0] bus,
input [7:0] data_out,
input output_enable,
output [7:0] data_in
);
assign bus = output_enable ? data_out : 8'bz;
assign data_in = bus;
endmodule
设计实例
ALU 设计
module alu(
input [31:0] a,
input [31:0] b,
input [3:0] op,
output [31:0] result,
output zero,
output carry,
output overflow
);
wire [32:0] sum;
assign sum = a + b;
always @(*) begin
case (op)
4'b0000: result = a & b;
4'b0001: result = a | b;
4'b0010: result = a ^ b;
4'b0011: result = ~a;
4'b0100: result = a + b;
4'b0110: result = a - b;
4'b0111: result = a < b ? 32'b1 : 32'b0;
4'b1000: result = a << b[4:0];
4'b1001: result = a >> b[4:0];
4'b1010: result = a >>> b[4:0];
default: result = 32'b0;
endcase
end
assign zero = (result == 32'b0);
assign carry = sum[32];
assign overflow = (a[31] == b[31]) && (result[31] != a[31]);
endmodule
7 段数码管译码器
module seven_segment(
input [3:0] digit,
output reg [6:0] segments
);
always @(*) begin
case (digit)
4'b0000: segments = 7'b1111110; // 0
4'b0001: segments = 7'b0110000; // 1
4'b0010: segments = 7'b1101101; // 2
4'b0011: segments = 7'b1111001; // 3
4'b0100: segments = 7'b0110011; // 4
4'b0101: segments = 7'b1011011; // 5
4'b0110: segments = 7'b1011111; // 6
4'b0111: segments = 7'b1110000; // 7
4'b1000: segments = 7'b1111111; // 8
4'b1001: segments = 7'b1111011; // 9
4'b1010: segments = 7'b1110111; // A
4'b1011: segments = 7'b0011111; // B
4'b1100: segments = 7'b1001110; // C
4'b1101: segments = 7'b0111101; // D
4'b1110: segments = 7'b1001111; // E
4'b1111: segments = 7'b1000111; // F
default: segments = 7'b0000000;
endcase
end
endmodule
小结
本章介绍了 Verilog 组合逻辑设计:
- 连续赋值:assign 语句描述组合逻辑
- 基本门电路:与门、或门、非门、异或门
- 多路选择器:条件运算符和 case 语句
- 译码器和编码器:二进制译码和编码
- 比较器:相等和大小比较
- 加法器和减法器:算术运算电路
- always 块组合逻辑:使用阻塞赋值
- 条件语句:if-else 和 case 语句
- 三态缓冲:高阻态和双向总线
掌握组合逻辑设计是数字电路设计的基础。下一章将介绍时序逻辑设计。