共计 1492 个字符,预计需要花费 4 分钟才能阅读完成。
16- 4 优先编码器入门指南:从原理到 FPGA 实现
从键盘扫描认识优先编码器
每次按下电脑键盘时,主板如何快速识别是哪个键被触发?这背后就用到了优先编码器(Priority Encoder)。想象一下:当同时按下 A 键和 Ctrl 键时,系统需要优先响应 Ctrl 组合键——这正是优先级判断的典型场景。
优先编码器与普通编码器的核心区别在于 输入冲突处理机制:
- 普通 8 - 3 编码器:当多个输入为 1 时输出不确定
- 16- 4 优先编码器:永远输出最高位有效的 1 的位置
真值表里的优先级秘密
来看一个简化版 4 - 2 优先编码器真值表(MSB 最高优先级):
| 输入 | 输出 |
|---|---|
| 0001 | 00 |
| 0010 | 01 |
| 0100 | 10 |
| 1000 | 11 |
| 1xxx | 11 |
当高位出现 1 时(如 1001),无论低位如何都会按照最高有效位编码。这个特性在中断控制器 (Interrupt Controller) 中尤为重要——系统需要优先处理级别更高的中断请求。
两种 Verilog 实现方案
方案 1:组合逻辑树
module priority_encoder_comb (input [15:0] din,
output reg [3:0] dout,
output reg valid
);
// 层级化优先级判断
always @(*) begin
casez (din)
16'b1???????????????: begin dout=4'b1111; valid=1; end
16'b01??????????????: begin dout=4'b1110; valid=1; end
16'b001?????????????: begin dout=4'b1101; valid=1; end
// ... 省略中间部分 ...
16'b0000000000000001: begin dout=4'b0000; valid=1; end
default: begin dout=4'b0000; valid=0; end
endcase
end
endmodule
方案 2:casex 行为描述
module priority_encoder_casex #(parameter WIDTH=16) (input [WIDTH-1:0] din,
output reg [$clog2(WIDTH)-1:0] dout
);
// 参数化位宽设计
always @(*) begin
dout = 0;
for (int i=WIDTH-1; i>=0; i--)
if (din[i]) begin
dout = i;
break; // 遇到第一个 1 立即终止
end
end
endmodule
性能对比实测
在 Xilinx Artix-7 FPGA 上综合后:
- 组合逻辑方案:
- 占用 56 个 LUT(查找表)
-
最大延迟 4.2ns(约 238MHz)
-
行为描述方案:
- 占用 49 个 LUT
- 最大延迟 3.8ns(约 263MHz)

新手避坑指南
- 锁存器陷阱:
- 组合逻辑中必须覆盖所有分支
-
推荐添加 default/default case
-
仿真调试技巧:
// 测试用例重点验证 initial begin din = 16'b0001000100010001; // 多个 1 同时有效 #10; if (dout !== 4'b1100) $error(" 优先级判断失败 "); end -
跨时钟域警告:
- 优先编码器输出建议同步打拍
- 使用
(* ASYNC_REG = "TRUE" *)标记同步寄存器
进阶思考
如果想让优先级可以运行时配置(比如通过寄存器动态修改权重),该如何改造现有设计?这里给出两个思路方向:
- 增加优先级映射表
- 采用可排序网络结构
下次我们可以深入探讨动态优先级调度的实现方案。在实际项目中,这种灵活设计在 QoS(服务质量)调度系统中非常有用。
小实验建议:尝试在 Vivado 里修改代码后观察综合出来的电路结构图,理解 RTL 到实际硬件的映射过程。
正文完
发表至: 未分类
近两天内
