在 SystemVerilog 中将动态位数组格式化为字符串
Formatting Dynamic Array of Bits as String in SystemVerilog
如何将动态位数组(或更准确地说,逻辑)格式化为字符串,例如,对于 UVM 的 convert2string?例如,我想转换
logic vdyn[];
...
vdyn = new [16] ('{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1});
到字符串0097
.
我认为以下内容可行(#
只是为了可读性而分隔字符串):
fmt = $sformatf("#%%%0dh#", (vdyn.size-1)/4 + 1); // "#%4h#"
vstr = $sformatf(fmt, { >> {vdyn}});
但它 returns # x#
,至少在 Questa 10.3d 中是这样(我怀疑这是一个错误 - 如果它能在其他模拟器上运行,我会很感兴趣)。
我尝试先将其转换为压缩数组,但遇到了其他问题。如果对结果没有大小限制,源值总是在目标变量中左对齐,例如:
logic [63:0] v64;
...
v64 = {>> {vdyn}}; // 64'h0097000000000000
如果不使用可变大小的切片,就无法只打印出我想要的部分。以下工作,但它要求我在编译时知道数组的大小:
v64 = 16'({>> {vdyn}}); // 64'h0000000000000097
我发现的最好的东西是下面的 "double-reverse"(注意我在这里使用 <<
,而不是 >>
):
v64 = {<< {vdyn}}; // 64'he900000000000000
v64 = {<< {v64}}; // 64'h0000000000000097
vstr = $sformatf(fmt, v64); // #0097#
不过,必须这样做似乎有些矫揉造作。顺便说一句,将前两个语句合并为一个是行不通的:
v64 = {<< {{<< {vdyn}}}}; // 64'hZ900000000000000
(v64[63]
由于某种原因是 z
)。同样,我怀疑这是 Questa 10.3d 中的错误。
尝试转换数组的一部分并循环遍历。例如,转换为 4 位值的 4 条目切片。可以使用 -:
或 +:
运算符(参见 IEEE Std 1800-2012 § 7.4.3 Operations on arrays 和 § 7.4.6 数组的索引和切片)
vstr = "";
for(int i=vdyn.size()-1; i>=0; i-=4) begin
vstr = $sformatf("%h%s", 4'({>>{vdyn[i -: 4]}}), vstr);
end
vstr = $sformatf("#%s#", vstr); // user formatting
代码中的 4
s 可以更改为其他内容,具体取决于需要多少前导 0 或非二次幂格式,但它必须是数字常量
我在其他一些模拟器上试过你的代码。 vstr = $sformatf(fmt, { >> {vdyn}});
有时会给我编译错误。将数组转换为大于其预期最大大小的值似乎可行
fmt = $sformatf("#%%%0dh#", (vdyn.size-1)/4 + 1); // "#%4h#"
vstr = $sformatf(fmt, 128'({ >> {vdyn}})); // works iff 128>=vdyn.size
我认为问题可能是使用动态类型的流运算符的宽度未在自定义上下文中定义(例如,系统任务的参数)。我认为 LRM 应该将此视为错误。
解决方法是将左对齐的结果向右移动
v64 = {>> {vdyn}};
v64 >>= 64-vdyn.size;
如何将动态位数组(或更准确地说,逻辑)格式化为字符串,例如,对于 UVM 的 convert2string?例如,我想转换
logic vdyn[];
...
vdyn = new [16] ('{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1});
到字符串0097
.
我认为以下内容可行(#
只是为了可读性而分隔字符串):
fmt = $sformatf("#%%%0dh#", (vdyn.size-1)/4 + 1); // "#%4h#"
vstr = $sformatf(fmt, { >> {vdyn}});
但它 returns # x#
,至少在 Questa 10.3d 中是这样(我怀疑这是一个错误 - 如果它能在其他模拟器上运行,我会很感兴趣)。
我尝试先将其转换为压缩数组,但遇到了其他问题。如果对结果没有大小限制,源值总是在目标变量中左对齐,例如:
logic [63:0] v64;
...
v64 = {>> {vdyn}}; // 64'h0097000000000000
如果不使用可变大小的切片,就无法只打印出我想要的部分。以下工作,但它要求我在编译时知道数组的大小:
v64 = 16'({>> {vdyn}}); // 64'h0000000000000097
我发现的最好的东西是下面的 "double-reverse"(注意我在这里使用 <<
,而不是 >>
):
v64 = {<< {vdyn}}; // 64'he900000000000000
v64 = {<< {v64}}; // 64'h0000000000000097
vstr = $sformatf(fmt, v64); // #0097#
不过,必须这样做似乎有些矫揉造作。顺便说一句,将前两个语句合并为一个是行不通的:
v64 = {<< {{<< {vdyn}}}}; // 64'hZ900000000000000
(v64[63]
由于某种原因是 z
)。同样,我怀疑这是 Questa 10.3d 中的错误。
尝试转换数组的一部分并循环遍历。例如,转换为 4 位值的 4 条目切片。可以使用 -:
或 +:
运算符(参见 IEEE Std 1800-2012 § 7.4.3 Operations on arrays 和 § 7.4.6 数组的索引和切片)
vstr = "";
for(int i=vdyn.size()-1; i>=0; i-=4) begin
vstr = $sformatf("%h%s", 4'({>>{vdyn[i -: 4]}}), vstr);
end
vstr = $sformatf("#%s#", vstr); // user formatting
代码中的 4
s 可以更改为其他内容,具体取决于需要多少前导 0 或非二次幂格式,但它必须是数字常量
我在其他一些模拟器上试过你的代码。 vstr = $sformatf(fmt, { >> {vdyn}});
有时会给我编译错误。将数组转换为大于其预期最大大小的值似乎可行
fmt = $sformatf("#%%%0dh#", (vdyn.size-1)/4 + 1); // "#%4h#"
vstr = $sformatf(fmt, 128'({ >> {vdyn}})); // works iff 128>=vdyn.size
我认为问题可能是使用动态类型的流运算符的宽度未在自定义上下文中定义(例如,系统任务的参数)。我认为 LRM 应该将此视为错误。
解决方法是将左对齐的结果向右移动
v64 = {>> {vdyn}};
v64 >>= 64-vdyn.size;