SystemVerilog学习【七】包(Package)详解
SystemVerilog学习【七】包(Package)详解
📖 扩展学习资源:
- SystemVerilog学习【一】数据类型详解 - CSDN
- SystemVerilog学习【二】接口(interface)详解 - CSDN
- SystemVerilog学习【三】类和面向对象编程详解 - CSDN
- SystemVerilog学习【四】约束随机化编程详解 - CSDN
- SystemVerilog学习【五】断言详解 - CSDN
- SystemVerilog学习【六】功能覆盖率详解 - CSDN
文章目录
- SystemVerilog学习【七】包(Package)详解
- 7. SystemVerilog——包(Package)详解
- 7.1 包的基本概念
- 7.1.1 传统Verilog的局限性
- 7.5.2 UVM包的应用
- 7.6 包的最佳实践
- 7.6.1 命名约定
- 7.6.2 文档和注释
- 7.7 总结
- 7.7.1 主要优势
- 7.7.2 与传统Verilog的对比
- 7.7.3 最佳实践要点
- 7.7.4 应用场景
- 7.4.2 包的编译和链接
- 7.4.3 包的版本管理
- 7.5 包在验证环境中的应用
- 7.5.1 验证组件的封装
- 7.1.2 SystemVerilog包的优势
- 7.1.3 包的作用域和可见性
- 7.2 包的定义和声明
- 7.2.1 基本包定义语法
- 7.2.2 包中的数据类型定义
- 7.2.3 包中的函数和任务
- 7.2.4 包中的参数和常量
- 7.3 包的导入机制
- 7.3.1 import语句的使用
- 7.3.2 通配符导入
- 7.3.3 选择性导入
- 7.3.4 导入的作用域
- 7.4 包的高级特性
- 7.4.1 包的嵌套和依赖
7. SystemVerilog——包(Package)详解
7.1 包的基本概念
7.1.1 传统Verilog的局限性
在传统Verilog中,代码重用和模块化存在诸多限制:
Verilog的局限性:
- 没有命名空间概念,容易产生命名冲突
- 全局声明污染命名空间
- 代码重用困难,需要通过include文件
- 缺乏封装机制,数据类型和函数难以组织
- 编译依赖关系复杂
// 传统Verilog方式 - 存在问题的代码组织// file1.v
`define DATA_WIDTH 32
`define ADDR_WIDTH 16function [31:0] calculate_checksum;input [31:0] data;// 函数实现
endfunction// file2.v
`define DATA_WIDTH 64 // 命名冲突!
`define ADDR_WIDTH 20 // 重定义问题function [31:0] calculate_checksum; // 函数名冲突input [63:0] data;// 不同的实现
endfunction// main.v
`include "file1.v"
`include "file2.v" // 会导致重定义错误module main;reg [`DATA_WIDTH-1:0] data; // 使用哪个DATA_WIDTH?reg [31:0] checksum;initial beginchecksum = calculate_checksum(data); // 调用哪个函数?endendmodule
7.5.2 UVM包的应用
UVM(Universal Verification Methodology)大量使用包来组织验证组件:
// uvm_package_demo.sv
// 演示UVM风格的包使用package my_uvm_pkg;import uvm_pkg::*;`include "uvm_macros.svh"// 配置对象class my_config extends uvm_object;int num_transactions;bit enable_coverage;string test_name;`uvm_object_utils_begin(my_config)`uvm_field_int(num_transactions, UVM_DEFAULT)`uvm_field_int(enable_coverage, UVM_DEFAULT)`uvm_field_string(test_name, UVM_DEFAULT)`uvm_object_utils_endfunction new(string name = "my_config");super.new(name);num_transactions = 100;enable_coverage = 1;test_name = "default_test";endfunctionendclass// 序列项class my_transaction extends uvm_sequence_item;rand logic [31:0] addr;rand logic [31:0] data;rand logic [3:0] byte_en;rand bit write;constraint addr_c {addr inside {[32'h1000:32'h1FFF]};addr[1:0] == 2'b00; // 字对齐}constraint byte_en_c {byte_en != 4'b0000; // 至少一个字节使能}`uvm_object_utils_begin(my_transaction)`uvm_field_int(addr, UVM_DEFAULT | UVM_HEX)`uvm_field_int(data, UVM_DEFAULT | UVM_HEX)`uvm_field_int(byte_en, UVM_DEFAULT | UVM_BIN)`uvm_field_int(write, UVM_DEFAULT)`uvm_object_utils_endfunction new(string name = "my_transaction");super.new(name);endfunctionfunction string convert2string();return $sformatf("%s: %s addr=0x%h data=0x%h be=%b",get_name(), write ? "WRITE" : "READ", addr, data, byte_en);endfunctionendclass// 序列class my_sequence extends uvm_sequence #(my_transaction);`uvm_object_utils(my_sequence)int num_trans;function new(string name = "my_sequence");super.new(name);num_trans = 10;endfunctionvirtual task body();my_transaction trans;`uvm_info(get_type_name(), $sformatf("Starting sequence with %d transactions", num_trans), UVM_MEDIUM)for (int i = 0; i < num_trans; i++) begintrans = my_transaction::type_id::create("trans");start_item(trans);if (!trans.randomize()) begin`uvm_error(get_type_name(), "Randomization failed")end`uvm_info(get_type_name(), $sformatf("Transaction %d: %s", i, trans.convert2string()), UVM_HIGH)finish_item(trans);end`uvm_info(get_type_name(), "Sequence completed", UVM_MEDIUM)endtaskendclass// 驱动器class my_driver extends uvm_driver #(my_transaction);`uvm_component_utils(my_driver)virtual memory_interface vif;function new(string name = "my_driver", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);if (!uvm_config_db#(virtual memory_interface)::get(this, "", "vif", vif)) begin`uvm_fatal(get_type_name(), "Virtual interface not found")endendfunctionvirtual task run_phase(uvm_phase phase);my_transaction trans;forever beginseq_item_port.get_next_item(trans);`uvm_info(get_type_name(), $sformatf("Driving: %s", trans.convert2string()), UVM_HIGH)drive_transaction(trans);seq_item_port.item_done();endendtaskvirtual task drive_transaction(my_transaction trans);@(posedge vif.clk);vif.addr <= trans.addr;vif.data <= trans.data;vif.byte_en <= trans.byte_en;vif.write <= trans.write;vif.valid <= 1'b1;// 等待readydo begin@(posedge vif.clk);end while (!vif.ready);// 如果是读操作,获取数据if (!trans.write) begin@(posedge vif.clk);trans.data = vif.rdata;end// 清除信号vif.valid <= 1'b0;endtaskendclass// 监视器class my_monitor extends uvm_monitor;`uvm_component_utils(my_monitor)virtual memory_interface vif;uvm_analysis_port #(my_transaction) analysis_port;function new(string name = "my_monitor", uvm_component parent = null);super.new(name, parent);analysis_port = new("analysis_port", this);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);if (!uvm_config_db#(virtual memory_interface)::get(this, "", "vif", vif)) begin`uvm_fatal(get_type_name(), "Virtual interface not found")endendfunctionvirtual task run_phase(uvm_phase phase);my_transaction trans;forever begincollect_transaction(trans);`uvm_info(get_type_name(), $sformatf("Collected: %s", trans.convert2string()), UVM_HIGH)analysis_port.write(trans);endendtaskvirtual task collect_transaction(ref my_transaction trans);// 等待有效事务do begin@(posedge vif.clk);end while (!(vif.valid && vif.ready));trans = my_transaction::type_id::create("collected_trans");trans.addr = vif.addr;trans.byte_en = vif.byte_en;trans.write = vif.write;if (vif.write) begintrans.data = vif.data;end else begin@(posedge vif.clk);trans.data = vif.rdata;endendtaskendclass// 代理class my_agent extends uvm_agent;`uvm_component_utils(my_agent)my_driver driver;my_monitor monitor;uvm_sequencer #(my_transaction) sequencer;function new(string name = "my_agent", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);monitor = my_monitor::type_id::create("monitor", this);if (get_is_active() == UVM_ACTIVE) begindriver = my_driver::type_id::create("driver", this);sequencer = uvm_sequencer#(my_transaction)::type_id::create("sequencer", this);endendfunctionvirtual function void connect_phase(uvm_phase phase);super.connect_phase(phase);if (get_is_active() == UVM_ACTIVE) begindriver.seq_item_port.connect(sequencer.seq_item_export);endendfunctionendclass// 环境class my_env extends uvm_env;`uvm_component_utils(my_env)my_agent agent;my_config cfg;function new(string name = "my_env", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);// 获取配置if (!uvm_config_db#(my_config)::get(this, "", "cfg", cfg)) begincfg = my_config::type_id::create("cfg");`uvm_info(get_type_name(), "Using default configuration", UVM_MEDIUM)endagent = my_agent::type_id::create("agent", this);endfunctionendclass// 基础测试class my_base_test extends uvm_test;`uvm_component_utils(my_base_test)my_env env;my_config cfg;function new(string name = "my_base_test", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);// 创建配置cfg = my_config::type_id::create("cfg");cfg.test_name = get_type_name();// 设置配置到数据库uvm_config_db#(my_config)::set(this, "*", "cfg", cfg);// 创建环境env = my_env::type_id::create("env", this);endfunctionvirtual function void end_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);`uvm_info(get_type_name(), "Test topology:", UVM_MEDIUM)print();endfunctionvirtual task run_phase(uvm_phase phase);my_sequence seq;phase.raise_objection(this);`uvm_info(get_type_name(), "Starting test", UVM_MEDIUM)seq = my_sequence::type_id::create("seq");seq.num_trans = cfg.num_transactions;seq.start(env.agent.sequencer);`uvm_info(get_type_name(), "Test completed", UVM_MEDIUM)phase.drop_objection(this);endtaskendclass// 具体测试class my_simple_test extends my_base_test;`uvm_component_utils(my_simple_test)function new(string name = "my_simple_test", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);cfg.num_transactions = 20;cfg.enable_coverage = 1;endfunctionendclassendpackage : my_uvm_pkg// UVM测试模块
module uvm_package_test;import uvm_pkg::*;import my_uvm_pkg::*;`include "uvm_macros.svh"logic clk = 0;logic rst_n = 0;// 时钟和复位always #5 clk = ~clk;initial beginrst_n = 0;#20 rst_n = 1;end// 接口实例memory_interface mem_if(clk, rst_n);// 简单DUT模型logic [31:0] memory[1024];always @(posedge clk) beginif (rst_n) beginmem_if.ready <= 1'b1;if (mem_if.valid) beginif (mem_if.write) beginmemory[mem_if.addr[11:2]] <= mem_if.data;end else beginmem_if.rdata <= memory[mem_if.addr[11:2]];endendend else beginmem_if.ready <= 1'b0;mem_if.rdata <= 32'h0;endend// UVM测试启动initial begin// 设置接口到配置数据库uvm_config_db#(virtual memory_interface)::set(null, "*", "vif", mem_if);// 运行测试run_test("my_simple_test");end
endmodule
7.6 包的最佳实践
7.6.1 命名约定
良好的命名约定提高代码可读性:
// naming_conventions_demo.sv// 包命名:使用描述性名称,以_pkg结尾
package cpu_instruction_decoder_pkg;// 常量命名:全大写,下划线分隔const int MAX_INSTRUCTION_WIDTH = 32;const int MIN_OPCODE_BITS = 6;const string PACKAGE_VERSION = "2.1.0";// 类型定义命名:小写,下划线分隔,以_t结尾typedef logic [MAX_INSTRUCTION_WIDTH-1:0] instruction_word_t;typedef logic [MIN_OPCODE_BITS-1:0] opcode_t;typedef logic [4:0] register_addr_t;// 枚举类型:大写,描述性名称typedef enum opcode_t {OP_ADD = 6'b000000,OP_SUB = 6'b000001,OP_MUL = 6'b000010,OP_DIV = 6'b000011,OP_LOAD = 6'b100000,OP_STORE = 6'b100001,OP_BRANCH = 6'b110000,OP_JUMP = 6'b110001} instruction_opcode_t;// 结构体命名:小写,下划线分隔,以_s结尾typedef struct packed {instruction_opcode_t opcode;register_addr_t rs1;register_addr_t rs2;register_addr_t rd;logic [10:0] immediate;} instruction_format_s;// 类命名:首字母大写,驼峰命名class InstructionDecoder;// 私有成员:以m_开头local instruction_format_s m_current_instruction;local bit m_valid;local string m_error_message;// 静态成员:以s_开头static int s_decode_count = 0;// 公共方法:小写开头,驼峰命名function new();m_valid = 0;m_error_message = "";endfunctionfunction bit decodeInstruction(instruction_word_t inst_word);s_decode_count++;// 解析指令m_current_instruction = instruction_format_s'(inst_word);// 验证操作码if (!isValidOpcode(m_current_instruction.opcode)) beginm_valid = 0;m_error_message = $sformatf("Invalid opcode: 0x%h", m_current_instruction.opcode);return 0;endm_valid = 1;m_error_message = "";return 1;endfunctionfunction bit isValidOpcode(instruction_opcode_t opcode);case (opcode)OP_ADD, OP_SUB, OP_MUL, OP_DIV,OP_LOAD, OP_STORE, OP_BRANCH, OP_JUMP: return 1;default: return 0;endcaseendfunctionfunction instruction_format_s getCurrentInstruction();return m_current_instruction;endfunctionfunction bit isValid();return m_valid;endfunctionfunction string getErrorMessage();return m_error_message;endfunctionfunction string toString();if (!m_valid) beginreturn $sformatf("Invalid instruction: %s", m_error_message);endreturn $sformatf("Opcode: %s, rs1: %d, rs2: %d, rd: %d, imm: %d",m_current_instruction.opcode.name(),m_current_instruction.rs1,m_current_instruction.rs2,m_current_instruction.rd,m_current_instruction.immediate);endfunctionstatic function int getDecodeCount();return s_decode_count;endfunctionendclass// 函数命名:小写开头,驼峰命名,描述性function automatic instruction_format_s createRTypeInstruction(instruction_opcode_t opcode,register_addr_t rs1,register_addr_t rs2,register_addr_t rd);instruction_format_s inst;inst.opcode = opcode;inst.rs1 = rs1;inst.rs2 = rs2;inst.rd = rd;inst.immediate = 11'b0;return inst;endfunctionfunction automatic instruction_format_s createITypeInstruction(instruction_opcode_t opcode,register_addr_t rs1,register_addr_t rd,logic [10:0] immediate);instruction_format_s inst;inst.opcode = opcode;inst.rs1 = rs1;inst.rs2 = 5'b0;inst.rd = rd;inst.immediate = immediate;return inst;endfunction// 宏定义:全大写,描述性`define CREATE_R_TYPE_INST(op, rs1, rs2, rd) \createRTypeInstruction(op, rs1, rs2, rd)`define CREATE_I_TYPE_INST(op, rs1, rd, imm) \createITypeInstruction(op, rs1, rd, imm)// 调试和诊断函数function automatic void printPackageInfo();$display("=== CPU Instruction Decoder Package ===");$display("Version: %s", PACKAGE_VERSION);$display("Max instruction width: %d bits", MAX_INSTRUCTION_WIDTH);$display("Opcode bits: %d", MIN_OPCODE_BITS);$display("Total decodes performed: %d", InstructionDecoder::getDecodeCount());endfunctionendpackage : cpu_instruction_decoder_pkg// 使用命名约定的测试
module naming_conventions_test;import cpu_instruction_decoder_pkg::*;InstructionDecoder decoder;instruction_format_s test_instructions[];initial begin$display("=== Naming Conventions Demo ===");// 显示包信息printPackageInfo();// 创建解码器decoder = new();// 创建测试指令test_instructions = new[6];test_instructions[0] = `CREATE_R_TYPE_INST(OP_ADD, 5'd1, 5'd2, 5'd3);test_instructions[1] = `CREATE_R_TYPE_INST(OP_SUB, 5'd4, 5'd5, 5'd6);test_instructions[2] = `CREATE_I_TYPE_INST(OP_LOAD, 5'd7, 5'd8, 11'd100);test_instructions[3] = `CREATE_I_TYPE_INST(OP_STORE, 5'd9, 5'd10, 11'd200);test_instructions[4] = `CREATE_R_TYPE_INST(OP_MUL, 5'd11, 5'd12, 5'd13);test_instructions[5] = `CREATE_R_TYPE_INST(instruction_opcode_t'(6'b111111), 5'd1, 5'd2, 5'd3); // 无效操作码$display("\n=== Testing Instructions ===");foreach (test_instructions[i]) begininstruction_word_t inst_word = instruction_word_t'(test_instructions[i]);$display("\nInstruction %d: 0x%h", i, inst_word);if (decoder.decodeInstruction(inst_word)) begin$display(" Decode SUCCESS: %s", decoder.toString());end else begin$display(" Decode FAILED: %s", decoder.getErrorMessage());endend$display("\n=== Final Statistics ===");printPackageInfo();end
endmodule
7.6.2 文档和注释
良好的文档是包维护的关键:
// documentation_demo.sv/*** @package signal_processing_pkg* @brief 信号处理算法包* @version 1.2.0* @author SystemVerilog Team* @date 2024-01-15* * 本包提供了常用的数字信号处理算法,包括:* - 滤波器设计和实现* - FFT/IFFT变换* - 信号生成器* - 统计分析工具* * @note 所有算法都经过验证,适用于定点和浮点运算* @warning 某些函数可能需要大量计算资源*/
package signal_processing_pkg;/*** @brief 包版本信息*/const string PACKAGE_VERSION = "1.2.0";const int VERSION_MAJOR = 1;const int VERSION_MINOR = 2;const int VERSION_PATCH = 0;/*** @brief 数学常数定义*/const real PI = 3.14159265358979323846;const real E = 2.71828182845904523536;const real SQRT_2 = 1.41421356237309504880;/*** @typedef sample_t* @brief 信号采样点数据类型* * 使用16位有符号定点数表示信号采样值* 范围:-32768 到 32767*/typedef logic signed [15:0] sample_t;/*** @typedef coefficient_t* @brief 滤波器系数数据类型* * 使用18位有符号定点数表示滤波器系数* 提供更高的精度以减少量化误差*/typedef logic signed [17:0] coefficient_t;/*** @enum filter_type_t* @brief 滤波器类型枚举*/typedef enum {FILTER_LOWPASS, ///< 低通滤波器FILTER_HIGHPASS, ///< 高通滤波器FILTER_BANDPASS, ///< 带通滤波器FILTER_BANDSTOP ///< 带阻滤波器} filter_type_t;/*** @struct filter_config_s* @brief 滤波器配置结构体* * 包含滤波器设计所需的所有参数*/typedef struct {filter_type_t filter_type; ///< 滤波器类型int order; ///< 滤波器阶数real cutoff_freq; ///< 截止频率 (归一化,0-1)real sampling_freq; ///< 采样频率 (Hz)real ripple; ///< 通带纹波 (dB)real stopband_atten; ///< 阻带衰减 (dB)} filter_config_s;/*** @class DigitalFilter* @brief 数字滤波器类* * 实现IIR和FIR数字滤波器的设计和处理* * @example* ```systemverilog* DigitalFilter lpf = new();* filter_config_s config;* config.filter_type = FILTER_LOWPASS;* config.order = 4;* config.cutoff_freq = 0.25;* lpf.configure(config);* sample_t output = lpf.process(input_sample);* ```*/class DigitalFilter;/*** @brief 滤波器配置*/local filter_config_s m_config;/*** @brief 滤波器系数*/local coefficient_t m_coefficients[];/*** @brief 延迟线(存储历史样本)*/local sample_t m_delay_line[];/*** @brief 滤波器是否已配置*/local bit m_configured;/*** @brief 构造函数* * 初始化滤波器对象,设置默认状态*/function new();m_configured = 0;m_coefficients = new[0];m_delay_line = new[0];endfunction/*** @brief 配置滤波器* @param config 滤波器配置参数* @return 配置是否成功* * 根据提供的配置参数设计滤波器系数* * @note 此函数会重新计算所有滤波器系数* @warning 高阶滤波器可能需要较长的计算时间*/function bit configure(filter_config_s config);// 验证配置参数if (config.order <= 0 || config.order > 32) begin$error("Invalid filter order: %d (must be 1-32)", config.order);return 0;endif (config.cutoff_freq <= 0.0 || config.cutoff_freq >= 0.5) begin$error("Invalid cutoff frequency: %f (must be 0-0.5)", config.cutoff_freq);return 0;endm_config = config;// 设计滤波器系数(简化实现)designCoefficients();// 初始化延迟线m_delay_line = new[m_config.order + 1];foreach (m_delay_line[i]) beginm_delay_line[i] = 0;endm_configured = 1;$info("Filter configured: Type=%s, Order=%d, Fc=%f", m_config.filter_type.name(), m_config.order, m_config.cutoff_freq);return 1;endfunction/*** @brief 处理单个采样点* @param input 输入采样值* @return 滤波后的输出值* * 对输入采样值进行滤波处理* * @pre 滤波器必须已经配置 (configure())* @post 内部状态更新,准备处理下一个采样点*/function sample_t process(sample_t input);longint accumulator;if (!m_configured) begin$error("Filter not configured");return 0;end// 更新延迟线for (int i = m_delay_line.size() - 1; i > 0; i--) beginm_delay_line[i] = m_delay_line[i-1];endm_delay_line[0] = input;// 计算输出(FIR滤波)accumulator = 0;for (int i = 0; i < m_coefficients.size(); i++) beginaccumulator += longint'(m_coefficients[i]) * longint'(m_delay_line[i]);end// 缩放和饱和处理accumulator = accumulator >>> 16; // 定点数缩放if (accumulator > 32767) accumulator = 32767;else if (accumulator < -32768) accumulator = -32768;return sample_t'(accumulator);endfunction/*** @brief 批量处理采样数据* @param input_samples 输入采样数组* @param output_samples 输出采样数组(引用传递)* @return 处理的采样点数量* * 对一批采样数据进行滤波处理* * @note output_samples数组大小必须与input_samples相同*/function int processBatch(sample_t input_samples[], ref sample_t output_samples[]);if (input_samples.size() != output_samples.size()) begin$error("Input and output array sizes must match");return 0;endforeach (input_samples[i]) beginoutput_samples[i] = process(input_samples[i]);endreturn input_samples.size();endfunction/*** @brief 重置滤波器状态* * 清除所有内部状态,但保留配置参数*/function void reset();if (m_configured) beginforeach (m_delay_line[i]) beginm_delay_line[i] = 0;endendendfunction/*** @brief 获取滤波器配置信息* @return 当前配置结构体*/function filter_config_s getConfig();return m_config;endfunction/*** @brief 获取滤波器系数* @return 系数数组的副本*/function coefficient_t[] getCoefficients();coefficient_t result[] = new[m_coefficients.size()];foreach (m_coefficients[i]) beginresult[i] = m_coefficients[i];endreturn result;endfunction/*** @brief 打印滤波器信息* * 输出滤波器的详细配置和状态信息*/function void printInfo();$display("=== Digital Filter Information ===");$display("Configured: %s", m_configured ? "Yes" : "No");if (m_configured) begin$display("Type: %s", m_config.filter_type.name());$display("Order: %d", m_config.order);$display("Cutoff Frequency: %f", m_config.cutoff_freq);$display("Sampling Frequency: %f Hz", m_config.sampling_freq);$display("Coefficients: %d", m_coefficients.size());$display("Coefficients:");foreach (m_coefficients[i]) begin$display(" h[%d] = %d (0x%h)", i, m_coefficients[i], m_coefficients[i]);endendendfunction/*** @brief 设计滤波器系数(私有方法)* * 根据配置参数计算滤波器系数* 这里使用简化的窗函数方法*/local function void designCoefficients();real omega_c = 2.0 * PI * m_config.cutoff_freq;int N = m_config.order + 1;m_coefficients = new[N];// 简化的低通滤波器设计(汉明窗)for (int n = 0; n < N; n++) beginreal h_ideal, window, h_windowed;int n_center = N / 2;// 理想低通滤波器冲激响应if (n == n_center) beginh_ideal = omega_c / PI;end else beginreal arg = omega_c * (n - n_center);h_ideal = $sin(arg) / (PI * (n - n_center));end// 汉明窗window = 0.54 - 0.46 * $cos(2.0 * PI * n / (N - 1));// 加窗h_windowed = h_ideal * window;// 转换为定点数m_coefficients[n] = coefficient_t'(h_windowed * 65536.0);end// 根据滤波器类型调整系数case (m_config.filter_type)FILTER_HIGHPASS: transformToHighpass();FILTER_BANDPASS: transformToBandpass();FILTER_BANDSTOP: transformToBandstop();default: ; // 低通滤波器,无需变换endcaseendfunction/*** @brief 变换为高通滤波器(私有方法)*/local function void transformToHighpass();// 简化实现:通过频谱反转实现for (int n = 0; n < m_coefficients.size(); n++) beginif (n % 2 == 1) beginm_coefficients[n] = -m_coefficients[n];endendendfunction/*** @brief 变换为带通滤波器(私有方法)*/local function void transformToBandpass();// 简化实现:调制方法real center_freq = m_config.cutoff_freq;for (int n = 0; n < m_coefficients.size(); n++) beginreal modulation = $cos(2.0 * PI * center_freq * n);m_coefficients[n] = coefficient_t'(real'(m_coefficients[n]) * modulation);endendfunction/*** @brief 变换为带阻滤波器(私有方法)*/local function void transformToBandstop();// 简化实现:全通减去带通transformToBandpass();for (int n = 0; n < m_coefficients.size(); n++) beginm_coefficients[n] = -m_coefficients[n];end// 在中心位置加上单位冲激m_coefficients[m_coefficients.size()/2] += coefficient_t'(65536);endfunctionendclass : DigitalFilter/*** @brief 生成正弦波信号* @param amplitude 振幅* @param frequency 频率(归一化)* @param phase 初始相位(弧度)* @param num_samples 采样点数* @return 生成的信号数组* * 生成指定参数的正弦波信号* * @example* ```systemverilog* sample_t sine_wave[] = generateSineWave(1000, 0.1, 0.0, 256);* ```*/function automatic sample_t[] generateSineWave(int amplitude,real frequency,real phase,int num_samples);sample_t result[] = new[num_samples];for (int n = 0; n < num_samples; n++) beginreal arg = 2.0 * PI * frequency * n + phase;real value = amplitude * $sin(arg);// 饱和处理if (value > 32767.0) value = 32767.0;else if (value < -32768.0) value = -32768.0;result[n] = sample_t'(value);endreturn result;endfunction/*** @brief 计算信号的RMS值* @param samples 输入信号数组* @return RMS值* * 计算信号的均方根值*/function automatic real calculateRMS(sample_t samples[]);longint sum_squares = 0;foreach (samples[i]) beginsum_squares += longint'(samples[i]) * longint'(samples[i]);endreturn $sqrt(real'(sum_squares) / samples.size());endfunction/*** @brief 打印包信息* * 显示包的版本和功能信息*/function automatic void printPackageInfo();$display("=== Signal Processing Package ===");$display("Version: %s", PACKAGE_VERSION);$display("Features:");$display(" - Digital filtering (FIR/IIR)");$display(" - Signal generation");$display(" - Statistical analysis");$display(" - Fixed-point arithmetic support");endfunctionendpackage : signal_processing_pkg// 文档化包的使用示例
module documentation_demo;import signal_processing_pkg::*;DigitalFilter lpf;filter_config_s config;sample_t input_signal[];sample_t output_signal[];initial begin$display("=== Documentation Demo ===");// 显示包信息printPackageInfo();// 创建低通滤波器lpf = new();// 配置滤波器config.filter_type = FILTER_LOWPASS;config.order = 8;config.cutoff_freq = 0.2;config.sampling_freq = 1000.0;config.ripple = 0.5;config.stopband_atten = 40.0;if (!lpf.configure(config)) begin$error("Filter configuration failed");$finish;end// 显示滤波器信息lpf.printInfo();// 生成测试信号(正弦波 + 噪声)input_signal = generateSineWave(1000, 0.1, 0.0, 128);// 添加高频噪声for (int i = 0; i < input_signal.size(); i++) beginsample_t noise = sample_t'($urandom_range(-200, 200));input_signal[i] += noise;end$display("\nInput signal RMS: %f", calculateRMS(input_signal));// 滤波处理output_signal = new[input_signal.size()];lpf.processBatch(input_signal, output_signal);$display("Output signal RMS: %f", calculateRMS(output_signal));// 显示部分结果$display("\nFirst 10 samples:");$display("Index | Input | Output | Difference");$display("------|--------|--------|----------");for (int i = 0; i < 10; i++) begin$display("%5d | %6d | %6d | %6d", i, input_signal[i], output_signal[i], input_signal[i] - output_signal[i]);endend
endmodule
7.7 总结
包(Package)是SystemVerilog中强大的代码组织和重用机制。通过本章的学习,我们了解了:
7.7.1 主要优势
- 代码重用性:包允许在多个模块间共享代码
- 命名空间管理:避免命名冲突,提供清晰的作用域
- 模块化设计:促进大型项目的模块化开发
- 版本控制:支持包的版本管理和兼容性
- 验证效率:在验证环境中提供强大的组件封装能力
7.7.2 与传统Verilog的对比
特性 | Verilog | SystemVerilog包 |
---|---|---|
代码重用 | `include文件 | 包导入机制 |
命名空间 | 全局命名空间 | 包级命名空间 |
类型定义 | 有限支持 | 丰富的类型系统 |
函数封装 | 模块内函数 | 包级函数和类 |
编译管理 | 文件依赖 | 包依赖管理 |
版本控制 | 手动管理 | 内建版本支持 |
7.7.3 最佳实践要点
- 合理的包结构:按功能模块组织包内容
- 清晰的命名约定:使用描述性和一致的命名
- 完善的文档:提供详细的API文档和使用示例
- 版本管理:维护包的版本兼容性
- 依赖管理:明确包之间的依赖关系
- 测试覆盖:为包提供充分的测试用例
7.7.4 应用场景
- 验证环境:UVM测试平台的组件封装
- IP复用:可重用IP核的接口和功能定义
- 算法库:数学运算、信号处理等算法封装
- 协议栈:通信协议的分层实现
- 工具函数:常用的实用函数集合
通过掌握包的使用,可以显著提高SystemVerilog代码的质量、可维护性和重用性,这对于现代数字设计和验证项目至关重要。
7.4.2 包的编译和链接
包的编译顺序和依赖管理是重要的考虑因素:
// compile_order_demo.sv - 演示编译顺序的重要性// 第一步:编译基础包(无依赖)
package foundation_pkg;typedef logic [31:0] word_t;typedef logic [15:0] half_word_t;typedef logic [7:0] byte_t;const int WORD_SIZE = 32;const int HALF_WORD_SIZE = 16;const int BYTE_SIZE = 8;function automatic word_t combine_half_words(half_word_t high, half_word_t low);return {high, low};endfunction
endpackage// 第二步:编译依赖foundation_pkg的包
package instruction_pkg;import foundation_pkg::*;typedef enum logic [5:0] {ADD = 6'b000000,SUB = 6'b000001,MUL = 6'b000010,DIV = 6'b000011,LOAD = 6'b100000,STORE = 6'b100001,BRANCH = 6'b110000,JUMP = 6'b110001} opcode_t;typedef struct packed {opcode_t opcode;logic [4:0] rs1;logic [4:0] rs2;logic [4:0] rd;logic [10:0] immediate;} instruction_t;function automatic instruction_t create_r_type(opcode_t op, logic [4:0] rs1, logic [4:0] rs2, logic [4:0] rd);instruction_t inst;inst.opcode = op;inst.rs1 = rs1;inst.rs2 = rs2;inst.rd = rd;inst.immediate = 11'b0;return inst;endfunctionfunction automatic instruction_t create_i_type(opcode_t op, logic [4:0] rs1, logic [4:0] rd, logic [10:0] imm);instruction_t inst;inst.opcode = op;inst.rs1 = rs1;inst.rs2 = 5'b0;inst.rd = rd;inst.immediate = imm;return inst;endfunction
endpackage// 第三步:编译依赖多个包的包
package processor_pkg;import foundation_pkg::*;import instruction_pkg::*;typedef enum logic [2:0] {FETCH = 3'b000,DECODE = 3'b001,EXECUTE = 3'b010,MEMORY = 3'b011,WRITEBACK = 3'b100,HALT = 3'b101} cpu_state_t;class register_file;word_t registers[32];function new();for (int i = 0; i < 32; i++) beginregisters[i] = 0;endendfunctionfunction word_t read(logic [4:0] addr);return (addr == 0) ? 0 : registers[addr];endfunctionfunction void write(logic [4:0] addr, word_t data);if (addr != 0) begin // x0 is always 0registers[addr] = data;endendfunctionendclassclass simple_cpu;register_file rf;word_t pc;cpu_state_t state;instruction_t current_instruction;function new();rf = new();pc = 0;state = FETCH;endfunctionfunction void execute_instruction(instruction_t inst);word_t operand1, operand2, result;operand1 = rf.read(inst.rs1);operand2 = rf.read(inst.rs2);case (inst.opcode)ADD: result = operand1 + operand2;SUB: result = operand1 - operand2;MUL: result = operand1 * operand2;DIV: result = (operand2 != 0) ? operand1 / operand2 : 0;LOAD: result = operand1 + word_t'(inst.immediate);STORE: result = operand1 + word_t'(inst.immediate);default: result = 0;endcaseif (inst.opcode != STORE) beginrf.write(inst.rd, result);endendfunctionfunction string state_to_string();return state.name();endfunctionendclass
endpackage// 编译脚本示例(伪代码)
/*
# compile_packages.sh
# 正确的编译顺序# 1. 编译基础包
vlog foundation_pkg.sv# 2. 编译依赖基础包的包
vlog instruction_pkg.sv# 3. 编译依赖多个包的包
vlog processor_pkg.sv# 4. 编译使用所有包的模块
vlog processor_test.sv# 错误的编译顺序会导致编译失败:
# vlog processor_pkg.sv # 错误!找不到foundation_pkg和instruction_pkg
*/// 使用示例
module compile_order_demo;import foundation_pkg::*;import instruction_pkg::*;import processor_pkg::*;simple_cpu cpu;instruction_t test_instructions[];initial begin$display("=== Compile Order Demo ===");// 创建CPUcpu = new();// 创建测试指令test_instructions = new[5];test_instructions[0] = create_i_type(LOAD, 5'd0, 5'd1, 11'd100); // x1 = 100test_instructions[1] = create_i_type(LOAD, 5'd0, 5'd2, 11'd200); // x2 = 200test_instructions[2] = create_r_type(ADD, 5'd1, 5'd2, 5'd3); // x3 = x1 + x2test_instructions[3] = create_r_type(SUB, 5'd3, 5'd1, 5'd4); // x4 = x3 - x1test_instructions[4] = create_r_type(MUL, 5'd2, 5'd4, 5'd5); // x5 = x2 * x4$display("Initial CPU state: %s", cpu.state_to_string());$display("Initial PC: %d", cpu.pc);// 执行指令foreach (test_instructions[i]) begin$display("\nExecuting instruction %d:", i);$display(" Opcode: %s", test_instructions[i].opcode.name());$display(" rs1: %d, rs2: %d, rd: %d", test_instructions[i].rs1, test_instructions[i].rs2, test_instructions[i].rd);cpu.execute_instruction(test_instructions[i]);cpu.pc += 4;// 显示寄存器状态$display(" Register file after execution:");for (int j = 1; j <= 5; j++) begin$display(" x%d = %d", j, cpu.rf.read(j));endend$display("\nFinal CPU state: %s", cpu.state_to_string());$display("Final PC: %d", cpu.pc);end
endmodule
7.4.3 包的版本管理
在大型项目中,包的版本管理变得重要:
// version_management_demo.sv// 版本1.0的包
package math_utils_v1;const string VERSION = "1.0.0";const int VERSION_MAJOR = 1;const int VERSION_MINOR = 0;const int VERSION_PATCH = 0;// 基础数学函数function automatic int add(int a, int b);return a + b;endfunctionfunction automatic int multiply(int a, int b);return a * b;endfunction// 简单的除法(无错误处理)function automatic int divide(int a, int b);return a / b; // 可能导致除零错误endfunction
endpackage// 版本2.0的包(改进版本)
package math_utils_v2;const string VERSION = "2.0.0";const int VERSION_MAJOR = 2;const int VERSION_MINOR = 0;const int VERSION_PATCH = 0;// 错误类型定义typedef enum {MATH_OK,MATH_DIVIDE_BY_ZERO,MATH_OVERFLOW,MATH_UNDERFLOW} math_error_t;// 结果结构体typedef struct {int result;math_error_t error;string message;} math_result_t;// 改进的数学函数(带错误处理)function automatic math_result_t safe_add(int a, int b);math_result_t res;longint temp = longint'(a) + longint'(b);if (temp > 2**31 - 1) beginres.result = 0;res.error = MATH_OVERFLOW;res.message = "Addition overflow";end else if (temp < -2**31) beginres.result = 0;res.error = MATH_UNDERFLOW;res.message = "Addition underflow";end else beginres.result = int'(temp);res.error = MATH_OK;res.message = "Success";endreturn res;endfunctionfunction automatic math_result_t safe_multiply(int a, int b);math_result_t res;longint temp = longint'(a) * longint'(b);if (temp > 2**31 - 1) beginres.result = 0;res.error = MATH_OVERFLOW;res.message = "Multiplication overflow";end else if (temp < -2**31) beginres.result = 0;res.error = MATH_UNDERFLOW;res.message = "Multiplication underflow";end else beginres.result = int'(temp);res.error = MATH_OK;res.message = "Success";endreturn res;endfunctionfunction automatic math_result_t safe_divide(int a, int b);math_result_t res;if (b == 0) beginres.result = 0;res.error = MATH_DIVIDE_BY_ZERO;res.message = "Division by zero";end else beginres.result = a / b;res.error = MATH_OK;res.message = "Success";endreturn res;endfunction// 向后兼容的函数(调用新的安全函数)function automatic int add(int a, int b);math_result_t res = safe_add(a, b);if (res.error != MATH_OK) begin$warning("Math operation failed: %s", res.message);endreturn res.result;endfunctionfunction automatic int multiply(int a, int b);math_result_t res = safe_multiply(a, b);if (res.error != MATH_OK) begin$warning("Math operation failed: %s", res.message);endreturn res.result;endfunctionfunction automatic int divide(int a, int b);math_result_t res = safe_divide(a, b);if (res.error != MATH_OK) begin$error("Math operation failed: %s", res.message);endreturn res.result;endfunction
endpackage// 版本兼容性测试
module version_compatibility_test;// 测试v1.0版本initial begin$display("=== Testing Math Utils v1.0 ===");import math_utils_v1::*;$display("Version: %s", VERSION);$display("5 + 3 = %d", add(5, 3));$display("4 * 6 = %d", multiply(4, 6));$display("10 / 2 = %d", divide(10, 2));// 这会导致运行时错误(除零)// $display("10 / 0 = %d", divide(10, 0));end// 测试v2.0版本initial begin#100; // 延迟以避免输出混乱$display("\n=== Testing Math Utils v2.0 ===");import math_utils_v2::*;$display("Version: %s", VERSION);// 测试正常操作math_result_t res;res = safe_add(5, 3);$display("safe_add(5, 3): result=%d, error=%s, message=%s", res.result, res.error.name(), res.message);res = safe_multiply(4, 6);$display("safe_multiply(4, 6): result=%d, error=%s, message=%s", res.result, res.error.name(), res.message);res = safe_divide(10, 2);$display("safe_divide(10, 2): result=%d, error=%s, message=%s", res.result, res.error.name(), res.message);// 测试错误情况res = safe_divide(10, 0);$display("safe_divide(10, 0): result=%d, error=%s, message=%s", res.result, res.error.name(), res.message);// 测试溢出res = safe_multiply(2147483647, 2);$display("safe_multiply(2147483647, 2): result=%d, error=%s, message=%s", res.result, res.error.name(), res.message);// 测试向后兼容性$display("\n--- Backward Compatibility Test ---");$display("add(5, 3) = %d", add(5, 3));$display("multiply(4, 6) = %d", multiply(4, 6));$display("divide(10, 2) = %d", divide(10, 2));end
endmodule// 版本选择机制
package version_selector;// 编译时版本选择`ifdef USE_MATH_V1import math_utils_v1::*;const string SELECTED_VERSION = "1.0.0";`elsif USE_MATH_V2import math_utils_v2::*;const string SELECTED_VERSION = "2.0.0";`else// 默认使用最新版本import math_utils_v2::*;const string SELECTED_VERSION = "2.0.0 (default)";`endiffunction automatic void print_version_info();$display("Selected math utils version: %s", SELECTED_VERSION);$display("Actual package version: %s", VERSION);endfunction
endpackage// 版本选择测试
module version_selector_test;import version_selector::*;initial begin$display("=== Version Selector Test ===");print_version_info();// 使用选定版本的函数$display("Testing selected version:");$display("5 + 3 = %d", add(5, 3));$display("4 * 6 = %d", multiply(4, 6));$display("10 / 2 = %d", divide(10, 2));end
endmodule
7.5 包在验证环境中的应用
7.5.1 验证组件的封装
包是组织验证组件的理想方式:
// verification_components_pkg.sv
package verification_components_pkg;// 基础验证类型typedef enum {TRANS_READ,TRANS_WRITE,TRANS_BURST_READ,TRANS_BURST_WRITE} transaction_type_t;typedef enum {SEVERITY_INFO,SEVERITY_WARNING,SEVERITY_ERROR,SEVERITY_FATAL} severity_t;// 基础事务类virtual class base_transaction;static int transaction_count = 0;int id;real timestamp;transaction_type_t trans_type;function new(transaction_type_t t_type = TRANS_READ);id = transaction_count++;timestamp = $realtime;trans_type = t_type;endfunctionpure virtual function string to_string();pure virtual function bit compare(base_transaction other);pure virtual function base_transaction copy();endclass// 具体的内存事务类class memory_transaction extends base_transaction;logic [31:0] address;logic [31:0] data;logic [3:0] byte_enable;bit error;function new(logic [31:0] addr = 0,logic [31:0] d = 0,transaction_type_t t_type = TRANS_READ);super.new(t_type);address = addr;data = d;byte_enable = 4'hF;error = 0;endfunctionvirtual function string to_string();return $sformatf("[%d] %s @ 0x%h = 0x%h (BE: %h) %s",id, trans_type.name(), address, data, byte_enable,error ? "ERROR" : "OK");endfunctionvirtual function bit compare(base_transaction other);memory_transaction mem_other;if (!$cast(mem_other, other)) return 0;return (address == mem_other.address) &&(data == mem_other.data) &&(trans_type == mem_other.trans_type) &&(byte_enable == mem_other.byte_enable);endfunctionvirtual function base_transaction copy();memory_transaction new_trans = new(address, data, trans_type);new_trans.byte_enable = byte_enable;new_trans.error = error;return new_trans;endfunctionendclass// 驱动器基类virtual class base_driver #(type T = base_transaction);mailbox #(T) req_mb;mailbox #(T) rsp_mb;string name;bit active;function new(string n = "base_driver");name = n;req_mb = new();rsp_mb = new();active = 0;endfunctionpure virtual task drive_transaction(T trans);task run();T trans;active = 1;$display("[%s] Driver started", name);while (active) beginreq_mb.get(trans);$display("[%s] Driving: %s", name, trans.to_string());drive_transaction(trans);rsp_mb.put(trans);end$display("[%s] Driver stopped", name);endtasktask stop();active = 0;endtaskendclass// 内存驱动器class memory_driver extends base_driver #(memory_transaction);virtual memory_interface mem_if;function new(virtual memory_interface vif, string n = "memory_driver");super.new(n);mem_if = vif;endfunctionvirtual task drive_transaction(memory_transaction trans);// 驱动接口信号@(posedge mem_if.clk);mem_if.addr <= trans.address;mem_if.data <= trans.data;mem_if.byte_en <= trans.byte_enable;mem_if.valid <= 1'b1;case (trans.trans_type)TRANS_READ: mem_if.write <= 1'b0;TRANS_WRITE: mem_if.write <= 1'b1;default: mem_if.write <= 1'b0;endcase// 等待ready信号do begin@(posedge mem_if.clk);end while (!mem_if.ready);// 如果是读操作,获取数据if (trans.trans_type == TRANS_READ) begin@(posedge mem_if.clk);trans.data = mem_if.rdata;end// 清除控制信号mem_if.valid <= 1'b0;mem_if.write <= 1'b0;endtaskendclass// 监视器基类virtual class base_monitor #(type T = base_transaction);mailbox #(T) analysis_mb;string name;bit active;function new(string n = "base_monitor");name = n;analysis_mb = new();active = 0;endfunctionpure virtual task collect_transaction(ref T trans);task run();T trans;active = 1;$display("[%s] Monitor started", name);while (active) begincollect_transaction(trans);$display("[%s] Collected: %s", name, trans.to_string());analysis_mb.put(trans);end$display("[%s] Monitor stopped", name);endtasktask stop();active = 0;endtaskendclass// 内存监视器class memory_monitor extends base_monitor #(memory_transaction);virtual memory_interface mem_if;function new(virtual memory_interface vif, string n = "memory_monitor");super.new(n);mem_if = vif;endfunctionvirtual task collect_transaction(ref memory_transaction trans);// 等待有效事务do begin@(posedge mem_if.clk);end while (!(mem_if.valid && mem_if.ready));// 收集事务信息trans = new();trans.address = mem_if.addr;trans.byte_enable = mem_if.byte_en;if (mem_if.write) begintrans.trans_type = TRANS_WRITE;trans.data = mem_if.data;end else begintrans.trans_type = TRANS_READ;// 等待读数据@(posedge mem_if.clk);trans.data = mem_if.rdata;endendtaskendclass// 记分板class scoreboard #(type T = base_transaction);mailbox #(T) expected_mb;mailbox #(T) actual_mb;string name;int matches;int mismatches;function new(string n = "scoreboard");name = n;expected_mb = new();actual_mb = new();matches = 0;mismatches = 0;endfunctiontask run();T expected, actual;$display("[%s] Scoreboard started", name);forkforever beginexpected_mb.get(expected);actual_mb.get(actual);if (expected.compare(actual)) beginmatches++;$display("[%s] MATCH: %s", name, expected.to_string());end else beginmismatches++;$display("[%s] MISMATCH:", name);$display(" Expected: %s", expected.to_string());$display(" Actual: %s", actual.to_string());endendjoin_noneendtaskfunction void report();real pass_rate = 0.0;int total = matches + mismatches;if (total > 0) beginpass_rate = (real'(matches) / real'(total)) * 100.0;end$display("\n=== %s Report ===", name);$display("Total transactions: %d", total);$display("Matches: %d", matches);$display("Mismatches: %d", mismatches);$display("Pass rate: %.2f%%", pass_rate);endfunctionendclass// 测试环境class test_environment;memory_driver driver;memory_monitor monitor;scoreboard #(memory_transaction) sb;function new(virtual memory_interface vif);driver = new(vif, "mem_driver");monitor = new(vif, "mem_monitor");sb = new("mem_scoreboard");endfunctiontask run_test();$display("=== Starting Test Environment ===");// 启动所有组件forkdriver.run();monitor.run();sb.run();join_none// 连接监视器到记分板forkforever beginmemory_transaction trans;monitor.analysis_mb.get(trans);sb.actual_mb.put(trans);endjoin_none// 生成测试事务generate_test_transactions();// 等待测试完成#1000;// 停止所有组件driver.stop();monitor.stop();// 生成报告sb.report();endtasktask generate_test_transactions();memory_transaction trans;for (int i = 0; i < 10; i++) begin// 生成写事务trans = new(32'h1000 + i*4, $urandom(), TRANS_WRITE);driver.req_mb.put(trans);sb.expected_mb.put(trans.copy());// 生成读事务trans = new(32'h1000 + i*4, 0, TRANS_READ);driver.req_mb.put(trans);// 注意:读事务的期望数据需要从内存模型获取sb.expected_mb.put(trans.copy());endendtaskendclassendpackage : verification_components_pkg// 内存接口定义
interface memory_interface(input logic clk, input logic rst_n);logic [31:0] addr;logic [31:0] data;logic [31:0] rdata;logic [3:0] byte_en;logic valid;logic ready;logic write;
endinterface// 使用验证组件的测试
module verification_components_test;import verification_components_pkg::*;logic clk = 0;logic rst_n = 0;// 时钟生成always #5 clk = ~clk;// 复位生成initial beginrst_n = 0;#20 rst_n = 1;end// 内存接口实例memory_interface mem_if(clk, rst_n);// 简单的内存模型logic [31:0] memory[1024];always @(posedge clk) beginif (rst_n) beginmem_if.ready <= 1'b1; // 简化:总是readyif (mem_if.valid) beginif (mem_if.write) begin// 写操作memory[mem_if.addr[11:2]] <= mem_if.data;end else begin// 读操作mem_if.rdata <= memory[mem_if.addr[11:2]];endendend else beginmem_if.ready <= 1'b0;mem_if.rdata <= 32'h0;endend// 测试test_environment env;initial begin// 等待复位完成wait(rst_n);@(posedge clk);// 创建并运行测试环境env = new(mem_if);env.run_test();$finish;end
endmodule
7.1.2 SystemVerilog包的优势
SystemVerilog引入包(Package)机制解决了传统Verilog的问题:
SystemVerilog包的优势:
- 提供命名空间,避免命名冲突
- 支持封装和模块化设计
- 便于代码重用和维护
- 支持选择性导入
- 改善编译依赖管理
- 支持面向对象编程
// SystemVerilog包方式 - 解决方案// cpu_pkg.sv
package cpu_pkg;// CPU相关的定义parameter DATA_WIDTH = 32;parameter ADDR_WIDTH = 16;typedef logic [DATA_WIDTH-1:0] cpu_data_t;typedef logic [ADDR_WIDTH-1:0] cpu_addr_t;function cpu_data_t calculate_checksum(cpu_data_t data);// CPU特定的校验和计算return data ^ (data >> 16);endfunctionclass cpu_transaction;cpu_addr_t addr;cpu_data_t data;bit write;function new(cpu_addr_t a = 0, cpu_data_t d = 0, bit w = 0);addr = a;data = d;write = w;endfunctionendclass
endpackage// memory_pkg.sv
package memory_pkg;// 内存相关的定义parameter DATA_WIDTH = 64; // 不会与cpu_pkg冲突parameter ADDR_WIDTH = 20;typedef logic [DATA_WIDTH-1:0] mem_data_t;typedef logic [ADDR_WIDTH-1:0] mem_addr_t;function mem_data_t calculate_checksum(mem_data_t data);// 内存特定的校验和计算return data ^ (data >> 32) ^ (data >> 16);endfunctionclass memory_transaction;mem_addr_t addr;mem_data_t data;bit [7:0] byte_enable;function new(mem_addr_t a = 0, mem_data_t d = 0, bit [7:0] be = 8'hFF);addr = a;data = d;byte_enable = be;endfunctionendclass
endpackage// main.sv
module main;import cpu_pkg::*; // 导入CPU包import memory_pkg::*; // 导入内存包// 使用包中的类型和函数cpu_data_t cpu_data;mem_data_t mem_data;cpu_transaction cpu_trans;memory_transaction mem_trans;initial begincpu_data = 32'h12345678;mem_data = 64'h123456789ABCDEF0;// 明确调用不同包中的函数$display("CPU checksum: %h", cpu_pkg::calculate_checksum(cpu_data));$display("Memory checksum: %h", memory_pkg::calculate_checksum(mem_data));// 创建事务对象cpu_trans = new(16'h1000, cpu_data, 1);mem_trans = new(20'h80000, mem_data, 8'hF0);end
endmodule
7.1.3 包的作用域和可见性
SystemVerilog包提供了灵活的作用域控制:
// scope_demo_pkg.sv
package scope_demo_pkg;// 包级别的声明parameter int GLOBAL_PARAM = 100;// 类型定义typedef enum {RED, GREEN, BLUE} color_t;// 函数定义function int add_numbers(int a, int b);return a + b;endfunction// 类定义class base_class;protected int protected_var;local int local_var;int public_var;function new();protected_var = 10;local_var = 20;public_var = 30;endfunctionfunction void display();$display("Protected: %d, Local: %d, Public: %d", protected_var, local_var, public_var);endfunctionendclass
endpackage// 使用示例
module scope_test;// 方式1:完全限定名访问int result1 = scope_demo_pkg::add_numbers(10, 20);// 方式2:选择性导入import scope_demo_pkg::color_t;color_t my_color = RED;// 方式3:通配符导入import scope_demo_pkg::*;base_class obj;initial begin$display("Result1: %d", result1);$display("Color: %s", my_color.name());obj = new();obj.display();// 访问公共成员obj.public_var = 100;$display("Modified public_var: %d", obj.public_var);end
endmodule
7.2 包的定义和声明
7.2.1 基本包定义语法
包的定义使用package
和endpackage
关键字:
// basic_package_syntax.sv
package basic_pkg;// 包的内容// 1. 参数声明parameter int WIDTH = 32;parameter real FREQUENCY = 100.0;// 2. 类型定义typedef logic [WIDTH-1:0] data_t;typedef logic [$clog2(WIDTH)-1:0] index_t;// 3. 枚举类型typedef enum logic [1:0] {IDLE = 2'b00,ACTIVE = 2'b01,WAIT = 2'b10,ERROR = 2'b11} state_t;// 4. 结构体定义typedef struct packed {logic valid;logic ready;data_t data;index_t index;} packet_t;// 5. 联合体定义typedef union packed {data_t word;logic [3:0][7:0] bytes;logic [31:0][0:0] bits;} data_union_t;// 6. 常量定义const int MAX_SIZE = 1024;const string VERSION = "1.0.0";endpackage : basic_pkg // 可选的包名标识// 包的使用示例
module package_usage_demo;// 导入包import basic_pkg::*;// 使用包中定义的类型data_t my_data;state_t current_state;packet_t tx_packet, rx_packet;data_union_t data_converter;initial begin// 初始化current_state = IDLE;my_data = 32'hDEADBEEF;// 使用结构体tx_packet.valid = 1'b1;tx_packet.ready = 1'b1;tx_packet.data = my_data;tx_packet.index = 5;// 使用联合体data_converter.word = my_data;$display("Word: %h", data_converter.word);$display("Bytes: %h %h %h %h", data_converter.bytes[3], data_converter.bytes[2],data_converter.bytes[1], data_converter.bytes[0]);// 使用常量$display("Max size: %d, Version: %s", MAX_SIZE, VERSION);// 状态转换case (current_state)IDLE: begin$display("Current state: IDLE");current_state = ACTIVE;endACTIVE: begin$display("Current state: ACTIVE");current_state = WAIT;endWAIT: begin$display("Current state: WAIT");current_state = IDLE;endERROR: begin$display("Current state: ERROR");current_state = IDLE;endendcaseend
endmodule
7.2.2 包中的数据类型定义
包是定义和组织数据类型的理想场所:
// data_types_pkg.sv
package data_types_pkg;// ============================================// 基础数据类型定义// ============================================// 位宽参数parameter int DATA_WIDTH = 32;parameter int ADDR_WIDTH = 16;parameter int ID_WIDTH = 4;// 基础类型定义typedef logic [DATA_WIDTH-1:0] data_t;typedef logic [ADDR_WIDTH-1:0] addr_t;typedef logic [ID_WIDTH-1:0] id_t;typedef logic [DATA_WIDTH/8-1:0] strobe_t;// ============================================// 枚举类型定义// ============================================// 总线操作类型typedef enum logic [1:0] {READ_op = 2'b00,write_op = 2'b01,burst_read = 2'b10,burst_write = 2'b11} operation_t;// 响应类型typedef enum logic [1:0] {OKAY = 2'b00,EXOKAY = 2'b01,SLVERR = 2'b10,DECERR = 2'b11} response_t;// 突发类型typedef enum logic [1:0] {FIXED = 2'b00,INCR = 2'b01,WRAP = 2'b10,RESERVED = 2'b11} burst_t;// ============================================// 结构体定义// ============================================// 基础事务结构typedef struct packed {id_t id;addr_t addr;data_t data;strobe_t strobe;operation_t op;logic valid;logic ready;} transaction_t;// AXI4-Lite写地址通道typedef struct packed {addr_t awaddr;logic [2:0] awprot;logic awvalid;logic awready;} axi_aw_t;// AXI4-Lite写数据通道typedef struct packed {data_t wdata;strobe_t wstrb;logic wvalid;logic wready;} axi_w_t;// AXI4-Lite写响应通道typedef struct packed {response_t bresp;logic bvalid;logic bready;} axi_b_t;// AXI4-Lite读地址通道typedef struct packed {addr_t araddr;logic [2:0] arprot;logic arvalid;logic arready;} axi_ar_t;// AXI4-Lite读数据通道typedef struct packed {data_t rdata;response_t rresp;logic rvalid;logic rready;} axi_r_t;// 完整的AXI4-Lite接口typedef struct {axi_aw_t aw;axi_w_t w;axi_b_t b;axi_ar_t ar;axi_r_t r;} axi4_lite_t;// ============================================// 联合体定义// ============================================// 数据格式转换联合体typedef union packed {data_t word;struct packed {logic [15:0] high;logic [15:0] low;} half_words;logic [3:0][7:0] bytes;logic [31:0][0:0] bits;} data_converter_t;// 地址格式联合体typedef union packed {addr_t full_addr;struct packed {logic [7:0] page;logic [7:0] offset;} paged;struct packed {logic [11:0] tag;logic [3:0] index;} cached;} addr_converter_t;// ============================================// 数组类型定义// ============================================// 定宽数组类型typedef data_t data_array_t[16];typedef addr_t addr_array_t[8];// 动态数组类型typedef data_t data_queue_t[$];typedef transaction_t trans_queue_t[$];// 关联数组类型typedef data_t data_assoc_t[addr_t];typedef string string_assoc_t[int];endpackage : data_types_pkg// 使用示例
module data_types_demo;import data_types_pkg::*;// 声明变量transaction_t trans;axi4_lite_t axi_if;data_converter_t converter;addr_converter_t addr_conv;// 数组变量data_array_t fixed_array;data_queue_t dynamic_queue;data_assoc_t assoc_array;initial begin// 初始化事务trans.id = 4'h5;trans.addr = 16'h1000;trans.data = 32'hDEADBEEF;trans.strobe = 4'hF;trans.op = write_op;trans.valid = 1'b1;trans.ready = 1'b0;$display("Transaction: ID=%h, Addr=%h, Data=%h, Op=%s", trans.id, trans.addr, trans.data, trans.op.name());// 使用数据转换器converter.word = trans.data;$display("Data conversion:");$display(" Word: %h", converter.word);$display(" High: %h, Low: %h", converter.half_words.high, converter.half_words.low);$display(" Bytes: %h %h %h %h", converter.bytes[3], converter.bytes[2], converter.bytes[1], converter.bytes[0]);// 使用地址转换器addr_conv.full_addr = trans.addr;$display("Address conversion:");$display(" Full: %h", addr_conv.full_addr);$display(" Page: %h, Offset: %h", addr_conv.paged.page, addr_conv.paged.offset);$display(" Tag: %h, Index: %h", addr_conv.cached.tag, addr_conv.cached.index);// 使用数组for (int i = 0; i < 16; i++) beginfixed_array[i] = i * i;enddynamic_queue.push_back(32'h11111111);dynamic_queue.push_back(32'h22222222);dynamic_queue.push_back(32'h33333333);assoc_array[16'h1000] = 32'hAAAA;assoc_array[16'h2000] = 32'hBBBB;assoc_array[16'h3000] = 32'hCCCC;$display("Array contents:");$display(" Fixed[5] = %h", fixed_array[5]);$display(" Queue size = %d", dynamic_queue.size());$display(" Assoc[0x2000] = %h", assoc_array[16'h2000]);end
endmodule
7.2.3 包中的函数和任务
包可以包含函数和任务的定义,提供可重用的功能:
// functions_tasks_pkg.sv
package functions_tasks_pkg;import data_types_pkg::*; // 导入数据类型// ============================================// 实用函数定义// ============================================// 计算校验和函数function automatic data_t calculate_checksum(data_t data);data_t checksum = 0;for (int i = 0; i < DATA_WIDTH; i += 8) beginchecksum ^= (data >> i) & 8'hFF;endreturn checksum;endfunction// 位反转函数function automatic data_t bit_reverse(data_t data);data_t reversed = 0;for (int i = 0; i < DATA_WIDTH; i++) beginreversed[i] = data[DATA_WIDTH-1-i];endreturn reversed;endfunction// 字节交换函数function automatic data_t byte_swap(data_t data);data_t swapped;for (int i = 0; i < DATA_WIDTH/8; i++) beginswapped[i*8 +: 8] = data[(DATA_WIDTH/8-1-i)*8 +: 8];endreturn swapped;endfunction// 奇偶校验函数function automatic logic parity_check(data_t data);logic parity = 0;for (int i = 0; i < DATA_WIDTH; i++) beginparity ^= data[i];endreturn parity;endfunction// 计算前导零个数function automatic int count_leading_zeros(data_t data);int count = 0;for (int i = DATA_WIDTH-1; i >= 0; i--) beginif (data[i] == 1'b0)count++;elsebreak;endreturn count;endfunction// 地址对齐检查function automatic logic is_aligned(addr_t addr, int alignment);return (addr % alignment) == 0;endfunction// 地址范围检查function automatic logic addr_in_range(addr_t addr, addr_t base, addr_t size);return (addr >= base) && (addr < (base + size));endfunction// ============================================// 事务处理函数// ============================================// 创建读事务function automatic transaction_t create_read_transaction(id_t id, addr_t addr);transaction_t trans;trans.id = id;trans.addr = addr;trans.data = 0;trans.strobe = '1;trans.op = read_op;trans.valid = 1'b1;trans.ready = 1'b0;return trans;endfunction// 创建写事务function automatic transaction_t create_write_transaction(id_t id, addr_t addr, data_t data, strobe_t strobe = '1);transaction_t trans;trans.id = id;trans.addr = addr;trans.data = data;trans.strobe = strobe;trans.op = write_op;trans.valid = 1'b1;trans.ready = 1'b0;return trans;endfunction// 事务比较函数function automatic logic compare_transactions(transaction_t trans1, transaction_t trans2);return (trans1.id == trans2.id) &&(trans1.addr == trans2.addr) &&(trans1.data == trans2.data) &&(trans1.strobe == trans2.strobe) &&(trans1.op == trans2.op);endfunction// 事务转字符串函数function automatic string transaction_to_string(transaction_t trans);string op_str;case (trans.op)read_op: op_str = "READ";write_op: op_str = "WRITE";burst_read: op_str = "BURST_READ";burst_write: op_str = "BURST_WRITE";endcasereturn $sformatf("[ID:%h] %s @ %h = %h (strb:%h) [V:%b R:%b]",trans.id, op_str, trans.addr, trans.data, trans.strobe, trans.valid, trans.ready);endfunction// ============================================// 任务定义// ============================================// 延迟任务task automatic wait_cycles(int cycles);repeat(cycles) @(posedge clk);endtask// 随机延迟任务task automatic random_delay(int min_cycles, int max_cycles);int delay = $urandom_range(min_cycles, max_cycles);wait_cycles(delay);endtask// 打印事务任务task automatic print_transaction(transaction_t trans, string prefix = "");$display("%s%s", prefix, transaction_to_string(trans));endtask// 验证事务任务task automatic verify_transaction(transaction_t expected, transaction_t actual, string test_name = "Transaction");if (compare_transactions(expected, actual)) begin$display("[PASS] %s verification passed", test_name);end else begin$display("[FAIL] %s verification failed", test_name);$display(" Expected: %s", transaction_to_string(expected));$display(" Actual: %s", transaction_to_string(actual));endendtask// ============================================// 调试和诊断函数// ============================================// 内存转储函数function automatic void dump_memory(data_t memory[], addr_t start_addr, int count);$display("Memory dump starting at address %h:", start_addr);for (int i = 0; i < count && i < memory.size(); i++) begin$display(" [%h]: %h", start_addr + i*4, memory[i]);endendfunction// 统计函数function automatic void print_statistics(int read_count, int write_count, int error_count);int total = read_count + write_count;$display("=== Transaction Statistics ===");$display(" Total transactions: %d", total);$display(" Read transactions: %d (%.1f%%)", read_count, total > 0 ? (real'(read_count)/total)*100.0 : 0.0);$display(" Write transactions: %d (%.1f%%)", write_count, total > 0 ? (real'(write_count)/total)*100.0 : 0.0);$display(" Error count: %d", error_count);if (total > 0) begin$display(" Error rate: %.2f%%", (real'(error_count)/total)*100.0);endendfunctionendpackage : functions_tasks_pkg// 使用示例
module functions_tasks_demo;import data_types_pkg::*;import functions_tasks_pkg::*;// 测试数据data_t test_data = 32'h12345678;transaction_t trans1, trans2;data_t memory[1024];// 统计变量int read_count = 0;int write_count = 0;int error_count = 0;initial begin$display("=== Functions and Tasks Demo ===");// 测试实用函数$display("\n--- Utility Functions Test ---");$display("Original data: %h", test_data);$display("Checksum: %h", calculate_checksum(test_data));$display("Bit reversed: %h", bit_reverse(test_data));$display("Byte swapped: %h", byte_swap(test_data));$display("Parity: %b", parity_check(test_data));$display("Leading zeros: %d", count_leading_zeros(test_data));// 测试地址函数$display("\n--- Address Functions Test ---");$display("Address 0x1000 aligned to 4: %b", is_aligned(16'h1000, 4));$display("Address 0x1002 aligned to 4: %b", is_aligned(16'h1002, 4));$display("Address 0x1500 in range [0x1000, 0x2000): %b", addr_in_range(16'h1500, 16'h1000, 16'h1000));// 测试事务函数$display("\n--- Transaction Functions Test ---");trans1 = create_read_transaction(4'h1, 16'h1000);trans2 = create_write_transaction(4'h2, 16'h2000, 32'hDEADBEEF, 4'hF);print_transaction(trans1, "Read: ");print_transaction(trans2, "Write: ");// 事务比较transaction_t trans3 = trans1;verify_transaction(trans1, trans3, "Read transaction copy");verify_transaction(trans1, trans2, "Different transactions");// 初始化内存for (int i = 0; i < 10; i++) beginmemory[i] = i * 16 + $urandom_range(0, 15);end// 内存转储$display("\n--- Memory Dump ---");dump_memory(memory, 16'h0000, 10);// 模拟一些事务统计read_count = 150;write_count = 75;error_count = 3;$display("\n--- Statistics ---");print_statistics(read_count, write_count, error_count);end
endmodule
7.2.4 包中的参数和常量
包中可以定义参数和常量,提供配置和常用值:
// constants_pkg.sv
package constants_pkg;// ============================================// 系统级常量// ============================================// 版本信息const string VERSION = "2.1.0";const string BUILD_DATE = "2024-01-15";const int VERSION_MAJOR = 2;const int VERSION_MINOR = 1;const int VERSION_PATCH = 0;// 系统配置parameter int SYSTEM_CLOCK_FREQ = 100_000_000; // 100MHzparameter real SYSTEM_PERIOD = 10.0; // 10nsparameter int RESET_CYCLES = 10;// ============================================// 总线配置常量// ============================================// AXI4配置parameter int AXI_DATA_WIDTH = 32;parameter int AXI_ADDR_WIDTH = 32;parameter int AXI_ID_WIDTH = 4;parameter int AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8;// AXI4突发配置parameter int AXI_MAX_BURST_LEN = 256;parameter int AXI_MAX_OUTSTANDING = 16;// 超时配置parameter int TIMEOUT_CYCLES = 1000;parameter real TIMEOUT_NS = TIMEOUT_CYCLES * SYSTEM_PERIOD;// ============================================// 内存配置常量// ============================================// 内存大小parameter int MEMORY_SIZE = 1024 * 1024; // 1MBparameter int CACHE_SIZE = 32 * 1024; // 32KBparameter int CACHE_LINE_SIZE = 64; // 64 bytesparameter int CACHE_WAYS = 4; // 4-way associative// 内存地址映射parameter logic [31:0] ROM_BASE_ADDR = 32'h0000_0000;parameter logic [31:0] ROM_SIZE = 32'h0010_0000; // 1MBparameter logic [31:0] RAM_BASE_ADDR = 32'h2000_0000;parameter logic [31:0] RAM_SIZE = 32'h0020_0000; // 2MBparameter logic [31:0] PERIPH_BASE_ADDR = 32'h4000_0000;parameter logic [31:0] PERIPH_SIZE = 32'h1000_0000; // 256MB// ============================================// 协议常量// ============================================// AXI响应类型const logic [1:0] AXI_RESP_OKAY = 2'b00;const logic [1:0] AXI_RESP_EXOKAY = 2'b01;const logic [1:0] AXI_RESP_SLVERR = 2'b10;const logic [1:0] AXI_RESP_DECERR = 2'b11;// AXI突发类型const logic [1:0] AXI_BURST_FIXED = 2'b00;const logic [1:0] AXI_BURST_INCR = 2'b01;const logic [1:0] AXI_BURST_WRAP = 2'b10;// AXI大小编码const logic [2:0] AXI_SIZE_1B = 3'b000;const logic [2:0] AXI_SIZE_2B = 3'b001;const logic [2:0] AXI_SIZE_4B = 3'b010;const logic [2:0] AXI_SIZE_8B = 3'b011;const logic [2:0] AXI_SIZE_16B = 3'b100;const logic [2:0] AXI_SIZE_32B = 3'b101;const logic [2:0] AXI_SIZE_64B = 3'b110;const logic [2:0] AXI_SIZE_128B = 3'b111;// ============================================// 测试和调试常量// ============================================// 测试模式parameter bit ENABLE_ASSERTIONS = 1;parameter bit ENABLE_COVERAGE = 1;parameter bit ENABLE_DEBUG_PRINTS = 1;parameter bit ENABLE_WAVEFORM_DUMP = 1;// 测试数据模式const logic [31:0] TEST_PATTERN_0 = 32'h0000_0000;const logic [31:0] TEST_PATTERN_1 = 32'hFFFF_FFFF;const logic [31:0] TEST_PATTERN_2 = 32'h5555_5555;const logic [31:0] TEST_PATTERN_3 = 32'hAAAA_AAAA;const logic [31:0] TEST_PATTERN_4 = 32'h1234_5678;const logic [31:0] TEST_PATTERN_5 = 32'hDEAD_BEEF;const logic [31:0] TEST_PATTERN_6 = 32'hCAFE_BABE;const logic [31:0] TEST_PATTERN_7 = 32'h8765_4321;// 测试模式数组const logic [31:0] TEST_PATTERNS[8] = '{TEST_PATTERN_0, TEST_PATTERN_1, TEST_PATTERN_2, TEST_PATTERN_3,TEST_PATTERN_4, TEST_PATTERN_5, TEST_PATTERN_6, TEST_PATTERN_7};// ============================================// 计算常量(编译时计算)// ============================================// 地址位宽计算parameter int ROM_ADDR_BITS = $clog2(ROM_SIZE);parameter int RAM_ADDR_BITS = $clog2(RAM_SIZE);parameter int CACHE_INDEX_BITS = $clog2(CACHE_SIZE / CACHE_LINE_SIZE / CACHE_WAYS);parameter int CACHE_OFFSET_BITS = $clog2(CACHE_LINE_SIZE);parameter int CACHE_TAG_BITS = 32 - CACHE_INDEX_BITS - CACHE_OFFSET_BITS;// 时钟周期计算parameter int CYCLES_PER_US = SYSTEM_CLOCK_FREQ / 1_000_000;parameter int CYCLES_PER_MS = SYSTEM_CLOCK_FREQ / 1_000;parameter int CYCLES_PER_SEC = SYSTEM_CLOCK_FREQ;// ============================================// 字符串常量// ============================================// 日志级别const string LOG_ERROR = "ERROR";const string LOG_WARNING = "WARNING";const string LOG_INFO = "INFO";const string LOG_DEBUG = "DEBUG";const string LOG_TRACE = "TRACE";// 组件名称const string COMP_CPU = "CPU";const string COMP_MEMORY = "MEMORY";const string COMP_CACHE = "CACHE";const string COMP_BUS = "BUS";const string COMP_PERIPH = "PERIPHERAL";// ============================================// 实用函数(基于常量)// ============================================// 检查地址是否在ROM范围内function automatic bit is_rom_address(logic [31:0] addr);return (addr >= ROM_BASE_ADDR) && (addr < (ROM_BASE_ADDR + ROM_SIZE));endfunction// 检查地址是否在RAM范围内function automatic bit is_ram_address(logic [31:0] addr);return (addr >= RAM_BASE_ADDR) && (addr < (RAM_BASE_ADDR + RAM_SIZE));endfunction// 检查地址是否在外设范围内function automatic bit is_peripheral_address(logic [31:0] addr);return (addr >= PERIPH_BASE_ADDR) && (addr < (PERIPH_BASE_ADDR + PERIPH_SIZE));endfunction// 获取缓存索引function automatic logic [CACHE_INDEX_BITS-1:0] get_cache_index(logic [31:0] addr);return addr[CACHE_OFFSET_BITS +: CACHE_INDEX_BITS];endfunction// 获取缓存标签function automatic logic [CACHE_TAG_BITS-1:0] get_cache_tag(logic [31:0] addr);return addr[CACHE_OFFSET_BITS + CACHE_INDEX_BITS +: CACHE_TAG_BITS];endfunction// 获取缓存偏移function automatic logic [CACHE_OFFSET_BITS-1:0] get_cache_offset(logic [31:0] addr);return addr[CACHE_OFFSET_BITS-1:0];endfunction// 时间转换函数function automatic int ns_to_cycles(real ns);return int'(ns / SYSTEM_PERIOD + 0.5);endfunctionfunction automatic real cycles_to_ns(int cycles);return real'(cycles) * SYSTEM_PERIOD;endfunctionendpackage : constants_pkg// 使用示例
module constants_demo;import constants_pkg::*;logic [31:0] test_addresses[] = {32'h0000_1000, // ROM32'h2000_5000, // RAM32'h4000_A000, // Peripheral32'h8000_0000 // Invalid};initial begin$display("=== Constants Package Demo ===");// 显示版本信息$display("\n--- Version Information ---");$display("Version: %s (Build: %s)", VERSION, BUILD_DATE);$display("Version components: %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);// 显示系统配置$display("\n--- System Configuration ---");$display("Clock frequency: %d Hz", SYSTEM_CLOCK_FREQ);$display("Clock period: %.1f ns", SYSTEM_PERIOD);$display("Reset cycles: %d", RESET_CYCLES);// 显示内存配置$display("\n--- Memory Configuration ---");$display("ROM: 0x%h - 0x%h (%d KB)", ROM_BASE_ADDR, ROM_BASE_ADDR + ROM_SIZE - 1, ROM_SIZE/1024);$display("RAM: 0x%h - 0x%h (%d KB)", RAM_BASE_ADDR, RAM_BASE_ADDR + RAM_SIZE - 1, RAM_SIZE/1024);$display("Peripherals: 0x%h - 0x%h (%d MB)", PERIPH_BASE_ADDR, PERIPH_BASE_ADDR + PERIPH_SIZE - 1, PERIPH_SIZE/(1024*1024));// 显示缓存配置$display("\n--- Cache Configuration ---");$display("Cache size: %d KB", CACHE_SIZE/1024);$display("Cache line size: %d bytes", CACHE_LINE_SIZE);$display("Cache ways: %d", CACHE_WAYS);$display("Index bits: %d, Tag bits: %d, Offset bits: %d", CACHE_INDEX_BITS, CACHE_TAG_BITS, CACHE_OFFSET_BITS);// 测试地址分类$display("\n--- Address Classification ---");foreach (test_addresses[i]) beginlogic [31:0] addr = test_addresses[i];string addr_type = "Unknown";if (is_rom_address(addr)) addr_type = "ROM";else if (is_ram_address(addr)) addr_type = "RAM";else if (is_peripheral_address(addr)) addr_type = "Peripheral";$display("Address 0x%h: %s", addr, addr_type);if (is_ram_address(addr)) begin$display(" Cache - Index: %d, Tag: 0x%h, Offset: %d",get_cache_index(addr), get_cache_tag(addr), get_cache_offset(addr));endend// 测试时间转换$display("\n--- Time Conversion ---");$display("100 ns = %d cycles", ns_to_cycles(100.0));$display("1000 cycles = %.1f ns", cycles_to_ns(1000));$display("1 us = %d cycles", CYCLES_PER_US);$display("1 ms = %d cycles", CYCLES_PER_MS);// 显示测试模式$display("\n--- Test Patterns ---");for (int i = 0; i < 8; i++) begin$display("Pattern[%d]: 0x%h", i, TEST_PATTERNS[i]);end// 显示AXI常量$display("\n--- AXI Configuration ---");$display("Data width: %d bits", AXI_DATA_WIDTH);$display("Address width: %d bits", AXI_ADDR_WIDTH);$display("ID width: %d bits", AXI_ID_WIDTH);$display("Strobe width: %d bits", AXI_STRB_WIDTH);$display("Max burst length: %d", AXI_MAX_BURST_LEN);$display("Max outstanding: %d", AXI_MAX_OUTSTANDING);end
endmodule
7.3 包的导入机制
7.3.1 import语句的使用
SystemVerilog提供了灵活的包导入机制:
// import_demo_pkg.sv
package import_demo_pkg;// 类型定义typedef enum {RED, GREEN, BLUE, YELLOW} color_t;typedef struct packed {logic [7:0] r, g, b;} rgb_t;// 常量定义const int MAX_COUNT = 100;const string PACKAGE_NAME = "import_demo_pkg";// 函数定义function automatic rgb_t color_to_rgb(color_t color);case (color)RED: return '{8'hFF, 8'h00, 8'h00};GREEN: return '{8'h00, 8'hFF, 8'h00};BLUE: return '{8'h00, 8'h00, 8'hFF};YELLOW: return '{8'hFF, 8'hFF, 8'h00};endcaseendfunctionfunction automatic string rgb_to_string(rgb_t rgb);return $sformatf("RGB(%d,%d,%d)", rgb.r, rgb.g, rgb.b);endfunction// 类定义class pixel_class;color_t color;rgb_t rgb;function new(color_t c = RED);color = c;rgb = color_to_rgb(c);endfunctionfunction void set_color(color_t c);color = c;rgb = color_to_rgb(c);endfunctionfunction string to_string();return $sformatf("%s -> %s", color.name(), rgb_to_string(rgb));endfunctionendclassendpackage : import_demo_pkg// ============================================
// 导入方式示例
// ============================================// 方式1:完全限定名访问(不使用import)
module qualified_access_demo;// 直接使用包名限定import_demo_pkg::color_t my_color;import_demo_pkg::rgb_t my_rgb;import_demo_pkg::pixel_class pixel;initial begin$display("=== Qualified Access Demo ===");// 使用完全限定名my_color = import_demo_pkg::RED;my_rgb = import_demo_pkg::color_to_rgb(my_color);$display("Color: %s", my_color.name());$display("RGB: %s", import_demo_pkg::rgb_to_string(my_rgb));$display("Max count: %d", import_demo_pkg::MAX_COUNT);$display("Package name: %s", import_demo_pkg::PACKAGE_NAME);// 创建类对象pixel = new(import_demo_pkg::BLUE);$display("Pixel: %s", pixel.to_string());end
endmodule// 方式2:选择性导入
module selective_import_demo;// 只导入需要的标识符import import_demo_pkg::color_t;import import_demo_pkg::rgb_t;import import_demo_pkg::color_to_rgb;import import_demo_pkg::MAX_COUNT;color_t my_color;rgb_t my_rgb;initial begin$display("\n=== Selective Import Demo ===");// 可以直接使用导入的标识符my_color = GREEN;my_rgb = color_to_rgb(my_color);$display("Color: %s", my_color.name());$display("Max count: %d", MAX_COUNT);// 未导入的标识符仍需完全限定名$display("RGB: %s", import_demo_pkg::rgb_to_string(my_rgb));$display("Package name: %s", import_demo_pkg::PACKAGE_NAME);end
endmodule// 方式3:通配符导入
module wildcard_import_demo;// 导入包中的所有标识符import import_demo_pkg::*;color_t my_color;rgb_t my_rgb;pixel_class pixel;initial begin$display("\n=== Wildcard Import Demo ===");// 可以直接使用所有导入的标识符my_color = YELLOW;my_rgb = color_to_rgb(my_color);$display("Color: %s", my_color.name());$display("RGB: %s", rgb_to_string(my_rgb));$display("Max count: %d", MAX_COUNT);$display("Package name: %s", PACKAGE_NAME);// 创建和使用类对象pixel = new(BLUE);$display("Initial pixel: %s", pixel.to_string());pixel.set_color(RED);$display("Modified pixel: %s", pixel.to_string());end
endmodule
7.3.2 通配符导入
通配符导入提供了便利,但需要注意命名冲突:
// 定义两个可能冲突的包
package package_a;typedef enum {STATE_IDLE, STATE_ACTIVE, STATE_DONE} state_t;const int TIMEOUT = 100;function automatic string get_state_name(state_t state);return state.name();endfunctionclass transaction_a;state_t state;int data;function new(state_t s = STATE_IDLE, int d = 0);state = s;data = d;endfunctionendclass
endpackagepackage package_b;typedef enum {STATE_RESET, STATE_IDLE, STATE_BUSY} state_t; // 部分重名const int TIMEOUT = 200; // 重名常量function automatic string get_state_name(state_t state);return $sformatf("B_%s", state.name());endfunctionclass transaction_b;state_t state;string name;function new(state_t s = STATE_RESET, string n = "default");state = s;name = n;endfunctionendclass
endpackage// 演示命名冲突和解决方案
module wildcard_conflict_demo;// 问题:同时导入两个包会导致冲突// import package_a::*; // 这会导致冲突// import package_b::*; // state_t, TIMEOUT, get_state_name重名// 解决方案1:使用完全限定名package_a::state_t state_a;package_b::state_t state_b;package_a::transaction_a trans_a;package_b::transaction_b trans_b;initial begin$display("=== Wildcard Conflict Resolution Demo ===");// 使用完全限定名避免冲突state_a = package_a::STATE_ACTIVE;state_b = package_b::STATE_BUSY;$display("Package A state: %s", package_a::get_state_name(state_a));$display("Package B state: %s", package_b::get_state_name(state_b));$display("Package A timeout: %d", package_a::TIMEOUT);$display("Package B timeout: %d", package_b::TIMEOUT);// 创建对象trans_a = new(package_a::STATE_DONE, 42);trans_b = new(package_b::STATE_IDLE, "test_transaction");$display("Transaction A: state=%s, data=%d", package_a::get_state_name(trans_a.state), trans_a.data);$display("Transaction B: state=%s, name=%s", package_b::get_state_name(trans_b.state), trans_b.name);end
endmodule// 解决方案3:使用局部作用域
module local_scope_resolution;initial begin$display("\n=== Local Scope Resolution Demo ===");// 在局部作用域中使用不同的包begin : package_a_scopeimport package_a::*;state_t state = STATE_ACTIVE;transaction_a trans = new(STATE_DONE, 100);$display("Package A - State: %s, Timeout: %d", get_state_name(state), TIMEOUT);endbegin : package_b_scopeimport package_b::*;state_t state = STATE_BUSY;transaction_b trans = new(STATE_IDLE, "local_test");$display("Package B - State: %s, Timeout: %d", get_state_name(state), TIMEOUT);endend
endmodule
7.3.3 选择性导入
选择性导入允许精确控制导入的标识符:
// utility_pkg.sv - 一个包含多种实用工具的包
package utility_pkg;// 数学函数function automatic int abs(int value);return (value < 0) ? -value : value;endfunctionfunction automatic int max(int a, int b);return (a > b) ? a : b;endfunctionfunction automatic int min(int a, int b);return (a < b) ? a : b;endfunctionfunction automatic real sqrt_approx(real x);// 简单的平方根近似real guess = x / 2.0;for (int i = 0; i < 10; i++) beginguess = (guess + x / guess) / 2.0;endreturn guess;endfunction// 字符串函数function automatic string to_upper(string str);string result = "";for (int i = 0; i < str.len(); i++) beginbyte c = str[i];if (c >= "a" && c <= "z") beginc = c - "a" + "A";endresult = {result, string'(c)};endreturn result;endfunctionfunction automatic string to_lower(string str);string result = "";for (int i = 0; i < str.len(); i++) beginbyte c = str[i];if (c >= "A" && c <= "Z") beginc = c - "A" + "a";endresult = {result, string'(c)};endreturn result;endfunctionfunction automatic string reverse_string(string str);string result = "";for (int i = str.len() - 1; i >= 0; i--) beginresult = {result, string'(str[i])};endreturn result;endfunction// 位操作函数function automatic int count_ones(logic [31:0] value);int count = 0;for (int i = 0; i < 32; i++) beginif (value[i]) count++;endreturn count;endfunctionfunction automatic logic [31:0] bit_reverse(logic [31:0] value);logic [31:0] result = 0;for (int i = 0; i < 32; i++) beginresult[i] = value[31-i];endreturn result;endfunction// 数组操作函数function automatic int array_sum(int arr[]);int sum = 0;foreach (arr[i]) sum += arr[i];return sum;endfunctionfunction automatic real array_average(int arr[]);if (arr.size() == 0) return 0.0;return real'(array_sum(arr)) / real'(arr.size());endfunction// 类型定义typedef enum {LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG} log_level_t;// 日志类class logger;static log_level_t current_level = LOG_INFO;static function void set_level(log_level_t level);current_level = level;endfunctionstatic function void log(log_level_t level, string message);if (level <= current_level) beginstring level_str;case (level)LOG_ERROR: level_str = "ERROR";LOG_WARN: level_str = "WARN ";LOG_INFO: level_str = "INFO ";LOG_DEBUG: level_str = "DEBUG";endcase$display("[%s] %s", level_str, message);endendfunctionendclassendpackage : utility_pkg// 选择性导入示例
module selective_import_demo;// 只导入需要的数学函数import utility_pkg::abs;import utility_pkg::max;import utility_pkg::min;// 只导入需要的字符串函数import utility_pkg::to_upper;import utility_pkg::reverse_string;// 导入日志相关import utility_pkg::log_level_t;import utility_pkg::logger;int test_values[] = '{-5, 10, -3, 7, 0, -12, 8};string test_string = "Hello SystemVerilog";initial begin$display("=== Selective Import Demo ===");// 使用导入的数学函数$display("\n--- Math Functions ---");foreach (test_values[i]) beginint val = test_values[i];$display("abs(%d) = %d", val, abs(val));endint max_val = max(max(test_values[0], test_values[1]), test_values[2]);int min_val = min(min(test_values[0], test_values[1]), test_values[2]);$display("max of first 3: %d, min of first 3: %d", max_val, min_val);// 使用导入的字符串函数$display("\n--- String Functions ---");$display("Original: %s", test_string);$display("Upper: %s", to_upper(test_string));$display("Reversed: %s", reverse_string(test_string));// 未导入的函数需要完全限定名$display("Lower: %s", utility_pkg::to_lower(test_string));// 使用导入的日志系统$display("\n--- Logging System ---");logger::set_level(LOG_DEBUG);logger::log(LOG_ERROR, "This is an error message");logger::log(LOG_WARN, "This is a warning message");logger::log(LOG_INFO, "This is an info message");logger::log(LOG_DEBUG, "This is a debug message");// 未导入的函数需要完全限定名$display("\n--- Non-imported Functions ---");logic [31:0] test_bits = 32'b10101010110011001111000011110000;$display("Bit count: %d", utility_pkg::count_ones(test_bits));$display("Bit reverse: %b", utility_pkg::bit_reverse(test_bits));int arr[] = '{1, 2, 3, 4, 5};$display("Array sum: %d", utility_pkg::array_sum(arr));$display("Array average: %.2f", utility_pkg::array_average(arr));end
endmodule
7.3.4 导入的作用域
导入语句的作用域规则很重要:
// scope_test_pkg.sv
package scope_test_pkg;typedef enum {ALPHA, BETA, GAMMA} greek_t;const int MAGIC_NUMBER = 42;function automatic string greek_to_string(greek_t g);return g.name();endfunctionclass scope_class;greek_t value;function new(greek_t v = ALPHA);value = v;endfunctionfunction string to_string();return $sformatf("scope_class(%s)", greek_to_string(value));endfunctionendclass
endpackage// 全局作用域导入
import scope_test_pkg::greek_t; // 全局导入
import scope_test_pkg::MAGIC_NUMBER;module scope_demo;// 全局导入的标识符可以直接使用greek_t global_greek = ALPHA; // 错误!ALPHA未全局导入// 正确的方式:greek_t global_greek = scope_test_pkg::ALPHA;// 模块级导入import scope_test_pkg::greek_to_string;import scope_test_pkg::scope_class;initial begin$display("=== Import Scope Demo ===");// 使用全局导入的类型$display("Magic number: %d", MAGIC_NUMBER);$display("Global greek: %s", scope_test_pkg::greek_to_string(global_greek));// 使用模块级导入的函数和类scope_class obj = new(scope_test_pkg::BETA);$display("Object: %s", obj.to_string());// 局部作用域导入begin : local_scopeimport scope_test_pkg::*; // 局部通配符导入greek_t local_greek = GAMMA; // 现在可以直接使用scope_class local_obj = new(BETA);$display("Local greek: %s", greek_to_string(local_greek));$display("Local object: %s", local_obj.to_string());end// 局部作用域外,通配符导入不可见// greek_t another_greek = GAMMA; // 错误!GAMMA不可见// 函数内导入test_function_import();// 任务内导入test_task_import();endfunction void test_function_import();import scope_test_pkg::ALPHA, scope_test_pkg::BETA;greek_t func_greek = ALPHA; // 函数内可以使用$display("Function greek: %s", greek_to_string(func_greek));// 嵌套块内的导入beginimport scope_test_pkg::GAMMA;greek_t nested_greek = GAMMA;$display("Nested greek: %s", greek_to_string(nested_greek));end// 嵌套块外,GAMMA不可见// greek_t another = GAMMA; // 错误!endfunctiontask test_task_import();// 任务级导入import scope_test_pkg::*;greek_t task_greek = BETA;scope_class task_obj = new(GAMMA);$display("Task greek: %s", greek_to_string(task_greek));$display("Task object: %s", task_obj.to_string());// 在任务中调用其他任务nested_task();endtasktask nested_task();// 这里看不到test_task_import中的导入// greek_t nested_greek = ALPHA; // 错误!// 需要重新导入或使用完全限定名scope_test_pkg::greek_t nested_greek = scope_test_pkg::ALPHA;$display("Nested task greek: %s", scope_test_pkg::greek_to_string(nested_greek));endtaskendmodule// 演示不同模块中的导入作用域
module another_module;// 全局导入仍然可见greek_t module_greek = scope_test_pkg::BETA;initial begin$display("\n=== Another Module Demo ===");$display("Magic number in another module: %d", MAGIC_NUMBER);$display("Module greek: %s", scope_test_pkg::greek_to_string(module_greek));// 但是scope_demo模块中的导入不可见// scope_class obj; // 错误!scope_class未导入// 需要重新导入import scope_test_pkg::scope_class;scope_class obj = new(scope_test_pkg::GAMMA);$display("Another module object: %s", obj.to_string());end
endmodule
7.4 包的高级特性
7.4.1 包的嵌套和依赖
SystemVerilog支持包之间的依赖关系:
// base_types_pkg.sv - 基础类型包
package base_types_pkg;// 基础数据类型parameter int DATA_WIDTH = 32;parameter int ADDR_WIDTH = 16;typedef logic [DATA_WIDTH-1:0] data_t;typedef logic [ADDR_WIDTH-1:0] addr_t;typedef logic [DATA_WIDTH/8-1:0] strobe_t;// 基础枚举typedef enum logic [1:0] {OP_READ = 2'b00,OP_WRITE = 2'b01,OP_BURST = 2'b10,OP_RESERVED = 2'b11} operation_t;// 基础结构体typedef struct packed {addr_t address;data_t data;strobe_t strobe;operation_t operation;logic valid;logic ready;} base_transaction_t;// 基础函数function automatic string op_to_string(operation_t op);case (op)OP_READ: return "READ";OP_WRITE: return "WRITE";OP_BURST: return "BURST";OP_RESERVED: return "RESERVED";endcaseendfunctionendpackage : base_types_pkg// protocol_pkg.sv - 协议包(依赖base_types_pkg)
package protocol_pkg;// 导入基础类型import base_types_pkg::*;// 扩展的协议状态typedef enum logic [2:0] {PROTO_IDLE = 3'b000,PROTO_REQUEST = 3'b001,PROTO_WAIT_ACK = 3'b010,PROTO_DATA_PHASE = 3'b011,PROTO_RESPONSE = 3'b100,PROTO_ERROR = 3'b101,PROTO_RETRY = 3'b110,PROTO_COMPLETE = 3'b111} protocol_state_t;// 协议错误类型typedef enum logic [1:0] {NO_ERROR = 2'b00,TIMEOUT_ERROR = 2'b01,PROTOCOL_ERROR = 2'b10,DATA_ERROR = 2'b11} error_type_t;// 扩展的事务结构(基于base_transaction_t)typedef struct {base_transaction_t base; // 包含基础事务protocol_state_t state;error_type_t error;int sequence_id;real timestamp;logic [7:0] priority;} protocol_transaction_t;// 协议处理类class protocol_handler;protocol_state_t current_state;protocol_transaction_t pending_transactions[$];int transaction_counter;function new();current_state = PROTO_IDLE;transaction_counter = 0;endfunctionfunction protocol_transaction_t create_transaction(addr_t addr, data_t data, operation_t op);protocol_transaction_t trans;// 填充基础事务trans.base.address = addr;trans.base.data = data;trans.base.strobe = '1;trans.base.operation = op;trans.base.valid = 1'b1;trans.base.ready = 1'b0;// 填充协议扩展trans.state = PROTO_REQUEST;trans.error = NO_ERROR;trans.sequence_id = transaction_counter++;trans.timestamp = $realtime;trans.priority = 8'h80; // 默认优先级return trans;endfunctionfunction void add_transaction(protocol_transaction_t trans);pending_transactions.push_back(trans);endfunctionfunction protocol_transaction_t get_next_transaction();if (pending_transactions.size() > 0) beginreturn pending_transactions.pop_front();end else beginprotocol_transaction_t empty_trans;return empty_trans;endendfunctionfunction string transaction_to_string(protocol_transaction_t trans);return $sformatf("[%d] %s @ %h = %h, State: %s, Error: %s, Priority: %d",trans.sequence_id,op_to_string(trans.base.operation),trans.base.address,trans.base.data,trans.state.name(),trans.error.name(),trans.priority);endfunctionendclassendpackage : protocol_pkg// verification_pkg.sv - 验证包(依赖protocol_pkg和base_types_pkg)
package verification_pkg;// 导入依赖的包import base_types_pkg::*;import protocol_pkg::*;// 验证相关的类型typedef enum {CHECK_PASS,CHECK_FAIL,CHECK_TIMEOUT,CHECK_SKIP} check_result_t;// 覆盖率点定义typedef struct {string name;int hit_count;int total_count;real coverage_percent;} coverage_point_t;// 验证统计typedef struct {int total_transactions;int passed_checks;int failed_checks;int timeout_checks;int skipped_checks;real start_time;real end_time;coverage_point_t coverage_points[$];} verification_stats_t;// 验证环境类class verification_env;protocol_handler handler;verification_stats_t stats;function new();handler = new();reset_stats();endfunctionfunction void reset_stats();stats.total_transactions = 0;stats.passed_checks = 0;stats.failed_checks = 0;stats.timeout_checks = 0;stats.skipped_checks = 0;stats.start_time = $realtime;stats.coverage_points.delete();endfunctionfunction void add_coverage_point(string name, int total);coverage_point_t cp;cp.name = name;cp.hit_count = 0;cp.total_count = total;cp.coverage_percent = 0.0;stats.coverage_points.push_back(cp);endfunctionfunction void hit_coverage_point(string name);foreach (stats.coverage_points[i]) beginif (stats.coverage_points[i].name == name) beginstats.coverage_points[i].hit_count++;stats.coverage_points[i].coverage_percent = (real'(stats.coverage_points[i].hit_count) / real'(stats.coverage_points[i].total_count)) * 100.0;break;endendendfunctionfunction check_result_t verify_transaction(protocol_transaction_t expected,protocol_transaction_t actual);stats.total_transactions++;// 检查基础事务if (expected.base.address != actual.base.address ||expected.base.data != actual.base.data ||expected.base.operation != actual.base.operation) beginstats.failed_checks++;return CHECK_FAIL;end// 检查协议状态if (expected.state != actual.state) beginstats.failed_checks++;return CHECK_FAIL;endstats.passed_checks++;return CHECK_PASS;endfunctionfunction void print_stats();real total_time = stats.end_time - stats.start_time;real pass_rate = 0.0;if (stats.total_transactions > 0) beginpass_rate = (real'(stats.passed_checks) / real'(stats.total_transactions)) * 100.0;end$display("=== Verification Statistics ===");$display("Total transactions: %d", stats.total_transactions);$display("Passed checks: %d", stats.passed_checks);$display("Failed checks: %d", stats.failed_checks);$display("Timeout checks: %d", stats.timeout_checks);$display("Skipped checks: %d", stats.skipped_checks);$display("Pass rate: %.2f%%", pass_rate);$display("Execution time: %.2f ns", total_time);$display("\n--- Coverage Points ---");foreach (stats.coverage_points[i]) begincoverage_point_t cp = stats.coverage_points[i];$display("%s: %d/%d (%.2f%%)", cp.name, cp.hit_count, cp.total_count, cp.coverage_percent);endendfunctionendclassendpackage : verification_pkg// 使用示例 - 展示包的依赖关系
module package_dependency_demo;// 导入所有相关包import base_types_pkg::*;import protocol_pkg::*;import verification_pkg::*;verification_env env;protocol_transaction_t trans1, trans2, trans3;initial begin$display("=== Package Dependency Demo ===");// 创建验证环境env = new();// 添加覆盖率点env.add_coverage_point("READ_OPERATIONS", 10);env.add_coverage_point("WRITE_OPERATIONS", 10);env.add_coverage_point("BURST_OPERATIONS", 5);// 创建测试事务trans1 = env.handler.create_transaction(16'h1000, 32'hDEADBEEF, OP_WRITE);trans2 = env.handler.create_transaction(16'h2000, 32'h0, OP_READ);trans3 = env.handler.create_transaction(16'h3000, 32'hCAFEBABE, OP_BURST);// 显示事务信息$display("\n--- Created Transactions ---");$display("Trans1: %s", env.handler.transaction_to_string(trans1));$display("Trans2: %s", env.handler.transaction_to_string(trans2));$display("Trans3: %s", env.handler.transaction_to_string(trans3));// 添加到处理器env.handler.add_transaction(trans1);env.handler.add_transaction(trans2);env.handler.add_transaction(trans3);// 模拟处理过程$display("\n--- Processing Transactions ---");while (env.handler.pending_transactions.size() > 0) beginprotocol_transaction_t current = env.handler.get_next_transaction();// 更新覆盖率case (current.base.operation)OP_READ: env.hit_coverage_point("READ_OPERATIONS");OP_WRITE: env.hit_coverage_point("WRITE_OPERATIONS");OP_BURST: env.hit_coverage_point("BURST_OPERATIONS");endcase// 模拟验证protocol_transaction_t expected = current;check_result_t result = env.verify_transaction(expected, current);$display("Processed: %s - Result: %s", env.handler.transaction_to_string(current),result.name());end// 完成统计env.stats.end_time = $realtime;env.print_stats();end
endmodule
```a = new(package_a::STATE_DONE, 42);trans_b = new(package_b::STATE_IDLE, "test_transaction");$display("Transaction A: state=%s, data=%d", package_a::get_state_name(trans_a.state), trans_a.data);$display("Transaction B: state=%s, name=%s", package_b::get_state_name(trans_b.state), trans_b.name);end
endmodule// 解决方案2:分别导入不冲突的标识符
module selective_conflict_resolution;// 选择性导入避免冲突import package_a::transaction_a;import package_b::transaction_b;// 对于冲突的标识符,使用完全限定名或别名typedef package_a::state_t state_a_t;typedef package_b::state_t state_b_t;state_a_t state_a;state_b_t state_b;transaction_a trans_a;transaction_b trans_b;initial begin$display("\n=== Selective Conflict Resolution Demo ===");state_a = package_a::STATE_ACTIVE;state_b = package_b::STATE_BUSY;trans_
📖 扩展学习资源:
- SystemVerilog常用语法学习 - CSDN
- SystemVerilog学习【一】数据类型详解 - CSDN
- SystemVerilog学习【二】接口(interface)详解 - CSDN
- SystemVerilog学习【三】类和面向对象编程详解 - CSDN
- SystemVerilog学习【四】约束随机化编程详解 - CSDN
- SystemVerilog学习【五】断言详解 - CSDN
- SystemVerilog学习【六】功能覆盖率详解 - CSDN