初次查看一个减法电路的 RTL 时,有些许看不懂的地方,简单分析了一下,做个记录。
由于减法电路是通过转换为加法电路实现的,所以还需要先贴出快速进位链的图。
其中,
- CI 是上一个 CARRY4 的进位输出,位宽为 1;
- CYINT 是进位的初始化值,位宽为 1;
- DI 是数据的输入(两个加数的任意一个),位宽为 4;
- SI 是两个加数的异或,位宽为 4;
- O 是加法结果输出,位宽为 4;
- CO 是进位输出,位宽为 4;(为什么进位输出是 4bit?后面有解释)
一、减法电路及推导
减法电路示意:
reg [15:0] fpga_chx_clk_locked_code_temp; assign emc_chx_clk_status = fpga_chx_clk_locked_code_temp; always@(posedge fpga_chx_clk) fpga_chx_clk_locked_code_temp <= emc_chx_divider_cnt - 'd3;
将减法转换成加法——加减数的补码:
emc_chx_divider_cnt – ‘d3 = emc_chx_divider_cnt + 16’hfffd
假设
DI = emc_cnt[15:0]
S = emc_cnt[15:0] ^ 16’hfffd
那么,第一个 carry4 的 DI 和 S 分别为:
DI = emc_cnt[3:0]
S = emc_cnt[3:0] ^ 4’b1101
S[0] = emc_cnt[0] ^ 1’b1 = ~emc_cnt[0];
S[1] = emc_cnt[1] ^ 1’b0 = emc_cnt[1];
S[2] = emc_cnt[2] ^ 1’b1 = ~emc_cnt[2];
S[3] = emc_cnt[3] ^ 1’b1 = ~emc_cnt[3];
进一步可以计算出输出 O 和进位 CO 的结果:
O[0] = S[0] ^ (CYINIT & CIN) = ~emc_cnt[0]
CO[0] = S[0] ? (CYINIT & CIN) : DI[0] = ~emc_cnt[0] ? 1’b0 : emc_cnt[0] = emc_cnt[0]
O[1] = S[1] ^ CO0 = emc_cnt[1] ^ emc_cnt[0]
CO[1] = S[1] ? CO0 : DI[1] = emc_cnt[1] ? emc_cnt[0] : emc_cnt[1] = emc_cnt[1] & emc_cnt[0]
其实,等同于 CO[1] = S[1] ? CO0 : 1’b0 = emc_cnt[1] ? emc_cnt[0] : 1’b0 = emc_cnt[1] & emc_cnt[0]
O[2] = S[2] ^ CO1 = ~emc_cnt[2] ^ (emc_cnt[1] & emc_cnt[0])
CO[2] = S[2] ? CO1 : DI[2] = ~emc_cnt[2] ? emc_cnt[1] & emc_cnt[0] : emc_cnt[2] = emc_cnt[2] ? emc_cnt[2] : emc_cnt[1] & emc_cnt[0]
O[3] = S[3] ^ CO2 = ~emc_cnt[3] ^ (emc_cnt[2] ? 1’b1 : emc_cnt[1] & emc_cnt[0])
CO[3] = S[3] ? CO2 : DI[3]
二、RTL 原理图验证
结合 RTL 视图,整理各个 CARRY4 的加数与被加数:
CARRY4 | CARRY4 x2 | CARRY4 | |||||||
[3] | [2] | [1] | [0] | [3…0] | [3] | [2] | [1] | [0] | |
DI | 1’b0 | 1’b0 | emc_cnt[4] | emc_cnt[3] | emc_cnt[12…5] | emc_cnt[4] | emc_cnt[3] | emc_cnt[2] | 1’b0 |
S | 1’b0 | ~emc_cnt[15] | ~emc_cnt[14] | ~emc_cnt[13] | ~emc_cnt[12…5] | ~emc_cnt[4] | ~emc_cnt[3] | ~emc_cnt[2] | emc_cnt[1] |
发现几个特点,下面是给出的解释:
1)emc_cnt[0]并未接入加法器,何解?
bit0 的输出 O[0]等于 S[0](Cin = 1’b0),所以 bit0 就直接经过 LUT1 至输出;但 bit0 的进位输出 CO[0](也就是 emc_cnt[0])接入了下一级的 CYINIT;
2)emc_cnt[1]应该接 DI,但后者却接了 1’b0,何解?
最低位 DI 接不接 emc_cnt[1]均不影响结果。emc_cnt[1] ? emc_cnt[0] : emc_cnt[1]等同于 emc_cnt[1] ? emc_cnt[0] : 1’b0
0 0 0
0 1 0
1 0 0
1 1 1
3)最高位,DI 未接 emc_cnt[15],何解?
因为不再需要向上一级进位,故不用接。
三、参考文章
1)CARRY4(超前进位加法器)具体超前在哪里?
超前进位加法器是相对于行波进位加法器而言的,这里可以参考“《Verilog 高级数字系统设计技术与实例分析》”。
2)CARRY4 中 CI 与 CYINIT 的含义?
What is CYINIT and it’s difference with CI in CARRY4 block?
CI is strictly used for cascading inputs from another CARRY output when we have carry chains.
CYINIT is used for the rest of the cases including the first/upper CARRY input in the chain. Usually it is the initial CARRY bit or first bit in the CARRY chain. I assume that the first block (lsb) can be a half adder but for uniformity of logic, a full adder is used with this CYINIT as 0. Also, if you want to initialize a CARRY input to be a static 0 or 1 you would use CYINIT.
3)进位链参考文章:
- Xilinx 系列 FPGA 进位链延时实现简介
- 影响 FPGA 时序的进位链(Carry Chain),你用对了么?
- Verilog 加法器和减法器(2) – 迈克老狼 2012 – 博客园 (cnblogs.com)
扩展:比较电路的 RTL
比较电路通常是采用 LUT 配合 CARRY4 实现。
1)直接比较
A==B
作为寄存器清零的信号。
LUT 用于比较每一位的数值,例如 LUT6 可以比较 3 个 bit 位,将输出结果从低到高接入 CARRY4,且可以级联。通过设定初始值 CYINIT == 1’b1,判断是否产生进位。如果产生了进位,则说明 LUT 的比较值相等;否则不相等。
2)A == B >>1
LUT 错位比较,B[1]对应 A[0]。。。
例如,fpga_chx_clk 的产生电路(分频电路)。
3)A == B + 1
注意当 B == 0xFF 时,CARRY4 最后一级的 CO 进位为 0。
4)A == B – 1
通过补码,将减法电路转换为加法电路。
- 比较的时候,有优先级顺序,先比较高位,后比较低位;
- CARRY4 的好处:减少延迟。
扫码关注尚为网微信公众号
原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1365.html