UVM 寄存器模型(Register Model)全面详解 UVM 寄存器模型Register Model全面详解一、概述1.1 为什么需要寄存器模型在 SoC 验证中寄存器验证是工作量最大的部分之一一个 SoC 可能有数千甚至上万个寄存器每个寄存器有不同字段field字段有不同属性读写、只读、清除等每个寄存器在不同地址访问方式各异需要保证默认值正确、读写正确、复位值正确、属性符合规格如果用传统方式逐个poke/get/check代码巨大且易错。UVM 寄存器模型提供了一套高抽象层的解决方案对比项传统方式UVM 寄存器模型寄存器定义散落各处易不一致集中式模型单一来源访问方式手动拼地址 总线事务reg.read()/write()模型自动翻译镜像值维护无靠人脑记忆模型自动维护期望值mirror覆盖率难统计内建寄存器覆盖率前门/后门访问分别实现一致接口运行时选择复用性低IP/SoC 各层级都能复用1.2 寄存器模型的核心组成┌─────────────────────────────────────────────────────┐ │ uvm_reg_block │ │ (寄存器块对应一个 IP 或一个子系统) │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │ │ │ uvm_reg_map │ │ uvm_reg_map │ │ 子 block │ │ │ │ (地址映射) │ │ │ │ │ │ │ └──────┬──────┘ └─────┬───────┘ └────────────┘ │ │ │ │ │ │ ┌──────▼──────┐ ┌─────▼───────┐ │ │ │ uvm_reg │ │ uvm_reg │ │ │ │ (寄存器) │ │ (寄存器) │ │ │ └──────┬──────┘ └─────────────┘ │ │ │ │ │ ┌──────▼────────────────────┐ │ │ │ uvm_reg_field (字段) │ │ │ │ field1 | field2 | ... │ │ │ └───────────────────────────┘ │ └─────────────────────────────────────────────────────┘类职责uvm_reg一个寄存器包含若干 fielduvm_reg_field寄存器中的一个字段RW/RO/W1C…uvm_reg_map地址映射一个 block 可有多张 map对应不同总线uvm_reg_block寄存器块IP/子系统级可嵌套uvm_reg_adapter寄存器事务 ↔ 总线事务的转换器uvm_reg_predictor监听总线自动更新镜像值uvm_mem内存区域不属于寄存器但同属模型二、构建寄存器模型2.1 一个简单例子定义一个寄存器假设规格如下寄存器地址字段位属性复位值CTRL0x00ENABLE[0]RW0MODE[3:1]RW0RSVD[31:4]RO0STATUS0x04DONE[0]RO0ERR[1]W1C (write-1-to-clear)0class ctrl_reg extends uvm_reg; uvm_object_utils(ctrl_reg) rand uvm_reg_field enable; rand uvm_reg_field mode; uvm_reg_field rsvd; // 保留位不 rand function new(string name ctrl_reg); super.new(name, 32, UVM_NO_COVERAGE); // 32 位宽 endfunction virtual function void build(); enable uvm_reg_field::type_id::create(enable); mode uvm_reg_field::type_id::create(mode); rsvd uvm_reg_field::type_id::create(rsvd); // configure(parent, size, lsb_pos, access, volatile, reset, has_reset, is_rand, individually_accessible) enable.configure(this, 1, 0, RW, 0, 0, 1, 1, 0); mode.configure (this, 3, 1, RW, 0, 0, 1, 1, 0); rsvd.configure (this, 28, 4, RO, 0, 0, 1, 0, 0); endfunction endclass class status_reg extends uvm_reg; uvm_object_utils(status_reg) uvm_reg_field done; // RO uvm_reg_field err; // W1C function new(string name status_reg); super.new(name, 32, UVM_NO_COVERAGE); endfunction virtual function void build(); done uvm_reg_field::type_id::create(done); err uvm_reg_field::type_id::create(err); done.configure(this, 1, 0, RO, 1, 0, 1, 0, 0); // volatile1 (硬件会改) err.configure (this, 1, 1, W1C, 1, 0, 1, 0, 0); endfunction endclass2.2 字段属性详解uvm_reg_field::configure(parent, size, lsb_pos, access, volatile, reset, has_reset, is_rand, individually_accessible)参数参数说明parent所属寄存器thissize字段位宽lsb_pos字段最低位位置access访问属性见下表volatile是否易失硬件能否改变reset复位值has_reset是否有复位值is_rand是否可随机化individually_accessible该字段能否独立访问访问属性access速查属性含义RO只读RW读写RC读清零RS读置位W1C写 1 清零写 0 无影响W1S写 1 置位W0C写 0 清零W0S写 0 置位WRCRW读清零WSRCRW读置位WC写清零WS写置位W1写 1 触发如触发一次性动作NOACCESS不可访问2.3 定义寄存器块block和 mapclass my_reg_block extends uvm_reg_block; uvm_object_utils(my_reg_block) rand ctrl_reg ctrl; rand status_reg status; uvm_reg_map apb_map; // APB 总线视角的地址映射 function new(string name my_reg_block); super.new(name, UVM_NO_COVERAGE); endfunction virtual function void build(); ctrl ctrl_reg::type_id::create(ctrl); status status_reg::type_id::create(status); // 必须先配置寄存器 ctrl.configure(this, null, ); ctrl.build(); status.configure(this, null, ); status.build(); // 创建地址映射base0x0, n_bytes4, endianUVM_LITTLE_ENDIAN apb_map create_map(apb_map, h0, 4, UVM_LITTLE_ENDIAN); // 把寄存器加入 map指定地址 apb_map.add_reg(ctrl, h0, RW); apb_map.add_reg(status, h4, RW); // 锁定模型防止后续误修改 lock_model(); endfunction endclass2.4 block 的嵌套SoC 层级class soc_reg_block extends uvm_reg_block; uvm_object_utils(soc_reg_block) rand my_reg_block ip_a_regs; // 子 block rand my_reg_block ip_b_regs; uvm_reg_map axi_map; function new(string name soc_reg_block); super.new(name, UVM_NO_COVERAGE); endfunction virtual function void build(); ip_a_regs my_reg_block::type_id::create(ip_a_regs); ip_a_regs.configure(this); ip_a_regs.build(); ip_b_regs my_reg_block::type_id::create(ip_b_regs); ip_b_regs.configure(this); ip_b_regs.build(); axi_map create_map(axi_map, h0, 4, UVM_LITTLE_ENDIAN); // 加入子 block指定偏移地址 axi_map.add_submap(ip_a_regs.default_map, h0000); axi_map.add_submap(ip_b_regs.default_map, h1000); lock_model(); endfunction endclass三、寄存器访问Adapter 与 Predictor3.1 整体连接┌─────────────────────┐ │ uvm_reg_block │ │ (寄存器模型) │ └──────────┬──────────┘ │ (使用 default_map) ┌─────────────┼─────────────────┐ │ │ │ uvm_reg_adapter uvm_reg_predictor (其他 seq 直接调用) (reg↔bus 转换) (bus→mirror 更新) │ │ ▼ ▼ sequencer/ monitor.analysis_port driver (前门访问) (监听总线自动更新镜像)3.2 Adapter —— reg 事务 ↔ bus 事务class apb_reg_adapter extends uvm_reg_adapter; uvm_object_utils(apb_reg_adapter) function new(string name apb_reg_adapter); super.new(name); // 是否支持 byte enableAPB 通常不支持 supports_byte_enable 0; // 是否提供响应读时才有响应 provides_responses 1; endfunction // 把 uvm_reg_bus_op (寄存器操作) 转为总线事务 virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); apb_transaction tr; tr apb_transaction::type_id::create(tr); tr.kind (rw.kind UVM_READ) ? APB_READ : APB_WRITE; tr.addr rw.addr; tr.data rw.data; return tr; endfunction // 把总线响应转为 uvm_reg_bus_op virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); apb_transaction tr; if (!$cast(tr, bus_item)) begin uvm_fatal(ADAPTER, Failed to cast bus_item) return; end rw.kind (tr.kind APB_READ) ? UVM_READ : UVM_WRITE; rw.addr tr.addr; rw.data tr.data; rw.status (tr.error) ? UVM_NOT_OK : UVM_IS_OK; endfunction endclass关键字段reg2bus—— 寄存器模型要发访问时把内部uvm_reg_bus_op地址、读/写、数据翻译成具体总线事务bus2reg—— 总线响应回来后把响应翻译回uvm_reg_bus_op让模型知道最终结果3.3 在 env 中连接class my_env extends uvm_env; uvm_component_utils(my_env) my_reg_block regmodel; apb_reg_adapter adapter; uvm_reg_predictor#(apb_transaction) predictor; apb_agent apb_agt; function void build_phase(uvm_phase phase); super.build_phase(phase); regmodel my_reg_block::type_id::create(regmodel); regmodel.build(); adapter apb_reg_adapter::type_id::create(adapter); predictor uvm_reg_predictor#(apb_transaction)::type_id::create(predictor, this); endfunction function void connect_phase(uvm_phase phase); // 1. 把 adapter 给 default_map前门访问用 regmodel.default_map.set_sequencer(apb_agt.sequencer, adapter); // 2. predictor 监听 monitor自动更新镜像 predictor.map regmodel.default_map; predictor.adapter adapter; apb_agt.monitor.ap.connect(predictor.bus_in); // 3. 设置 root sequence 可使用 regmodel uvm_config_db#(uvm_reg_block)::set(this, *, regmodel, regmodel); endfunction endclass四、寄存器访问方式4.1 前门访问Frontdoor通过实际总线事务访问 DUTtask access_via_frontdoor(); uvm_status_e status; uvm_reg_data_t data; // 写 regmodel.ctrl.write(status, 32h0000_0005); // ENABLE1, MODE2 // 读 regmodel.ctrl.read(status, data); // 字段级访问推荐 regmodel.ctrl.enable.set(1); regmodel.ctrl.mode.set(3); regmodel.ctrl.update(status); // 把期望值一次性写入 endtask特点真实走总线验证总线通路 DUT 寄存器功能慢每访问一次都消耗多个总线周期发起 sequence经过 sequencer→driver→DUT4.2 后门访问Backdoor通过 hierarchical 路径或 DPI 直接读写 RTL不经过总线task access_via_backdoor(); uvm_status_e status; uvm_reg_data_t data; // 后门写 regmodel.ctrl.write(status, 32h5, UVM_BACKDOOR); // 后门读 regmodel.ctrl.read(status, data, UVM_BACKDOOR); // 后门 peek/poke不更新镜像 regmodel.ctrl.peek(status, data); // 仅读 RTL regmodel.ctrl.poke(status, 32h5); // 仅写 RTL不更新 mirror endtask配置后门路径在 build 阶段class my_reg_block extends uvm_reg_block; virtual function void build(); // ... 创建寄存器 ... ctrl.add_hdl_path_slice(tb_top.dut.regs.ctrl_reg, 0, 32); // 或批量 ctrl.add_hdl_path(tb_top.dut.regs.ctrl_reg); endfunction endclass特点极快仿真时间几乎为 0验证 DUT 内部寄存器本身绕过总线不验证总线通路适合初始化、检查、绕过死锁场景4.3 前门 vs 后门选择场景推荐正常功能激励前门复位后检查默认值后门快初始化大量寄存器到某状态后门快验证总线通路本身前门死锁状态下查看寄存器实际值后门 peek比对期望值 vs 实际值mirror前门 peek后门五、镜像值Mirror与期望值Desired寄存器模型维护两个值概念含义更新方式Mirrored value镜像值模型认为 DUT 寄存器当前的值predictor 自动更新 / read / peek 更新Desired value期望值你希望 DUT 寄存器变成的值set()设置update()提交Actual value实际值DUT 寄存器真实硬件值通过 read前门/ peek后门得到5.1 工作流task mirror_and_update(); uvm_status_e status; // 1. 检查镜像值与硬件是否一致前门读后比对 regmodel.ctrl.mirror(status, UVM_CHECK); // read compare mirror // 2. 设置期望值不访问硬件 regmodel.ctrl.enable.set(1); regmodel.ctrl.mode.set(2); // 3. 提交仅当期望值 ≠ 镜像值时才真正写入 regmodel.ctrl.update(status); // 4. 现在镜像值被更新等于期望值 endtask状态变化: 初始: desired0, mirrored0, actual0 set(1): desired1, mirrored0, actual0 update: desired1, mirrored1, actual1 (实际写入发生)5.2mirror的检查模式// UVM_CHECK读完硬件后与 mirror 比对不一致报错 regmodel.ctrl.mirror(status, UVM_CHECK); // 不传 UVM_CHECK仅更新 mirror不比对 regmodel.ctrl.mirror(status);六、内置 SequenceUVM 提供了一组开箱即用的寄存器验证 sequence直接覆盖常见场景6.1 常用内置 sequenceSequence功能uvm_reg_hw_reset_seq复位后检查所有寄存器的复位值最常用uvm_reg_bit_bash_seq对每个 bit 单独读写测试uvm_reg_access_seq前门写→后门读前门读→后门写验证前后门一致uvm_reg_mem_access_seq内存区域访问测试uvm_mem_walk_seq内存走步测试walking 1s and 0suvm_reg_single_bit_bash_seq单寄存器 bit bashuvm_reg_single_access_seq单寄存器 access 测试6.2 使用方式class reg_test extends uvm_test; task run_phase(uvm_phase phase); uvm_reg_hw_reset_seq reset_seq; uvm_reg_bit_bash_seq bitbash_seq; uvm_reg_access_seq access_seq; phase.raise_objection(this); // 1. 复位值检查 reset_seq uvm_reg_hw_reset_seq::type_id::create(reset_seq); reset_seq.model regmodel; reset_seq.start(null); // 2. bit bash 测试 bitbash_seq uvm_reg_bit_bash_seq::type_id::create(bitbash_seq); bitbash_seq.model regmodel; bitbash_seq.start(null); // 3. 前后门一致性测试 access_seq uvm_reg_access_seq::type_id::create(access_seq); access_seq.model regmodel; access_seq.start(null); phase.drop_objection(this); endtask endclass6.3 内置 sequence 的优势覆盖率自动纳入寄存器覆盖率模型经过大量项目验证减少遗漏可单独运行也可组合成完整测试套件七、寄存器覆盖率7.1 覆盖率模型类型class ctrl_reg extends uvm_reg; function new(string name ctrl_reg); // 第三参数覆盖率模型 super.new(name, 32, UVM_CVR_ALL); endfunction endclass覆盖率类型含义UVM_NO_COVERAGE不收集覆盖率UVM_CVR_REG_BITS每个 bit 的 0/1 覆盖UVM_CVR_ADDR_MAP地址映射覆盖UVM_CVR_FIELD_VALS字段值覆盖UVM_CVR_ALL全部7.2 启用与查看// 在 block build 时启用 virtual function void build(); set_coverage(UVM_CVR_ALL); // ... endfunction // 仿真末尾报告覆盖率与 uvm_phase report_phase 协同 function void report_phase(uvm_phase phase); $display(Reg coverage: %0.2f%%, regmodel.get_coverage()); endfunction字段值覆盖对枚举型字段尤其有用如 MODE 字段有 4 种取值覆盖率会跟踪每种值是否被写过。八、寄存器模型在 UVM 中的完整集成8.1 集成步骤总结Step 1: 定义 uvm_reg / uvm_reg_field (寄存器层) Step 2: 定义 uvm_reg_block创建 mapadd_reg (块层) Step 3: 定义 uvm_reg_adapter (reg↔bus 转换) Step 4: 在 env 的 build_phase 创建 regmodel/build Step 5: 在 env 的 connect_phase: - set_sequencer(adapter) (前门访问通道) - 配置 predictor接 monitor.ap (镜像自动更新) Step 6: 通过 uvm_config_db 把 regmodel 给 sequence Step 7: sequence/test 中调用 reg.read/write (使用)8.2 sequence 中使用寄存器模型class config_dut_seq extends uvm_sequence #(apb_transaction); uvm_object_utils(config_dut_seq) uvm_declare_p_sequencer(apb_sequencer) my_reg_block regmodel; task body(); uvm_status_e status; if (!uvm_config_db#(uvm_reg_block)::get(null, get_full_name(), regmodel, regmodel)) uvm_fatal(NO_REG, regmodel not set) // 用字段访问配置 DUT regmodel.ctrl.enable.set(1); regmodel.ctrl.mode.set(2); regmodel.ctrl.update(status); // 一次性写 // 等状态寄存器 DONE 置位 uvm_info(CFG, Waiting for DONE, UVM_LOW) do begin regmodel.status.done.mirror(status); // 读并更新镜像 end while (!regmodel.status.done.get()); // 清 ERR (W1C) regmodel.status.err.set(1); regmodel.status.update(status); endtask endclass九、完整示例9.1 完整代码// 寄存器定义 class ctrl_reg extends uvm_reg; uvm_object_utils(ctrl_reg) rand uvm_reg_field enable; rand uvm_reg_field mode; function new(string name ctrl_reg); super.new(name, 32, UVM_CVR_ALL); endfunction virtual function void build(); enable uvm_reg_field::type_id::create(enable); mode uvm_reg_field::type_id::create(mode); enable.configure(this, 1, 0, RW, 0, 0, 1, 1, 0); mode.configure (this, 3, 1, RW, 0, 0, 1, 1, 0); endfunction endclass // 寄存器块 class my_reg_block extends uvm_reg_block; uvm_object_utils(my_reg_block) rand ctrl_reg ctrl; uvm_reg_map apb_map; function new(string name my_reg_block); super.new(name, UVM_CVR_ALL); endfunction virtual function void build(); ctrl ctrl_reg::type_id::create(ctrl); ctrl.configure(this, null, ); ctrl.build(); ctrl.add_hdl_path_slice(tb_top.dut.ctrl_q, 0, 32); apb_map create_map(apb_map, h0, 4, UVM_LITTLE_ENDIAN); apb_map.add_reg(ctrl, h0, RW); lock_model(); endfunction endclass // Adapter class apb_adapter extends uvm_reg_adapter; uvm_object_utils(apb_adapter) function new(string name apb_adapter); super.new(name); supports_byte_enable 0; endfunction virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); apb_tx tr apb_tx::type_id::create(tr); tr.kind (rw.kind UVM_READ) ? APB_READ : APB_WRITE; tr.addr rw.addr; tr.data rw.data; return tr; endfunction virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); apb_tx tr; $cast(tr, bus_item); rw.kind (tr.kind APB_READ) ? UVM_READ : UVM_WRITE; rw.addr tr.addr; rw.data tr.data; rw.status tr.err ? UVM_NOT_OK : UVM_IS_OK; endfunction endclass // Env 集成 class my_env extends uvm_env; uvm_component_utils(my_env) my_reg_block regmodel; apb_adapter adapter; uvm_reg_predictor#(apb_tx) predictor; apb_agent apb_agt; function void build_phase(uvm_phase phase); super.build_phase(phase); regmodel my_reg_block::type_id::create(regmodel); regmodel.build(); adapter apb_adapter::type_id::create(adapter); predictor uvm_reg_predictor#(apb_tx)::type_id::create(predictor, this); apb_agt apb_agent::type_id::create(apb_agt, this); endfunction function void connect_phase(uvm_phase phase); regmodel.default_map.set_sequencer(apb_agt.sqr, adapter); predictor.map regmodel.default_map; predictor.adapter adapter; apb_agt.mon.ap.connect(predictor.bus_in); uvm_config_db#(uvm_reg_block)::set(this, *, regmodel, regmodel); endfunction endclass // Test class reg_test extends uvm_test; uvm_component_utils(reg_test) my_env env; task run_phase(uvm_phase phase); uvm_reg_hw_reset_seq reset_seq; uvm_status_e status; phase.raise_objection(this); // 1. 复位值检查前门读后对照 spec reset_seq uvm_reg_hw_reset_seq::type_id::create(reset_seq); reset_seq.model env.regmodel; reset_seq.start(null); // 2. 字段级配置 env.regmodel.ctrl.enable.set(1); env.regmodel.ctrl.mode.set(3); env.regmodel.ctrl.update(status); // 3. 后门读验证写入成功 env.regmodel.ctrl.mirror(status, UVM_CHECK, UVM_BACKDOOR); phase.drop_objection(this); endtask endclass9.2 模型自动生成的替代方案手写寄存器模型工作量大工业界常用工具自动生成工具输入输出IP-XACT UVMgenIP-XACT XML完整 UVM regmodel SV 代码PeakRDLSystemRDLUVM regmodel 文档 C headerRdl2UVMSystemRDLUVM regmodel自研脚本Excel/CSV 寄存器表UVM regmodel团队定制推荐做法用 SystemRDL 或 IP-XACT 作为寄存器规格单一来源由工具生成 regmodel C 头 文档避免多处维护。十、常见问题与最佳实践10.1 必须调用 lock_model()virtual function void build(); // ... 添加 reg ... lock_model(); // ← 必须调用否则地址解析失败 endfunctionlock_model()完成地址计算与模型内部一致性检查未调用会导致运行时崩溃。10.2 volatile 字段设置硬件可改变的寄存器状态位、计数器volatile1模型不会假设它与镜像一致// RO 且 volatile1 → mirror 总是反映读回值比对更宽松 done.configure(this, 1, 0, RO, 1, 0, 1, 0, 0);10.3 复位值检查是基础每个寄存器都应该跑uvm_reg_hw_reset_seq确保复位后所有寄存器值与规格一致。这是寄存器验证的门禁。10.4 不要硬编码地址// ❌ 硬编码 seq.addr 32h0000; // ✅ 通过模型获取 seq.addr regmodel.ctrl.get_address(); // 或使用 default_map 转换 seq.addr regmodel.default_map.get_reg_by_offset(h0).get_address();10.5 多 map 场景一个 block 可以有多张 map多总线视角class dual_view_block extends uvm_reg_block; uvm_reg_map apb_map; // APB 视角base0x0 uvm_reg_map axi_map; // AXI 视角base0x1000_0000 virtual function void build(); apb_map create_map(apb_map, h0, 4, UVM_LITTLE_ENDIAN); axi_map create_map(axi_map, h1000_0000, 4, UVM_LITTLE_ENDIAN); // 同一寄存器加入不同 map apb_map.add_reg(ctrl, h0, RW); axi_map.add_reg(ctrl, h0, RW); endfunction endclass通过get_address(map_name)获取特定视角下的地址。10.6 跨子系统的内存映射// SoC 层级 soc_map.add_submap(cpu_regs.default_map, h0000_0000); soc_map.add_submap(dma_regs.default_map, h0001_0000); soc_map.add_submap(usb_regs.default_map, h0002_0000); // 一句访问自动解析完整地址 soc_block.cpu_regs.ctrl.write(status, 5); // 模型知道完整地址十一、寄存器模型覆盖率策略11.1 三层覆盖率层级覆盖内容字段值覆盖每个字段所有合法值是否被写过bit 覆盖每个 bit 的 0/1 是否都被写入地址覆盖map 中所有地址是否被访问11.2 推进覆盖率的手段1. uvm_reg_hw_reset_seq → 默认值覆盖 2. uvm_reg_bit_bash_seq → bit 0/1 全覆盖 3. uvm_reg_access_seq → 前门/后门一致覆盖 4. 定向 sequence 写各字段典型值 → 字段值覆盖 5. 随机化 regmodel 后 update → 全空间随机覆盖class random_reg_seq extends uvm_sequence; task body(); // 随机化整个寄存器块的所有 rand 字段 if (!regmodel.randomize()) uvm_error(RAND, Failed to randomize regmodel) regmodel.update(status); // 把随机值写入 DUT endtask endclass十二、总结概念要点核心组成reg → field → map → block可嵌套Adapterreg2bus / bus2reg 转换连接模型与总线Predictor监听总线自动维护镜像值前门访问走总线慢但真实验证通路后门访问走 hierarchical/DPI快绕过总线镜像值 (mirror)模型认为 DUT 当前的值期望值 (desired)你想让 DUT 变成的值update / mirror提交期望值 / 检查镜像一致内置 sequencehw_reset / bit_bash / access开箱即用覆盖率bits / field_vals / addr_map 三类SoC 嵌套add_submap 构建层级地址空间单一来源SystemRDL / IP-XACT → 工具生成 regmodelUVM 寄存器模型的设计哲学把寄存器规格抽象成可执行对象。规格说CTRL 寄存器第 0 位是 RW 的 ENABLE就写成enable.configure(this, 1, 0, RW, ...)一一对应。模型自动维护镜像、生成覆盖率、提供前后门统一接口、支持嵌套层级使得数以千计的寄存器验证从手工作坊变成自动化流水线。配合 SystemRDL/IP-XACT 工具链寄存器规格从一份描述同时生成 RTL、UVM 模型、C 头、文档真正实现单一来源、多处一致。