共计 2333 个字符,预计需要花费 6 分钟才能阅读完成。
背景介绍
在数字电路设计中,编码器(Encoder)是一种基础但非常重要的组合逻辑电路。它的作用是将多个输入信号转换为特定编码形式的输出。比如 8 - 3 编码器,就是将有 8 个输入(通常只有 1 个是高电平)转换为 3 位二进制编码输出。

当我们需要处理更多输入信号时,比如 16 个输入,就需要更高阶的编码器。但现成的 16- 4 编码器可能不易获得或面积较大,这时候级联多个低阶编码器就是一个实用且经济的解决方案。
技术原理
8- 3 编码器真值表分析
先来看一个标准的 8 - 3 编码器的真值表(这里只列出有效输入情况):
| 输入 | 输出 |
|---|---|
| 00000001 | 000 |
| 00000010 | 001 |
| 00000100 | 010 |
| 00001000 | 011 |
| 00010000 | 100 |
| 00100000 | 101 |
| 01000000 | 110 |
| 10000000 | 111 |
注意:LSB(Least Significant Bit,最低有效位)是输出最右边的那位。
级联原理
要把两个 8 - 3 编码器级联成 16- 4 编码器,核心思路是:
- 将 16 个输入分成两组,每组 8 个,分别接两个 8 - 3 编码器
- 判断哪组有有效输入(通过编码器的使能输出信号)
- 组合两个编码器的输出,并增加一位作为最高位(MSB)表示来自哪一组
这样,4 位输出的构成就是:
– 最高位(bit3):1 表示来自第二组,0 表示第一组
– 低 3 位(bit2-bit0):来自对应组的编码器输出
Verilog 实现
下面是用 Verilog 实现这个设计的完整代码:
module encoder_8to3 (input [7:0] in,
output reg [2:0] out,
output reg valid
);
always @(*) begin
casez(in)
8'b00000001: begin out = 3'b000; valid = 1'b1; end
8'b00000010: begin out = 3'b001; valid = 1'b1; end
8'b00000100: begin out = 3'b010; valid = 1'b1; end
8'b00001000: begin out = 3'b011; valid = 1'b1; end
8'b00010000: begin out = 3'b100; valid = 1'b1; end
8'b00100000: begin out = 3'b101; valid = 1'b1; end
8'b01000000: begin out = 3'b110; valid = 1'b1; end
8'b10000000: begin out = 3'b111; valid = 1'b1; end
default: begin out = 3'b000; valid = 1'b0; end
endcase
end
endmodule
module encoder_16to4 (input [15:0] in,
output reg [3:0] out
);
wire [2:0] out1, out2;
wire valid1, valid2;
encoder_8to3 enc1 (.in(in[7:0]), .out(out1), .valid(valid1));
encoder_8to3 enc2 (.in(in[15:8]), .out(out2), .valid(valid2));
always @(*) begin
if (valid2) begin
out = {1'b1, out2}; // 来自高 8 位
end else begin
out = {1'b0, out1}; // 来自低 8 位
end
end
endmodule
代码说明
encoder_8to3模块实现了基本的 8 - 3 编码器,除了输出编码还输出一个 valid 信号表示是否有有效输入encoder_16to4模块实例化两个 8 - 3 编码器,分别处理输入的低 8 位和高 8 位- 通过检查 valid 信号决定最终输出的最高位
关键问题
级联延迟
级联设计会增加组合逻辑的深度,导致更大的传播延迟。在我们的设计中:
- 第一级延迟:8- 3 编码器的内部延迟
- 第二级延迟:选择逻辑的延迟
这可能会限制整个系统能达到的最高时钟频率。
输入冲突
如果两个 8 - 3 编码器同时有有效输入(虽然按照编码器规范不应该发生),我们的设计会优先选择高 8 位的输入。这在实际应用中可能需要根据具体需求调整优先级。
优化建议
流水线设计
为改善时序性能,可以在两级编码器之间插入流水线寄存器:
// 在 encoder_16to4 模块中加入寄存器
reg [2:0] out1_reg, out2_reg;
reg valid1_reg, valid2_reg;
always @(posedge clk) begin
out1_reg <= out1;
out2_reg <= out2;
valid1_reg <= valid1;
valid2_reg <= valid2;
end
这样虽然会增加一个时钟周期的延迟,但可以显著提高系统时钟频率。
面积优化
如果面积是关键考量,可以考虑以下优化:
- 共享部分解码逻辑
- 使用更紧凑的编码方式
- 在 FPGA 实现时,利用 LUT 资源的特性
实践建议
-
仿真验证 :使用 Modelsim 或 Vivado 自带的仿真工具验证设计
Testbench 编写要点:
initial begin // 测试低 8 位有效 in = 16'b00000000_00000100; #10; // 测试高 8 位有效 in = 16'b00000100_00000000; #10; // 测试无有效输入 in = 16'b00000000_00000000; #10; $finish; end -
综合实现 :推荐使用 Xilinx Vivado 进行综合和实现,查看时序报告和资源利用率
-
板级验证 :在 FPGA 开发板上用 LED 或逻辑分析仪验证实际功能
思考题
- 如果我们需要实现一个 32- 5 编码器,应该如何扩展这个设计?需要多少个 8 - 3 编码器?
- 在级联设计中,如果要求低 8 位优先而不是高 8 位优先,应该如何修改代码?
- 流水线设计会增加延迟,在哪些应用场景下这种延迟是不可接受的?
