如何免费扩展工作空间:VirtualMonitor虚拟显示器终极指南
2025/12/17 4:21:36
start()任务不是在uvm_sequence中声明的,而是在uvm_sequence_base中声明的,所以uvm_sequence继承了uvm_sequence_base中的start()方法
virtual task start ( uvm_sequencer_base sequencer, // 目标sequencer (必须指定) uvm_sequence_base parent_sequence = null, // 父sequence的句柄 (可选) int this_priority = -1, // 优先级 bit call_pre_post = 1 // 是否自动调用pre_body/post_body, 默认会调用 );// 示例1:基本用法(使用默认参数) seq.start(m_sequencer); // 示例2:指定父sequence(用于层次化报告) seq.start(m_sequencer, this); // this指向当前启动它的父sequence // 示例3:设置优先级 seq.start(m_sequencer, null, 200); // 优先级设为200 // 示例4:不调用pre_body()和post_body() seq.start(m_sequencer, null, 100, 0);set_item_context):sequencer以及parent_sequence关联,这是建立 UVM 层次结构的第一步。将传入的seqr的句柄赋给sequence中的m_sequencer,m_sequencer是在uvm_sequence_item中定义的m_sequence_state_mutex):try_get(1)检查该 sequence 是否已经在运行。如果锁获取失败,抛出FATAL错误,防止同一个 sequence 实例同时被启动两次。children_array列表中,用于后续的资源管理和状态追踪。this_priority):clear_response_queue):response_queue,确保之前运行留下的过期响应(Response)不会干扰本次执行。m_sequencer.begin_tr开启事务记录,这允许用户在波形仿真器(如 Verdi)中观察到 sequence 的开始和持续时间。m_sequencer.m_register_sequence(this)。此时 Sequencer 正式感知到该 sequence 的存在,并分配sequence_id(将其初始化为 -1 是为了重置之前的运行状态)。m_sequence_state = ...后跟#0。#0的作用是让出仿真时间槽(Delta Cycle),确保外部通过wait语句监控状态的进程能够捕捉到状态的变化。pre_start():最先执行的回调。pre_body():仅当call_pre_post == 1时调用。pre_do/mid_do):如果作为子 sequence 运行,会触发父类的这些回调,允许父类对子类进行干预。body():核心用户逻辑,产生激励的地方。post_do):body完成后的后处理。post_body():仅当call_pre_post == 1时调用。post_start():最后执行的回调。fork块结束时状态不是FINISHED或STOPPED,通常意味着用户在外部使用了disable fork。此时 UVM 会发出警告并强制触发this.kill()来回收资源。m_sequencer.end_tr(this),在波形上标记该 sequence 结束。clean_exit_sequence):children_array中删除引用,防止内存泄漏。m_init_phase_daps(1)负责重置与 Phase 相关的权限,确保下次运行时的环境是干净的。start()方法不仅是调用body()。它是一个精密的调度器,通过处理优先级分配、多进程并发、事务追踪、Objection 管理以及健壮的退出机制,确保了 sequence 在 UVM 复杂环境下的安全运行。