mantissa_norm
我们开始对 mantissa_norm.sv 进行逐行分析。这个模块的功能是 尾数规格化(Mantissa Normalization),即通过左移尾数使最高位为 1,并相应调整指数。
🔹 第 1 行:模块说明
// Mantissa normalization
这是模块功能注释:用于浮点或 Posit 算术中规格化尾数。
🔹 第 2–5 行:模块参数定义
module mantissa_norm #(
parameter int unsigned WIDTH = 8,
parameter int unsigned EXP_WIDTH = 3,
parameter int unsigned DECIMAL_POINT = 3 // digits before decimal point
)(
| 参数名 | 说明 |
|---|---|
WIDTH |
输入尾数(operand)的位宽 |
EXP_WIDTH |
输出指数调整值的位宽(为 signed) |
DECIMAL_POINT |
输入中小数点前的位数(例如隐藏位或整数部分) |
此模块的目标是使 MSB ≈ DECIMAL_POINT 位置为 1,即归一化。
🔹 第 6–9 行:输入输出端口
input logic [WIDTH-1:0] operand_i,
output logic signed [EXP_WIDTH:0] exp_adjust,
output logic [WIDTH-1:0] result_o
);
| 信号 | 方向 | 功能 |
|---|---|---|
operand_i |
in | 待规格化的尾数输入 |
exp_adjust |
out | 规格化所需的指数偏移值 |
result_o |
out | 规格化后的尾数输出 |
🔹 第 11–13 行:内部变量定义
localparam int unsigned LZC_WIDTH = pdpu_pkg::clog2(WIDTH);
logic [LZC_WIDTH-1:0] leading_zero_count;
logic lzc_zeroes;
| 信号 | 说明 |
|---|---|
LZC_WIDTH |
前导零计数结果所需的位宽(log2(WIDTH) 向上取整) |
leading_zero_count |
前导零的实际数量(从 LZC 输出) |
lzc_zeroes |
LZC 返回的 empty_o 信号(表示输入是否全为0) |
🔹 第 15–22 行:调用 lzc 模块
// leading zero count
lzc #(
.WIDTH(WIDTH),
.MODE(1'b1)
) u_lzc(
.in_i(operand_i),
.cnt_o(leading_zero_count),
.empty_o(lzc_zeroes)
);
调用我们之前分析并转换的 leading zero counter 模块(lzc.v):
| 参数 | 值 | 含义 |
|---|---|---|
MODE=1 |
LZC 模式 | 计算从 MSB 开始的 0 的数量 |
输出 cnt_o |
前导零数量 | |
输出 empty_o |
是否全部为 0 |
到此,我们完成了:
- 参数和端口定义
- 调用 LZC 获得
leading_zero_count
下一步将是根据 LZC 结果进行移位和指数调整。
是否继续分析接下来的移位与指数调整逻辑?
我们继续分析 mantissa_norm.sv 中第 21–40 行的内容,这部分主要处理 指数调整(exp_adjust) 和开始准备 尾数左移(规格化) 的操作。
📘 行 23–25:LZC模块结束
.cnt_o(leading_zero_count),
.empty_o(lzc_zeroes)
);
这是 lzc 实例的最后端口连接,正式结束 u_lzc 实例化。
📐 行 27:指数调整的 always_comb 块开始
// Exponent adjustment
always_comb begin
在组合逻辑块中,根据前导零数目,决定应调整指数的量。
🔁 行 28–36:指数调整逻辑
if (lzc_zeroes) begin
exp_adjust = '0;
end
else if (leading_zero_count <= DECIMAL_POINT - 1) begin
exp_adjust = DECIMAL_POINT - leading_zero_count - 1;
end
else begin
exp_adjust = -signed'(leading_zero_count - DECIMAL_POINT + 1);
end
| 条件 | 指数调整方式 |
|---|---|
输入为全 0(lzc_zeroes) |
指数调整设为 0 |
| 前导零少于 decimal point(无需左移) | 指数调整为一个正数(向上加) |
| 前导零多于 decimal point(需要左移规格化) | 指数调整为一个负数(向下减) |
其中:
DECIMAL_POINT - leading_zero_count - 1表示右移补足小数点-(leading_zero_count - DECIMAL_POINT + 1)表示左移规格化
这种计算兼容 Posit 的浮点模型中 “隐藏位” 在 MSB 左侧的情况。
🔁 行 38–40:调用 barrel_shifter 准备移位规格化
// Mantissa normalization
barrel_shifter #(
.WIDTH(WIDTH),
开始实例化我们之前分析过的 桶形移位器:
- 用于将
operand_i根据前导零数量左移 - 实现尾数对齐(最高位为 1)
是否继续分析 barrel_shifter 的剩余端口连接与整个模块的结尾?
继续分析 mantissa_norm.sv 模块最后部分,包括桶形移位器 barrel_shifter 的完整实例化与模块结尾:
🔧 行 41–42:barrel_shifter 参数设置
.SHIFT_WIDTH(LZC_WIDTH),
.MODE(1'b0)
| 参数 | 值 | 含义 |
|---|---|---|
SHIFT_WIDTH |
LZC 位宽 | 控制最大移位量 |
MODE=0 |
左移模式 | 因为规格化尾数需要将其左移到最高位 |
🔌 行 43–46:barrel_shifter 端口连接
) u_barrel_shifter(
.operand_i(operand_i),
.shift_amount(leading_zero_count),
.result_o(result_o)
);
| 端口名 | 来源/目标 | 说明 |
|---|---|---|
operand_i |
输入尾数 | 原始尾数输入 |
shift_amount |
LZC 输出 | 左移多少位 |
result_o |
输出尾数 | 左移后的规格化结果 |
🔚 行 47:模块结束
endmodule
✅ 总结:mantissa_norm 模块功能
| 子模块 | 功能 |
|---|---|
lzc |
计算尾数前导零 |
exp_adjust |
计算规格化后的指数修正 |
barrel_shifter |
将尾数左移,保证最高位为 1(规格化) |
整个模块是浮点/Posit 算法中尾数规格化必不可少的一环,结构简洁、逻辑清晰,并且支持任意宽度。
是否将此模块转换为 Verilog-2001 格式(不使用 logic、包引用、参数类型等 SystemVerilog 特性)?

浙公网安备 33010602011771号