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 特性)?

posted @ 2025-05-04 16:32  江左子固  阅读(49)  评论(0)    收藏  举报