当前位置: 首页 > news >正文

[SystemVerilog] Struct

SystemVerilog Struct用法详解

SystemVerilog 的 struct 是一种复合数据类型,用于将多个不同类型的变量(成员)组织成一个单一的实体。struct 在硬件设计和验证中广泛使用,特别适合表示复杂的数据结构,如数据包、配置寄存器或状态信息。与联合体(union)和类(class)相比,struct 提供了静态、紧凑的数据组织方式,并且支持综合。本文将详细介绍 SystemVerilog 中 struct 的各种用法,包括基本定义、成员访问、嵌套结构、参数化、数组、以及在验证和设计中的应用,并提供示例代码和最佳实践。

1. Struct 概述

struct 是一种用户定义的复合数据类型,允许将多个不同类型的成员组合在一起,形成一个逻辑单元。每个成员占用独立的存储空间,访问时通过点号(.)引用。与其他数据类型的对比:

  • 与联合体(union)struct 的成员独立存储,union 的成员共享存储空间。
  • 与类(class)struct 是静态类型,支持综合;class 是动态类型,仅用于验证。
  • 与数组struct 支持异构成员,数组成员类型相同。

主要用途

  • 硬件设计:表示寄存器组、数据包或配置信息。
  • 验证:在测试环境中组织复杂数据(如 UVM 事务)。
  • 模块化:提高代码的可读性和可维护性。

基本语法

struct [packed] [signed/unsigned] {type1 member1;type2 member2;...
} struct_name;
  • packed:可选,指定结构体的紧凑存储,适合硬件综合。
  • signed/unsigned:可选,指定结构体成员的符号性(通常与 packed 一起使用)。
  • type1, type2:成员的数据类型,如 logicint 等。
  • struct_name:结构体的名称。

2. 基本 Struct 定义与使用

struct 的基本用法是定义一组相关成员,并在代码中访问这些成员。

示例:简单数据包结构体

module example;struct {int id;logic [7:0] data;bit valid;} packet;initial beginpacket.id = 1;packet.data = 8'hA5;packet.valid = 1;$display("Packet: ID=%d, Data=%h, Valid=%b", packet.id, packet.data, packet.valid);end
endmodule

说明

  • packet 结构体包含三个成员:id(32位整数)、data(8位逻辑信号)和 valid(1位标志)。
  • 通过点号(.)访问成员,如 packet.id
  • 结构体成员独立存储,修改一个成员不影响其他成员。

注意

  • 结构体成员的默认初始值取决于其类型(logic 为 X,int 为 0,bit 为 0)。
  • 未使用 packed 时,结构体可能包含填充位,不适合直接映射到硬件。

3. Packed Struct

packed 结构体将所有成员紧凑存储,适合硬件设计中表示连续的位字段(如寄存器或数据包)。packed 结构体可以整体赋值或比较。

示例:紧凑寄存器结构体

module example;struct packed {logic [3:0] opcode;logic [7:0] address;logic valid;} reg_config;initial beginreg_config = 13'h1A5F; // 整体赋值(opcode=4'h1, address=8'hA5, valid=1)$display("Opcode: %h, Address: %h, Valid: %b", reg_config.opcode, reg_config.address, reg_config.valid);end
endmodule

说明

  • packed 确保 opcodeaddressvalid 紧凑排列为 13 位。
  • 整体赋值(如 reg_config = 13'h1A5F)按照成员定义顺序分配位。
  • 支持位操作和综合,适合寄存器建模。

注意

  • packed 结构体中的成员必须是可综合类型(如 logicbit)。
  • 成员按声明顺序从高位到低位排列(除非明确指定位域)。

带符号的 Packed Struct

packed 结构体可以指定 signedunsigned,影响整体结构体的符号性。

module example;struct packed signed {logic [3:0] value;logic sign;} data;initial begindata = -5; // 带符号赋值$display("Value: %d, Sign: %b", data.value, data.sign);end
endmodule

说明

  • signed 指定结构体整体为有符号类型。
  • 赋值时按有符号整数解释。

注意

  • 符号性仅影响整体赋值或比较,成员仍按其类型处理。
  • 通常与 packed 一起使用。

4. 嵌套 Struct

struct 支持嵌套,允许在结构体中定义其他结构体,形成层次化数据结构。

示例:嵌套数据包

module example;struct {int id;struct {logic [7:0] payload;logic [3:0] crc;} body;bit valid;} packet;initial beginpacket.id = 1;packet.body.payload = 8'hA5;packet.body.crc = 4'hF;packet.valid = 1;$display("Packet: ID=%d, Payload=%h, CRC=%h, Valid=%b", packet.id, packet.body.payload, packet.body.crc, packet.valid);end
endmodule

说明

  • body 是一个嵌套结构体,包含 payloadcrc
  • 通过多级点号访问成员,如 packet.body.payload
  • 嵌套结构体适合表示复杂数据层次。

注意

  • 嵌套结构体可能增加存储需求,未使用 packed 时可能包含填充位。
  • 确保嵌套层次清晰,避免过深嵌套。

5. 参数化 Struct

struct 可以通过模块参数或局部参数(localparam)实现参数化,动态配置成员的位宽或其他属性。

示例:参数化结构体

module example #(parameter DATA_WIDTH = 8);struct packed {logic [DATA_WIDTH-1:0] data;logic [3:0] opcode;} packet;initial beginpacket.data = 'hA5;packet.opcode = 4'hF;$display("Data: %h, Opcode: %h", packet.data, packet.opcode);end
endmodule

说明

  • 参数 DATA_WIDTH 控制 data 成员的位宽。
  • packed 确保紧凑存储。
  • 参数化提高了结构体的复用性。

注意

  • 参数必须在编译时确定。
  • 确保成员类型与参数值兼容。

6. Struct 数组

struct 可以作为数组元素,适合表示一组相似的数据结构,如数据包队列或寄存器组。

示例:结构体数组

module example;struct {int id;logic [7:0] data;} packet [0:2]; // 3个packet结构体initial beginpacket[0] = '{id: 1, data: 8'hA1}; // 使用结构体字面量赋值packet[1] = '{id: 2, data: 8'hA2};packet[2] = '{id: 3, data: 8'hA3};foreach (packet[i])$display("Packet[%0d]: ID=%d, Data=%h", i, packet[i].id, packet[i].data);end
endmodule

说明

  • packet 是一个包含 3 个结构体的数组。
  • 使用结构体字面量 '{id: value, data: value} 赋值。
  • foreach 循环遍历数组。

注意

  • 结构体数组支持综合,适合寄存器文件或内存建模。
  • 确保数组大小在编译时确定。

7. Struct 在验证中的应用

struct 在验证环境(如 UVM)中常用于定义事务(transaction)或数据包,组织测试数据。

示例:UVM 验证中的 Struct

import uvm_pkg::*;
`include "uvm_macros.svh"module example;struct {int id;logic [7:0] data;bit valid;} packet;initial beginpacket = '{id: 1, data: 8'hA5, valid: 1};`uvm_info("TEST", $sformatf("Packet: ID=%0d, Data=%h, Valid=%b", packet.id, packet.data, packet.valid), UVM_LOW)end
endmodule

说明

  • packet 结构体表示一个简单的事务。
  • 使用 UVM 宏(uvm_info)打印结构体内容。
  • 结构体适合定义测试用例中的数据结构。

注意

  • 验证中,struct 常与 class 结合,class 用于动态行为,struct 用于静态数据。
  • 确保结构体成员类型支持仿真。

8. Struct 在硬件设计中的应用

struct 在硬件设计中常用于表示寄存器组、数据包或状态信息,支持综合。

示例:寄存器组

module reg_bank (input logic clk, rst_n, write_en,input logic [7:0] write_data,output logic [7:0] read_data);struct packed {logic [3:0] control;logic [3:0] status;} reg_file;always_ff @(posedge clk or negedge rst_n) beginif (!rst_n)reg_file = '0;else if (write_en)reg_file = write_data;endassign read_data = reg_file;
endmodule

说明

  • reg_file 是一个 packed 结构体,表示 8 位寄存器组。
  • 支持同步写操作,异步复位。
  • read_data 直接输出结构体内容。

注意

  • 使用 packed 确保紧凑存储和位对齐。
  • 验证综合工具对 struct 的支持。

9. Struct 的高级用法

9.1 结构体字面量赋值

SystemVerilog 支持使用结构体字面量('{})为结构体赋值,简化初始化。

module example;struct {int id;logic [7:0] data;} packet;initial beginpacket = '{id: 1, data: 8'hA5}; // 字面量赋值$display("Packet: ID=%d, Data=%h", packet.id, packet.data);end
endmodule

说明

  • '{id: value, data: value} 按成员名称赋值,顺序无关。
  • 提高代码可读性。

注意

  • 所有成员必须赋值,否则报错。
  • 支持嵌套字面量。

9.2 默认值赋值

可以使用 '{default: value} 为结构体所有成员赋默认值。

module example;struct {int id;logic [7:0] data;bit valid;} packet;initial beginpacket = '{default: 0}; // 所有成员赋值为 0$display("Packet: ID=%d, Data=%h, Valid=%b", packet.id, packet.data, packet.valid);end
endmodule

说明

  • '{default: 0} 将所有成员初始化为 0。
  • 适合快速清零或初始化。

注意

  • 默认值必须与成员类型兼容。
  • 仅适用于简单初始化。

9.3 结构体比较

struct 支持整体比较(==!=),但需确保成员类型支持比较。

module example;struct {int id;logic [7:0] data;} pkt1, pkt2;initial beginpkt1 = '{id: 1, data: 8'hA5};pkt2 = '{id: 1, data: 8'hA5};if (pkt1 == pkt2)$display("Packets are equal");else$display("Packets are different");end
endmodule

说明

  • 比较逐个检查成员。
  • packed 结构体支持位级比较。

注意

  • 非综合类型(如 string)可能导致比较不可靠。
  • 确保比较逻辑明确。

10. 注意事项与最佳实践

  1. 类型选择

    • 硬件设计中使用 packed 结构体,确保紧凑存储。
    • 验证中可以使用非 packed 结构体,灵活组织数据。
  2. 综合支持

    • 确保 struct 成员为可综合类型(如 logicbit)。
    • 验证综合工具对 packed 和嵌套结构体的支持。
  3. 成员访问

    • 使用点号(.)访问成员,确保成员名称唯一。
    • 避免深层嵌套,保持访问简洁。
  4. 初始化

    • 显式初始化结构体成员,避免 X 或未定义值。
    • 使用结构体字面量或默认值简化初始化。
  5. 数组与结构体

    • 结构体数组适合表示寄存器组或数据队列。
    • 确保数组大小在编译时确定(硬件设计)。
  6. 验证环境

    • 在 UVM 中,使用 struct 定义静态事务数据。
    • 结合 class 实现动态行为。
  7. 代码可读性

    • 为结构体和成员提供有意义的名称。
    • 添加注释说明结构体用途和成员功能。
  8. 调试与验证

    • 检查结构体成员的初始值和赋值逻辑。
    • 使用仿真工具验证结构体行为。

11. 总结

SystemVerilog 的 struct 是一种灵活的复合数据类型,适用于硬件设计和验证中的数据组织。通过基本定义、packed 结构体、嵌套结构、参数化、数组等功能,struct 支持复杂数据建模,如寄存器组、数据包和事务。在硬件设计中,packed 结构体确保紧凑存储和综合支持;在验证中,struct 提供静态数据组织,结合 class 增强测试灵活性。遵循最佳实践并根据应用场景选择合适的 struct 用法,能够显著提高代码的可读性、可维护性和设计效率。

12. 设计工具推荐

  • SZ901
    SZ901 是一款基于XVC协议的FPGA网络下载器。
    • 最高支持53M
    • 支持4路JTAG独立使用
    • 支持端口合并
    • 支持国产FLASH烧写
    • 下载器无限扩展
    • 配备专属程序固化软件,一键烧写,能大大减小程序固化时间!

相关文章:

  • ChatGPT与DeepSeek在科研论文撰写中的整体科研流程与案例解析
  • 使用 malloc 函数模拟开辟一个 3x5 的整型二维数组
  • 多模态大语言模型arxiv论文略读(四十四)
  • linux blueZ 第六篇:嵌入式与工业级应用案例——在 Raspberry Pi、Yocto 与 Buildroot 上裁剪 BlueZ 并落地实战
  • 单例模式:确保类的唯一实例
  • MyBatis 类型处理器(TypeHandler)注册与映射机制:JsonListTypeHandler和JsonListTypeHandler注册时机
  • 单例模式:全局唯一性在软件设计中的艺术实践
  • 《代码整洁之道》第6章 对象和数据结构 - 笔记
  • 04 Enhanced Telecom Operations Map (eTOM)
  • 计算机网络自顶向下思维导图
  • 《代码整洁之道》第12章 迭进 - 笔记
  • EasyRTC嵌入式音视频通信SDK助力视频客服,开启智能服务新时代
  • 嵌入式软件--stm32 DAY 4 中断系统
  • 从零开始了解数据采集(二十一)——电子制造行业趋势分析案例
  • 消防应急物资智能调用立库:豪越科技助力消防“速战速决”
  • 央视两次采访报道爱藏评级,聚焦生肖钞市场升温,评级币成交易安全“定心丸”
  • uniapp: 低功耗蓝牙(BLE)的使用
  • 《代码整洁之道》第8章 边界 - 笔记
  • JVM——垃圾收集策略
  • 【首款Armv9开源芯片“星睿“O6测评】SVE2指令集介绍与测试
  • 中央纪委办公厅公开通报3起整治形式主义为基层减负典型问题
  • 特朗普将举行集会庆祝重返白宫执政百日,美媒:时机不当
  • 四川一国企“80后”掌门人为报领导“知遇之恩”,盲目决策致数亿损失
  • 快捷公寓单间不足5平方米?公寓方:预订平台图片只是参考,已退房款
  • 远程控制、窃密、挖矿!我国境内捕获“银狐”木马病毒变种
  • 云南洱源县4.8级地震:房屋受损442户,无人员伤亡报告