跳到主要内容

组合逻辑设计

组合逻辑电路的输出只取决于当前输入,不包含记忆元件。本章介绍如何使用 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 语句
  • 三态缓冲:高阻态和双向总线

掌握组合逻辑设计是数字电路设计的基础。下一章将介绍时序逻辑设计。