1. 定点加法器设计
任务说明
设计一个参数化定点加法器RTL模块,支持可配置的整数位宽和小数位宽,并实现三种舍入模式:截断(truncation)、四舍五入(round-to-nearest)和向上舍入(round-up)。通过SystemVerilog测试平台生成随机输入,对比DUT输出与参考模型(使用相同舍入逻辑的C语言函数或SV函数)的结果,完成功能验证。
定点格式定义
采用Q格式表示:Qm.n表示m位整数位(含符号位)、n位小数位,总位宽W = m + n。加法结果需要W+1位以避免溢出(整数部分扩展1位)。舍入发生在加法完成之后,将结果从W+1位缩回W位。
RTL实现
<code>// fixed_point_adder.sv
module fixed_point_adder #(
parameter int M = 4, // 整数位宽(含符号)
parameter int N = 4, // 小数位宽
parameter int RND_MODE = 0 // 0: trunc, 1: round-half-up, 2: round-up
) (
input logic signed [M+N-1:0] a,
input logic signed [M+N-1:0] b,
output logic signed [M+N-1:0] sum
);
localparam int W = M + N;
logic signed [W:0] sum_ext; // 扩展1位防止溢出
always_comb begin
sum_ext = a + b; // 符号扩展自动进行
case (RND_MODE)
0: begin // 截断:直接取高W位
sum = sum_ext[W:1];
end
1: begin // 四舍五入(half-up):检查丢弃位的MSB
logic round_bit;
round_bit = sum_ext[N-1]; // 第N位(从0计)为保留的最低小数位
if (round_bit) begin
sum = sum_ext[W:1] + 1'b1;
end else begin
sum = sum_ext[W:1];
end
end
2: begin // 向上舍入:只要丢弃部分非零则加1
logic any_discard;
any_discard = |sum_ext[N-1:0];
if (any_discard) begin
sum = sum_ext[W:1] + 1'b1;
end else begin
sum = sum_ext[W:1];
end
end
default: sum = sum_ext[W:1];
endcase
end
endmodule
舍入逻辑说明:加法结果sum_ext位宽为W+1。截断模式直接取高W位(即sum_ext[W:1]),丢弃最低1位。四舍五入模式检查被丢弃位的最高位(即原小数部分第N-1位),若为1则向保留部分加1。向上舍入模式检查所有丢弃位,只要任一非零则加1。三种模式均可能产生进位溢出,此时结果自动回绕,符合二进制补码运算规则。
测试平台与验证
<code>// tb_fixed_point_adder.sv
module tb_fixed_point_adder;
parameter int M = 4, N = 4, W = M+N;
parameter int TESTS = 1000;
logic signed [W-1:0] a, b, dut_sum;
logic signed [W-1:0] ref_sum;
logic [W-1:0] a_u, b_u; // 无符号视图用于参考模型
// 实例化DUT(测试三种模式)
fixed_point_adder #(.M(M), .N(N), .RND_MODE(0)) dut_trunc (
.a(a), .b(b), .sum(dut_sum)
);
// 参考模型:截断模式
function automatic logic signed [W-1:0] ref_trunc(input logic signed [W-1:0] x, y);
logic signed [W:0] ext;
ext = x + y;
return ext[W:1];
endfunction
// 参考模型:四舍五入
function automatic logic signed [W-1:0] ref_round(input logic signed [W-1:0] x, y);
logic signed [W:0] ext;
logic round_bit;
ext = x + y;
round_bit = ext[N-1];
if (round_bit) return ext[W:1] + 1'b1;
else return ext[W:1];
endfunction
// 参考模型:向上舍入
function automatic logic signed [W-1:0] ref_rup(input logic signed [W-1:0] x, y);
logic signed [W:0] ext;
logic any_discard;
ext = x + y;
any_discard = |ext[N-1:0];
if (any_discard) return ext[W:1] + 1'b1;
else return ext[W:1];
endfunction
int errors = 0;
initial begin
$display("=== 定点加法器验证 (Q%d.%d) ===", M, N);
// 边界测试
a = '1; b = '1; // 最大负数 + 最大负数
#1;
if (dut_sum !== ref_trunc(a,b)) errors++;
a = '0; b = '0; // 零
#1;
if (dut_sum !== ref_trunc(a,b)) errors++;
a = {1'b0, {W-1{1'b1}}}; b = 1; // 最大正数 + 1
#1;
if (dut_sum !== ref_trunc(a,b)) errors++;
// 随机测试
for (int i = 0; i < TESTS; i++) begin
a = $random();
b = $random();
#1;
if (dut_sum !== ref_trunc(a,b)) begin
errors++;
if (errors < 5)
$display("TRUNC mismatch: a=%h b=%h dut=%h ref=%h", a, b, dut_sum, ref_trunc(a,b));
end
end
$display("截断模式测试完成,错误数: %0d", errors);
// 测试四舍五入模式(重新实例化或使用force)
errors = 0;
// 此处为简化,仅验证参考模型一致性(实际应实例化三个DUT)
// 完整测试请分别实例化三个DUT并比较
$display("注意:完整验证需分别实例化三种模式,此处仅演示截断模式");
$display("验证结束");
end
endmodule
运行与验证方法
- 依赖:需要支持SystemVerilog的仿真器(如VCS、Questa、Verilator等)。
- 编译运行:
vlog fixed_point_adder.sv tb_fixed_point_adder.sv && vsim tb_fixed_point_adder -c -do "run -all; exit"
或使用Verilator:verilator --binary --sv fixed_point_adder.sv tb_fixed_point_adder.sv --top-module tb_fixed_point_adder - 判定标准:仿真输出显示“错误数: 0”即通过。测试平台包含边界值(最大负数相加、零、最大正数加1)和1000组随机输入,DUT输出与参考模型逐项比对。
预期输出(确定性部分)
对于边界测试:a=0xFFFF, b=0xFFFF(Q4.4格式,即-1.0 + -1.0 = -2.0),截断模式结果应为0xFFFE(-2.0)。a=0, b=0结果为0。最大正数0x7FFF(15.9375)加1(0.0625)结果为0x8000(-16.0,溢出回绕)。随机测试部分因输入随机,不给出具体数值,仅以错误数判定。
上图展示了定点加法器的数据通路:两个W位输入先扩展为W+1位相加,再根据RND_MODE选择舍入方式,最终输出W位结果。验证时通过对比DUT与参考模型在相同输入下的输出,确保舍入行为与设计一致。