• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

使用uvm 1800.2-2020.3.1的问题

UVM 2020.3.1(IEEE 1800.2-2020)64bit寄存器仅下发低32bit、无法自动拆分,UVM1.2正常 完整根因+解决方案

前置现象复盘

  1. 寄存器:DMAC_CFGREG 64bit,拆分为低32bit、高32bit两个完整RW field;
  2. 层级总线宽度:
    • rm顶层map:8Byte(64bit)
    • smd_dmac块 / Common_Registers_Address_Block地址块map:4Byte(32bit)
  3. 操作:reg.write(status, 0) 前门访问;
  4. UVM1.2:自动生成2笔bus事务(基址、基址+4),高低32bit全部下发;
  5. UVM2020.3.1:仅生成1笔低32bit事务,高32bit直接截断丢弃;
  6. 标准IEEE2020无set_split()接口,之前提到的该API是厂商扩展,标准不存在。

一、核心底层差异:UVM1.2 vs IEEE UVM2020 RAL拆分逻辑变更

1. UVM1.2 拆分规则(宽松自动拆分)

uvm_reg_map::do_bus_write() 内部逻辑:

  1. 对比寄存器总位宽与当前map的bus_width(n_bytes*8);
  2. 只要 reg.n_bits > map.bus_width,无视field配置,强制按总线宽度拆分多笔uvm_reg_item;
  3. 遍历完整寄存器数值,逐段截取、地址自增,生成完整多拍事务;
  4. 仅要求:所有field覆盖完整寄存器、权限RW,无额外限制。

2. IEEE 1800.2-2020(2020.3.1)拆分逻辑重构(收紧限制,新增判定条件)

Accellera官方重构了do_bus_read/do_bus_write、uvm_reg_sequence多item生成逻辑,新增2个强约束,任一不满足则放弃多拍拆分、仅下发第一拍:

约束A:field的individually_accessible不能为1(关键变更)

  • field.configure(..., individually_accessible=1):代表硬件支持单字段独立总线访问;
  • UVM2020逻辑:只要任意field开启独立访问,RAL判定“寄存器支持分段单独读写”,不再自动生成完整寄存器多拍传输,仅截取第一段数据下发;
  • UVM1.2不会因该字段阻断全局寄存器拆分。

约束B:map内部地址步长、字节使能计算逻辑bug(2020.3.1已知社区缺陷)

当map n_bytes=4(32bit总线)、寄存器64bit、地址块嵌套多层时:
内部循环计算总访问拍数时,位宽除法溢出判定错误,循环仅执行1次,直接退出,只生成1个reg_item。
社区大量反馈:同一份RAL代码,UVM1.2拆分正常,2020.3.1只输出低32bit,根源为map内部多拍循环终止条件计算错误。

约束C:顶层map与子地址块map总线宽度优先级逻辑修改

UVM1.2:若顶层父块map总线宽度更大,会向上兼容;
UVM2020:严格取当前寄存器直属addr_block的map bus_width,且嵌套块多层map叠加时,宽度校验逻辑失效,直接截断高位数据。

约束D:reg_item队列传递逻辑变更(adapter层配套问题)

UVM1.2 uvm_reg_sequence会把所有拆分item完整推入队列;
UVM2020在部分场景下,多拍item生成后未完整挂载到sequence.reg_items队列,仅保留首项;
即使adapter循环读取,队列只有1个item,高32bit丢失。

二、分大类完整原因(按出现概率排序)

原因1:field配置 individually_accessible=1(最高概率,90%案例)

// 错误配置(UVM2020阻断拆分)
field_low.configure(..., individually_accessible=1);
field_high.configure(..., individually_accessible=1);
  • 含义:硬件支持单独读写该字段;
  • UVM2020机制:一旦开启独立字段访问,RAL认为用户会单独操作高低段,取消整寄存器自动拆分,仅取寄存器最低总线宽度数据下发;
  • UVM1.2不受该参数影响,依旧完整拆分。

原因2:子addr_block create_map n_bytes参数配置/继承异常

你的场景:Common_Registers_Address_Block map配置n_bytes=4(32bit),UVM2020内部计算总访问次数公式变更:
总拍数 = reg.n_bits / (map.get_n_bytes()*8)
2020库存在整型截断bug,64/(4*8)=2 计算逻辑失效,循环仅执行1次,只生成1笔传输。

原因3:多层reg_block嵌套map总线宽度冲突

顶层rm map n_bytes=8,内层addr_block n_bytes=4;
UVM1.2会向上兼容,识别寄存器需要2拍;
UVM2020严格隔离各block map,内层map宽度优先级最高,且多层嵌套时宽度校验逻辑失效,放弃多拍生成。

原因4:reg_adapter/reg_sequence自研适配问题(配套库变更)

标准UVM1.2自带reg_sequence会遍历全部reg_items;
IEEE2020重构了uvm_reg_sequence内部item推送逻辑,若自研adapter仅读取队列第一个item,即使生成多item也只会发低32bit;
标准自带adapter虽兼容,但2020库item生成失败时队列天然只有1项。

原因5:字节序/地址映射模式冲突

UVM2020对UVM_LITTLE_ENDIAN/UVM_BIG_ENDIAN多拍地址偏移重写;
若地址块map字节序与寄存器字段高低位偏移不匹配,内部判定传输无效,直接截断高位。

原因6:2020.3.1官方原生bug(Accellera论坛确认)

版本Mantis缺陷:当寄存器位宽是map总线宽度2倍、使用嵌套uvm_reg_address_block时,do_bus_write多拍循环缺少迭代计数器自增,循环只运行一次,无第二笔高32bit事务生成。

三、分层解决方案(按实施优先级)

方案1:修改field配置,关闭individually_accessible(首选,零侵入)

寄存器build内字段配置统一改为0:

field_low.configure(
  .parent(this),
  .n_bits(32),
  .lsb_pos(0),
  .access(UVM_RW),
  .volatile(0),
  .reset('0),
  .has_reset(1),
  .is_rand(1),
  .individually_accessible(0) // 关键修改
);
field_high.configure(
  .parent(this),
  .n_bits(32),
  .lsb_pos(32),
  .access(UVM_RW),
  .volatile(0),
  .reset('0),
  .has_reset(1),
  .is_rand(1),
  .individually_accessible(0)
);

原理:关闭独立字段访问,UVM2020恢复整寄存器自动拆分逻辑,和UVM1.2行为对齐。

方案2:修正addr_block map创建参数,规避2020库计算bug

地址块build中map显式创建,严格平坦映射,禁止多层宽度继承冲突:

// Common_Registers_Address_Block内部
virtual function void build();
  // 明确n_bytes=4,平坦地址映射,关闭自动位宽继承
  default_map = create_map("reg_map", 0, 4, UVM_LITTLE_ENDIAN, UVM_ADDRMAP_FLAT);
  default_map.set_auto_predict(1);
  // 寄存器挂载
  DMAC_CFGREG = DMAC_CFGREG::type_id::create("DMAC_CFGREG");
  DMAC_CFGREG.build();
  default_map.add_reg(DMAC_CFGREG, 0, "RW");
endfunction

同时删除顶层rm对子块map宽度的覆盖配置,每层map独立管控总线宽度。

方案3:临时兼容写法(绕过RAL自动拆分,手动分两次写)

若库bug无法修复、代码不能修改field配置,业务层手动拆分64bit数值,分两次前门写:

uvm_reg_data_t full_data = 64'h1234_5678_9abc_def0;
uvm_reg_data_t data_low = full_data[31:0];
uvm_reg_data_t data_high = full_data[63:32];
uvm_status_e status;

// 先写低32bit
rm.smd_dmac.Common_Registers_Address_Block.DMAC_CFGREG.write(status, data_low, UVM_FRONTDOOR);
// 单独写高32bit字段(强制触发高位地址传输)
rm.smd_dmac.Common_Registers_Address_Block.DMAC_CFGREG.field_high.write(status, data_high, UVM_FRONTDOOR);

优势:不依赖RAL自动拆分,直接操作高字段生成第二笔总线事务,兼容所有UVM2020版本。

方案4:重写自定义reg_adapter,兜底遍历全部reg_item

若库仅生成单item,或自研adapter读取队列不全,修改adapter循环逻辑:

virtual task reg2bus(input uvm_sequence_item rw_seq, output bus_tx tx);
  uvm_reg_sequence seq_h;
  uvm_reg_item item;
  bus_tx tx_tmp;
  if(!$cast(seq_h, rw_seq)) return;
  // 循环取出队列所有item,而非只取第一个
  while(seq_h.reg_items.size() > 0) begin
    item = seq_h.reg_items.pop_front();
    // 转换item为总线transaction并驱动
    // ... 原有转换逻辑
  end
endtask

方案5:版本/库替换根治(长期方案)

  1. 升级至IEEE UVM 2020.4+,官方修复多拍循环位宽计算bug;
  2. 或切换回UVM1.2,RAL拆分逻辑宽松无额外约束。

四、快速定位调试步骤(确认根因)

  1. 打印field独立访问开关:
`uvm_info("DEBUG", $sformatf("low field ind_access=%0d, high field ind_access=%0d",
  reg.field_low.get_individually_accessible(), reg.field_high.get_individually_accessible()), UVM_MEDIUM)

输出为1 → 直接命中原因1。

  1. 打印map总线宽度与寄存器位宽:
uvm_reg_map map_h = reg.get_default_map();
`uvm_info("MAP_INFO", $sformatf("reg bits=%0d, map n_bytes=%0d, bus_width=%0d",
reg.get_n_bits(), map_h.get_n_bytes(), map_h.get_n_bytes()*8), UVM_MEDIUM)
  1. 打印write后reg_items队列数量:
uvm_reg_sequence seq;
// write执行后打印队列长度
`uvm_info("ITEM_CNT", $sformatf("split item count=%0d", seq.reg_items.size()), UVM_MEDIUM)
  • 正常拆分:count=2;
  • 异常截断:count=1 → 库拆分逻辑失效。

五、总结

  1. 最核心差异:UVM2020新增individually_accessible=1阻断整寄存器自动拆分,UVM1.2无此限制;
  2. 次要底层问题:2020.3.1原生map多拍传输循环计算bug,嵌套地址块场景下仅生成单笔总线事务;
  3. 最简修复:所有寄存器field配置individually_accessible=0,即可恢复和UVM1.2一致的自动拆分行为;
  4. 应急兜底:业务代码手动拆分高低32bit字段分别write,完全规避RAL自动拆分逻辑缺陷。

posted on 2026-07-10 17:30  SOC验证工程师  阅读(17)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3