共计 2069 个字符,预计需要花费 6 分钟才能阅读完成。
优先编码器是什么?
优先编码器(Priority Encoder)是数字系统中常用的组合逻辑电路,它能将多个输入信号中优先级最高的那个转换成二进制编码。举个生活中的例子:就像医院急诊科会根据病人病情的轻重缓急来决定谁先就诊一样,优先编码器也会根据输入信号的优先级来决定输出哪个编码。

在 FPGA 开发中,优先编码器常用于中断请求处理、键盘扫描电路等场景。比如当多个外设同时发出中断请求时,83 优先编码器可以快速识别出优先级最高的那个中断源。
为什么选择 83 优先编码器?
83 优先编码器是指将 8 个输入编码成 3 位二进制输出的优先编码器。相比其他编码方案,它具有以下特点:
- 与 16- 4 编码器相比,83 编码器输入端口更少,适合中小规模应用
- 输出位数与输入数量成对数关系,硬件开销更优
- 优先级明确,最高位输入(din[7])具有最高优先级
真值表对比
| 输入(din) | 常规编码器输出 | 优先编码器输出 |
|---|---|---|
| 00000001 | 000 | 000 |
| 00000010 | 001 | 001 |
| 00000100 | 010 | 010 |
| … | … | … |
| 10000000 | 111 | 111 |
| 00010001 | 001 (错误) | 100 (正确) |
可以看到,当多个输入同时有效时,优先编码器会输出优先级最高的那个,而常规编码器会产生错误输出。
Verilog 实现详解
行为级描述代码
module pri_encoder_8_3 (input [7:0] din, // 8 位输入信号
output [2:0] dout, // 3 位编码输出
output valid // 有效标志位
);
always_comb begin
casez (din) // casez 支持 z 和? 通配符
8'b1???????: begin dout = 3'b111; valid = 1'b1; end
8'b01??????: begin dout = 3'b110; valid = 1'b1; end
8'b001?????: begin dout = 3'b101; valid = 1'b1; end
8'b0001????: begin dout = 3'b100; valid = 1'b1; end
8'b00001???: begin dout = 3'b011; valid = 1'b1; end
8'b000001??: begin dout = 3'b010; valid = 1'b1; end
8'b0000001?: begin dout = 3'b001; valid = 1'b1; end
8'b00000001: begin dout = 3'b000; valid = 1'b1; end
default: begin dout = 3'b000; valid = 1'b0; end // 无有效输入
endcase
end
endmodule
关键设计技巧
- casez 语句 :使用
casez配合?通配符,可以简洁地描述优先级逻辑 - valid 信号:增加有效标志位,明确区分 ” 全零输入 ” 和 ” 最低优先级有效 ” 两种情况
- 完备性处理:default 分支确保所有未列出的输入组合都有确定输出
时序特性(文字描述)
- 当 din[7]从 0 变为 1 时,dout 会在一个组合逻辑延迟后变为 3 ’b111
- valid 信号与 dout 同时变化,没有额外延迟
- 如果多个输入同时变化,输出将稳定在最高优先级对应的编码
测试验证方法
Testbench 示例
`timescale 1ns/1ps
module tb_pri_encoder();
reg [7:0] din;
wire [2:0] dout;
wire valid;
pri_encoder_8_3 uut (.*);
initial begin
// 测试单 bit 有效
din = 8'b00000001; #10;
din = 8'b00000010; #10;
...
// 测试多 bit 同时有效
din = 8'b00010001; #10; // 应输出 100
din = 8'b00100100; #10; // 应输出 101
// 测试无效输入
din = 8'b00000000; #10;
$finish;
end
endmodule
仿真波形解读
- t=0ns 时,din=00000001 → dout=000, valid=1
- t=10ns 时,din=00000010 → dout=001, valid=1
- t=20ns 时,din=00010001 → dout=100, valid=1 (而不是 000)
- t=30ns 时,din=00000000 → dout=000, valid=0
实战避坑指南
常见问题与解决方案
- 未处理输入状态:
- 问题:忘记处理全零输入情况
-
解决:添加 valid 信号明确状态
-
组合逻辑毛刺:
- 问题:输入变化时输出可能出现短暂毛刺
-
解决:在关键路径后插入寄存器
-
优化权衡:
- 面积优化:共用部分解码逻辑
- 速度优化:采用并行前缀结构
最佳实践建议
- 所有信号明确位宽,避免隐含截断
- 组合逻辑避免使用 for 循环
- 关键路径添加时序约束
总结与思考
通过这个 83 优先编码器的实现,我们掌握了:
1. 优先编码器的设计原理
2. Verilog 行为级描述方法
3. 完备性验证的重要性
留给读者的思考题:
1. 如何修改代码使其支持参数化位宽(如 16- 4 编码)?
2. 在异步复位系统中,需要特别注意哪些时序约束?
希望这篇笔记能帮助 FPGA 新手少走弯路。如果有任何问题,欢迎在评论区交流讨论!
正文完
发表至: 未分类
近一天内
