Vivado混合仿真报错:无法将打包类型分配给非打包类型
Vivado混合仿真中VHDL数组与SystemVerilog打包类型赋值问题
问题场景
使用Vivado 2022.1进行混合语言仿真,涉及以下文件:
不可修改的VHDL包(mytypes.vhd)
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package mytypes is type std_logic_vector_array is array(natural range <>) of std_logic_vector; type my_record is record rxdata : std_logic_vector_array(3 downto 0)(7 downto 0); end record; end package mytypes;
SystemVerilog测试台(mytest.sv)
import mytypes::*; class MyPacket; rand bit[31:0] _header; endclass module simu( output mytypes::my_record recdata ); logic CLK100; MyPacket pckt; const int increment = 2; initial begin CLK100 = 0; forever #(5) CLK100 = ~CLK100; end initial begin pckt = new(); pckt.randomize(); @(posedge CLK100); for (int i = 0; i < 4; i+= increment) begin recdata.rxdata[0][7:0] = pckt._header[i*8 +: 8]; @(posedge CLK100); end end endmodule
仿真时触发错误:
[VRFC 10-395] cannot assign a packed type to an unpacked type
存在以下限制条件:
- 必须使用混合源仿真
- 无法修改VHDL包,且VHDL无打包/非打包数据类型的概念
MyPacket._header作为单一逻辑元素,声明为非打包类型不符合业务逻辑
需要找到无需修改原有数据模型的解决方案,比如让仿真器将VHDL数组解释为打包类型,或通过宏等方式规避赋值错误。
解决方案
1. 逐位赋值规避类型差异
由于Vivado将VHDL的二维数组映射为SystemVerilog的完全非打包数组,直接将打包的bit[7:0]切片赋值给非打包数组会触发错误。可以通过逐位赋值的方式绕过这个限制:
// 修改测试台内的赋值循环 for (int i = 0; i < 4; i+= increment) begin bit [7:0] temp_slice = pckt._header[i*8 +: 8]; // 逐位将打包切片赋值给非打包的VHDL数组元素 for (int j = 0; j < 8; j++) begin recdata.rxdata[i][j] = temp_slice[j]; end @(posedge CLK100); end
这种方式无需修改原有数据模型,完全适配现有类型映射规则。
2. 用宏封装逐位赋值逻辑
如果需要多次进行此类赋值,可以用宏封装重复代码,提升可读性:
// 在测试台开头定义宏 `define PACKED_TO_UNPACKED(dst_unpacked, src_packed) \ for (int __idx = 0; __idx < $bits(src_packed); __idx++) begin \ dst_unpacked[__idx] = src_packed[__idx]; \ end // 赋值时直接调用宏 for (int i = 0; i < 4; i+= increment) begin bit [7:0] temp_slice = pckt._header[i*8 +: 8]; `PACKED_TO_UNPACKED(recdata.rxdata[i], temp_slice); @(posedge CLK100); end
宏内部使用双下划线前缀的变量名,避免与用户代码中的变量冲突。
3. 利用$cast进行类型强制转换
可以在SystemVerilog中定义与VHDL数组位宽匹配的打包类型,再通过$cast完成打包到非打包的转换:
// 定义与VHDL rxdata位宽匹配的打包类型 typedef bit [3:0][7:0] packed_rxdata_t; // 修改赋值逻辑 initial begin pckt = new(); pckt.randomize(); @(posedge CLK100); packed_rxdata_t temp_packed = pckt._header; // 强制将打包类型转换为VHDL导出的非打包类型 $cast(recdata.rxdata, temp_packed); // 若需要分时钟周期输出,可拆分赋值 for (int i = 0; i < 4; i+= increment) begin packed_rxdata_t temp = '0; temp[i] = pckt._header[i*8 +: 8]; $cast(recdata.rxdata, temp); @(posedge CLK100); end end
$cast会在运行时检查位宽兼容性,确保转换安全,且无需修改原有数据结构。
内容的提问来源于stack exchange,提问作者G. B.
相关产品推荐
相关产品推荐

