FPGA基础——编码(独热码、格雷码、二进制码)
一、编码特点介绍
二进制码(Binary code):一种采用二进制格式连续编码的方法,其基本单位是二进制数(bit),由0和1组成。
独热码(One-hot code):每个状态由一个比特表示,且只有一个比特为1,其余位均为0。例如,6个状态的独热码可以表示为000001、000010、000100、001000、010000、100000。
格雷码(Gray Code):任意两个相邻状态之间只有一位二进制数不同。
(1)独热码(One-hot Code)
特点:
- 唯一性定义:每个状态仅有一位为1,其余位均为0(例如,3个状态对应编码
3'b001
、3'b010
、3'b100
)。 - 资源消耗:需要与状态数相等的触发器(n状态需n个触发器),但组合逻辑简化,仅需比较单个比特位即可判断状态。
- 性能优势:
- 速度与状态数量无关,仅取决于特定状态转移的路径复杂度。
- 减少毛刺:通过时序逻辑滤除组合逻辑输出中的瞬态干扰,适合总线信号对齐。
- 设计友好性:
- 易于综合、调试和静态时序分析。
- 无效状态多,需设计容错机制(如
default
分支强制跳转)。
适用场景:
- 大型状态机:FPGA寄存器资源丰富,独热码可显著提升速度和可靠性(如32+状态的系统)。
- 多选一逻辑:如仲裁器、优先级编码器,通过位掩码快速判断选择。
- 高时序要求场景:如流水灯控制、高速数据流调度(减少关键路径延迟)。
(2)格雷码(Gray Code)
特点:
- 单步跳变:相邻状态仅一位变化,降低多比特跳变导致的毛刺和功耗。
- 循环特性:首尾状态也仅相差一位,适合周期性计数。
- 抗干扰能力:减少异步场景下的亚稳态风险,提高跨时钟域数据传输的可靠性。
- 设计复杂度:
- 编码规则复杂,需通过递归或异或运算生成。
- 译码需额外逻辑(如逐位异或恢复二进制值)。
适用场景:
- 跨时钟域同步:如异步FIFO的读写指针编码,确保地址变化时仅一位翻转。
- 旋转编码器:物理位置检测中避免多位跳变导致的错误解码。
- 低功耗设计:减少状态切换时的动态功耗(如电池供电设备)。
- 通信纠错:QAM调制等场景中减少单比特错误的影响。
(3)二进制码(Binary Code)
特点:
- 资源效率:
- 寄存器占用 log2(n)。
- 组合逻辑复杂,易产生竞争冒险和长路径延迟。
- 可读性:直接映射数值,便于人工理解和调试(如状态
3'b011
对应十进制3)。 - 扩展性限制:状态数增加时,译码复杂度指数上升,速度显著下降。
适用场景:
- 小型状态机(状态数≤4):资源受限场景下兼顾效率和可读性。
- 数值计算电路:如二进制编码器、计数器,直接映射数学运算。
- CPLD设计:CPLD组合逻辑资源多,二进制码比独热码更高效。
(4)特性对比
特性 | 独热码 | 格雷码 | 二进制码 |
---|---|---|---|
资源占用 | 多寄存器,少组合逻辑 | 中等寄存器,中等组合逻辑 | 少寄存器,多组合逻辑 |
速度 | 快(与状态数无关) | 中等(依赖状态跳变复杂度) | 慢(随状态数增加下降) |
抗干扰能力 | 中(依赖时序约束) | 高(单比特跳变) | 低(多比特跳变) |
适用规模 | 大型状态机(>24状态) | 中等规模(4~24状态) | 小型状态机(≤4状态) |
典型应用 | 高速仲裁、多选一逻辑 | 异步FIFO、旋转编码器 | 基础计数器、数值编码器 |
设计建议:
- FPGA优先独热码:利用其寄存器资源优势,简化时序收敛。
- 异步场景必选格雷码:确保跨时钟域信号稳定性。
- 小型系统或CPLD用二进制码:节省资源且易于实现。
二、独热码占用较少的组合逻辑
相对于格雷码,使用独热码作为状态会使用更多的触发器,但会占用较少的组合电路,即独热码相比格雷码更节省组合逻辑。
比如说,表示4个状态,那么状态机寄存器采用格雷码编码只需要2bit:00(S0),01(S1),11(S2),10(S3);
采用独热码需要4bit:0001(S0),0010(S1),0100(S2),1000(S3)。所以很明显采用格雷码可以省2bit寄存器。
例一:
假如我们要在代码中判断状态机是否处于某状态S1,
对于格雷码的状态机来说,代码是这样的:assign S1 = (STATUS==2'b01);
对于独热码来说,代码是这样的就行:assign S1=STATUS[1];
所以独热码的译码非常简单。
例二:
考虑最简单的跳变,当A为1时,状态机会从S0跳到S1。
采用格雷码写:
STATUS[1:0] <= (STATUS==2'b00) & A ? 2'b01 : 2'b00;
采用独热码写:
STATUS[1] <= STATUS[0] & A;
总结一下:
独热码适合写条件复杂但是状态少的状态机;
格雷码适合写条件不复杂但是状态多的状态机。
三、格雷码、二进制码转换
(1)二进制码转格雷码
格雷码第n位 = 二进制码第(n+1)位+二进制码第n位。不必理会进制。
Verilog 代码:
gray=(binary>>1)^binary;
(2)格雷码转二进制码
二进制码第n位 = 二进制码第(n+1)位+格雷码第n位。因为二进制码和格雷码皆有相同位数,所以二进制码可从最高位的左边位元取0,以进行计算。
verilog 代码:
integer i;
for(i=0;i<=n-1;i=i+1)
binary[i]= ^(gray>>i) //gray移位后,自身按位异或