posit_decoder

我们开始对 posit_decoder.sv 文件的前 20 行进行逐行分析。该模块的功能是将一个 N 位的 Posit 编码解码为:符号位、regime+exponent、尾数(mantissa)。


📝 第 1 行:模块说明

// Posit decoder

📘 说明该模块用于将 Posit 格式解码成其内部数值表示。


🔧 第 2–8 行:模块与参数定义

module posit_decoder #(
    parameter int unsigned n = 16,  // word size
    parameter int unsigned es = 1,  // exponent size
    //do not change
    parameter int unsigned nd = pdpu_pkg::clog2(n-1),
    parameter int unsigned EXP_WIDTH = nd+es,       // not include sign bit
    parameter int unsigned MANT_WIDTH = n-es-3      // not include implicit bit
)(
参数 含义
n Posit 编码的总位宽(例如 n=16
es exponent 字段的最大位宽
nd 最大可能的 regime 位数(clog2(n-1))
EXP_WIDTH regime + exponent 的总位宽
MANT_WIDTH 尾数的最大长度(去掉 sign, regime 最少1位, es)

注:这些参数与之前的 posit_encoder 模块保持一致,确保解码-编码的对称性。


🔌 第 9–13 行:输入输出端口定义

    input logic [n-1:0] operand_i,
    output logic sign_o,
    output logic signed [EXP_WIDTH:0] rg_exp_o,  
    output logic [MANT_WIDTH:0] mant_norm_o
);
信号名 方向 含义
operand_i 输入 原始 Posit 编码
sign_o 输出 符号位
rg_exp_o 输出 regime + exponent 联合位段(有符号)
mant_norm_o 输出 规格化后的尾数(包含隐藏位)

🧱 第 15–17 行:注释说明

    // ---------------
    // Perform two's complement if negative
    // ---------------

📘 说明即将进行符号提取及补码处理,Posit 编码采用 sign-magnitude 编码方式,负数需转换为补码以统一后续处理。


🔧 第 18–19 行:内部变量定义

    logic sign;
    logic [n-2:0] operand_value;
变量名 含义
sign Posit 的符号位(最高位)
operand_value 除去符号位的剩余位串(用于 regime/exponent 解码)

这些是标准 Posit 解码流程的前置准备步骤:

  • 提取 sign 位
  • 准备对负数进行反码/补码转换
  • 进入 regime 解析流程

是否继续分析接下来如何实现补码操作和 regime 字段提取?

我们继续分析 posit_decoder.sv 中第 21–40 行的逻辑,这部分实现了:

  1. 提取符号位并进行补码转换(若为负数)
  2. 准备进行 regime 解码(通过前导 0 或 1 计数)

➕ 行 22:符号位提取

assign sign = operand_i[n-1];

📘 Posit 编码的最高位是符号位。


♻️ 行 23:补码转换

assign operand_value = sign ? (~operand_i[n-2:0]+1) : operand_i[n-2:0];

🧠 解释:

  • 若为负数(sign=1),将剩下的位串取补码(反码+1)
  • 否则直接取剩余位作为 operand value
  • 这样处理后的 operand_value 可以统一进行 regime + exponent 解码

🔍 行 26–27:regime 字段符号提取

logic regS;
assign regS = operand_value[n-2];
  • regime 的符号是编码中的次高位(bit n-2)
  • regS = 1 表示 regime 以 1 开头(即 k >= 0),否则 k < 0

🔄 行 28–29:准备 LZC 输入

logic [n-2:0] lzc_operand;
assign lzc_operand = regS ? (~operand_value) : operand_value;

📘 为了用 LZC 模块统一处理 regime 位长度:

  • regS == 1(即 1 开头),将其取反变为 0 开头
  • 然后用 leading-zero-counter 来数连续 0 的数量

这样不论是连续 1(正 regime)还是连续 0(负 regime),都能转化为数 0。


🔧 行 30–32:LZC 模块接口定义

logic [nd-1:0] leading_zero_count;
logic lzc_zeroes;
  • 输出 leading_zero_count 是前导 0 或 1 的数量(用于确定 regime 位长)
  • 输出 lzc_zeroes 用于检测是否全部为 0(非法 Posit)

⚙️ 行 33–39:实例化 LZC

lzc #(
    .WIDTH(n-1),
    .MODE(1'b1)
) u_lzc (
    .in_i(lzc_operand),

📌 LZC 使用我们之前转换的模块,mode 设置为 1 表示数从 MSB 开始的前导 0。

此处用于 regime 解码:

  • regS=1(即 regime 开头是 1)时,取反后得到若干个 0 → 用 LZC 数出 regime 的长度。
  • regS=0(即负 regime)时,也可以直接 LZC。

是否继续分析 LZC 输出与 regime 指数组合字段(rg_exp_o)的赋值部分?

我们继续分析 posit_decoder.sv 的第 41–60 行,这部分主要完成:

  • 根据 LZC 结果计算 regime 的长度k 值
  • 移除 regime 字段准备提取 exponent 和 mantissa

✅ 行 41–43:LZC输出连接

.cnt_o(leading_zero_count),
.empty_o(lzc_zeroes)
);

📌 LZC 输出前导 0 的数量(leading_zero_count)与是否全 0(lzc_zeroes


🔢 行 45–47:定义中间变量

logic [nd-1:0] runlength;       // 连续相同位的个数
logic [nd-1:0] regime_bits;     // regime 字段总长度
logic signed [nd:0] regime_k;   // regime 表示的实际值 k

这些变量用于计算 regime k 值,并为指数字段提供基础。


🧮 行 49–51:计算 regime k 值及长度

assign runlength = lzc_zeroes ? (n-1) : leading_zero_count;
assign regime_bits = lzc_zeroes ? (n-1) : (leading_zero_count+1);
assign regime_k = regS ? ({1'b0,runlength-1}) : ({1'b1,~runlength+1});
表达式 含义
runlength 若全 0,则最大长度,否则取 LZC 结果
regime_bits regime 字段的总长度为连续相同位数 + 1(符号位)
regime_k 实际 regime 值 k,根据 regS 正负号处理,采用补码计算

注:

  • regS=1 表示正 k,k = runlength - 1
  • regS=0 表示负 k,k = -runlength(已用补码表达)

🧹 行 54–55:准备移除 regime 字段

// Left shift regime field
logic [n-2:0] op_no_rg;

变量 op_no_rg 用于保存 移除 regime 后的位串(接下来将从中提取 exponent 和 mantissa)


🌀 行 57–59:桶形移位器准备

barrel_shifter #(
    .WIDTH(n-1),
    .SHIFT_WIDTH(nd),

调用我们之前转换过的 barrel_shifter,用于将 operand_value 左移 regime_bits 位,从而剥离 regime 字段。


是否继续分析 barrel_shifter 的连接、剩余 exponent 与 mantissa 提取过程?

我们继续分析 posit_decoder.sv 的第 41–60 行,这部分主要完成:

  • 根据 LZC 结果计算 regime 的长度k 值
  • 移除 regime 字段准备提取 exponent 和 mantissa

✅ 行 41–43:LZC输出连接

.cnt_o(leading_zero_count),
.empty_o(lzc_zeroes)
);

📌 LZC 输出前导 0 的数量(leading_zero_count)与是否全 0(lzc_zeroes


🔢 行 45–47:定义中间变量

logic [nd-1:0] runlength;       // 连续相同位的个数
logic [nd-1:0] regime_bits;     // regime 字段总长度
logic signed [nd:0] regime_k;   // regime 表示的实际值 k

这些变量用于计算 regime k 值,并为指数字段提供基础。


🧮 行 49–51:计算 regime k 值及长度

assign runlength = lzc_zeroes ? (n-1) : leading_zero_count;
assign regime_bits = lzc_zeroes ? (n-1) : (leading_zero_count+1);
assign regime_k = regS ? ({1'b0,runlength-1}) : ({1'b1,~runlength+1});
表达式 含义
runlength 若全 0,则最大长度,否则取 LZC 结果
regime_bits regime 字段的总长度为连续相同位数 + 1(符号位)
regime_k 实际 regime 值 k,根据 regS 正负号处理,采用补码计算

注:

  • regS=1 表示正 k,k = runlength - 1
  • regS=0 表示负 k,k = -runlength(已用补码表达)

🧹 行 54–55:准备移除 regime 字段

// Left shift regime field
logic [n-2:0] op_no_rg;

变量 op_no_rg 用于保存 移除 regime 后的位串(接下来将从中提取 exponent 和 mantissa)


🌀 行 57–59:桶形移位器准备

barrel_shifter #(
    .WIDTH(n-1),
    .SHIFT_WIDTH(nd),

调用我们之前转换过的 barrel_shifter,用于将 operand_value 左移 regime_bits 位,从而剥离 regime 字段。


是否继续分析 barrel_shifter 的连接、剩余 exponent 与 mantissa 提取过程?

我们继续分析 posit_decoder.sv 的第 61–80 行,这部分主要完成:

  1. 调用桶形移位器移除 regime 字段
  2. 提取 sign 输出
  3. 开始处理 exponent 位段的提取

🔄 行 61–66:桶形移位器调用完毕

.MODE(1'b0)
) u_barrel_shifter(
    .operand_i(operand_value),
    .shift_amount(regime_bits),
    .result_o(op_no_rg)
);

📌 使用 barrel_shifteroperand_value 左移 regime_bits 位,去除 regime 段。

  • 得到的 op_no_rg 即为剩余位串(接下来将从中提取 exponent 和 mantissa)

🔧 行 68–70:符号位输出连接

// Extract sign
assign sign_o = sign;
  • 原始最高位 sign 直接赋值为输出信号 sign_o

📤 行 73–75:指数字段处理准备

logic [es:0] exp;
if(es==0) begin
    assign exp = 0;

📌 Posit 中 es=0 是合法情况(如 posit<8,0>),此时 exponent 字段不存在,直接设为 0。

否则将提取 exponent 字段的位串。


🔄 行 76:开始处理非零 es 的指数提取

else begin

后续将用 op_no_rg 中前 es 位作为 exponent,再合并 regime_k 输出最终 rg_exp_o


是否继续分析 exponent 提取、指数拼接与尾数提取逻辑?

我们继续分析 posit_decoder.sv 的最后 20 行,完成了 exponent 与 mantissa 提取,并正式结束模块:


🔢 行 81:提取 exponent 位段

assign exp = op_no_rg[n-2:n-2-es+1];

📌 从 op_no_rg 中提取 es 位作为 exponent(高位优先)

例如:

  • n = 16, es = 2 ⇒ 提取位 [14:13] 为 exponent

🔗 行 83:拼接 regime 与 exponent

assign rg_exp_o = regime_k << es | exp;

🧠 意思:

  • regime_k 左移 es 位,腾出空间
  • 然后和 exponent 做按位或,构成一个完整的 指数编码输出

该值为有符号数,代表最终浮点指数(注意 Posit 没有显式 bias)


🧵 行 86–87:尾数提取准备

logic implicit_bit;
assign implicit_bit = |operand_i[n-2:0];
  • Posit 有隐藏位(implicit bit)机制

    • 只要除 sign 外的内容非 0,就说明尾数有效 ⇒ 隐式 bit = 1
    • 否则为 0

🧮 行 88:输出尾数(mantissa)

assign mant_norm_o = {implicit_bit, op_no_rg[n-2-es:2]};

📌 拼接:

  • 首位是 implicit bit
  • 后面是除去 exponent 字段后的剩余比特(从 op_no_rg[n-2-es]bit 2

注意:

  • 舍弃了低两位(bit 1bit 0),这些位通常为保留/精度外位

🔚 行 89:模块结束

endmodule

✅ 总结:posit_decoder 功能概览

功能模块 说明
sign 提取 最高位
two's complement 负数取补码,便于统一处理
regime 解码 利用前导 0/1 计数器,获得 k
exponent 提取 es 位,从 regime 后的位串中获取
mantissa 提取 隐式位 + 剩余位构成

是否将该模块转换为 Verilog-2001 格式?(移除 logicalways_comb、包引用等 SV 特性)

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