2. 定点减法器设计
任务定义
设计一个参数化定点减法器,输入为两个补码格式的有符号定点数,输出为两者之差。减法通过“取反加一”转换为加法实现,需正确处理借位(即加法进位)及溢出标志。验证重点在于补码减法中借位与溢出的关系。
设计规格
- 位宽参数:
W(默认8位),数据格式为定点数,二进制小数点位置由外部约定,本设计不感知小数点位置,仅执行整数补码减法。 - 输入:
a[W-1:0]、b[W-1:0],均为二进制补码。 - 输出:
diff[W-1:0](补码结果)、borrow(借位标志,即加法进位)、overflow(溢出标志)。 - 运算:
diff = a - b = a + (~b + 1)。
RTL实现
module fixed_subtractor #(
parameter W = 8
)(
input wire [W-1:0] a,
input wire [W-1:0] b,
output wire [W-1:0] diff,
output wire borrow,
output wire overflow
);
wire [W-1:0] b_not;
wire [W-1:0] b_comp; // b的补码
wire carry_out; // 加法进位,即减法借位
assign b_not = ~b;
assign b_comp = b_not + 1'b1;
// 加法器:a + (~b + 1)
assign {carry_out, diff} = a + b_comp;
// 借位标志:加法进位即为减法借位
assign borrow = carry_out;
// 溢出检测:两个操作数符号相同且与结果符号不同
// 减法溢出条件:a与b符号相反,且结果符号与a不同
wire sign_a = a[W-1];
wire sign_b = b[W-1];
wire sign_r = diff[W-1];
assign overflow = (sign_a != sign_b) && (sign_r != sign_a);
endmodule
测试平台与验证
以下测试平台覆盖三类关键场景:无借位正数减法、有借位正数减法、溢出场景(正减负溢出、负减正溢出)。
`timescale 1ns/1ps
module tb_fixed_subtractor;
parameter W = 8;
reg [W-1:0] a, b;
wire [W-1:0] diff;
wire borrow, overflow;
fixed_subtractor #(.W(W)) dut (
.a(a), .b(b),
.diff(diff),
.borrow(borrow),
.overflow(overflow)
);
// 参考模型:使用更大位宽避免溢出干扰
function [W:0] ref_sub;
input [W-1:0] x, y;
begin
ref_sub = {1'b0, x} - {1'b0, y};
end
endfunction
integer i;
reg [W-1:0] ref_diff;
reg ref_borrow;
initial begin
$monitor("t=%0t a=%h b=%h diff=%h borrow=%b overflow=%b",
$time, a, b, diff, borrow, overflow);
// 用例1:正数减法,无借位 (a=5, b=3)
a = 8'h05; b = 8'h03; #10;
// 用例2:正数减法,有借位 (a=3, b=5)
a = 8'h03; b = 8'h05; #10;
// 用例3:正减负,溢出 (a=127, b=-128)
a = 8'h7F; b = 8'h80; #10;
// 用例4:负减正,溢出 (a=-128, b=1)
a = 8'h80; b = 8'h01; #10;
// 用例5:负减负,无溢出 (a=-3, b=-5) = 2
a = 8'hFD; b = 8'hFB; #10;
// 自动比对
for (i = 0; i < 5; i = i + 1) begin
case (i)
0: begin a = 8'h05; b = 8'h03; end
1: begin a = 8'h03; b = 8'h05; end
2: begin a = 8'h7F; b = 8'h80; end
3: begin a = 8'h80; b = 8'h01; end
4: begin a = 8'hFD; b = 8'hFB; end
endcase
#10;
ref_diff = ref_sub(a, b);
ref_borrow = (a < b) ? 1'b1 : 1'b0; // 无符号比较近似,仅用于正数场景
if (diff !== ref_diff[W-1:0])
$display("FAIL: a=%h b=%h diff=%h expected=%h", a, b, diff, ref_diff[W-1:0]);
else
$display("PASS: a=%h b=%h diff=%h", a, b, diff);
end
$finish;
end
endmodule
验证方法与判定标准
- 运行方式:使用支持Verilog-2001的仿真器(如Vivado XSim、ModelSim、Icarus Verilog)编译并运行上述RTL与测试平台。
- 观测点:
diff是否为正确补码差;borrow在a<b(无符号视角)时是否为1;overflow在用例3、4中是否为1,在用例1、2、5中是否为0。 - 判定标准:仿真器输出中所有
PASS且无FAIL,同时用例3、4的overflow为1,用例1、2、5的overflow为0,即判定通过。
预期输出(确定性推导)
根据补码运算规则,可推导各用例预期结果:
- 用例1:a=5, b=3 → diff=0x02, borrow=0, overflow=0
- 用例2:a=3, b=5 → diff=0xFE(-2), borrow=1, overflow=0
- 用例3:a=127, b=-128 → diff=0xFF(-1), borrow=0, overflow=1
- 用例4:a=-128, b=1 → diff=0x7F(127), borrow=1, overflow=1
- 用例5:a=-3, b=-5 → diff=0x02(2), borrow=0, overflow=0
上图展示了减法器的数据通路:b先取反加一得到补码,再与a相加,加法进位直接映射为借位标志,溢出由操作数与结果符号关系独立判定。