<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>sqlmap&#39;s Blog</title>
  
  <subtitle>IC 验证工程师 | UVM · SystemVerilog</subtitle>
  <link href="https://sqlmaps.com/atom.xml" rel="self"/>
  
  <link href="https://sqlmaps.com/"/>
  <updated>2026-10-17T20:13:37.242Z</updated>
  <id>https://sqlmaps.com/</id>
  
  <author>
    <name>sqlmap3</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>博通 Jericho+Ramon 与 Tomahawk 技术架构与区别详解</title>
    <link href="https://sqlmaps.com/2026/10/18/%E5%8D%9A%E9%80%9A-Jericho-Ramon-vs-Tomahawk/"/>
    <id>https://sqlmaps.com/2026/10/18/%E5%8D%9A%E9%80%9A-Jericho-Ramon-vs-Tomahawk/</id>
    <published>2026-10-18T00:00:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<p>博通的交换芯片有两条完全不同的技术路线：一条是为运营商路由而生的分布式多芯片架构（StrataDNX），一条是为云数据中心而生的单芯片高速交换（StrataXGS）。这一篇把两家的世代规格、系统架构、关键机制（cell 交换、VOQ、信用流控、深缓冲）以及 leaf、spine、Clos 等名词一次讲清。</p><blockquote><p><strong>一句话结论</strong>：<strong>Tomahawk 是”一颗芯片打天下”的高速交换机</strong>——单芯片、低时延、浅缓冲、每比特成本最低；<strong>Jericho + Ramon 是”多芯片分布式”的深缓冲路由器</strong>——大路由表、GB 级 HBM 缓冲、fabric 内天生无损，可扩展成一台数百 Tbps 的逻辑路由器。</p></blockquote><p>文中数字的置信度标注：<code>[官方]</code> Broadcom 新闻稿&#x2F;产品页；<code>[媒体]</code> 行业媒体报道；<code>[第三方·低置信]</code> 第三方整理站点，数字仅供参考。各厂商公布带宽的统计口径不完全一致，细节见「口径说明与未核实事项」一节。资料检索时间：2026-10-18。</p><h2 id="01-两大家族速览"><a href="#01-两大家族速览" class="headerlink" title="01 两大家族速览"></a>01 两大家族速览</h2><p>两条产品线同属博通，但基因不同：StrataDNX 源自 2009 年底收购的 Dune Networks（高端路由 fabric 技术），StrataXGS 则是博通自家的数据中心交换血统。理解它们的区别，先记住分工：**DNX 解决”路由规模与确定性”，XGS 解决”带宽密度与时延”**。</p><h3 id="Jericho-Ramon（StrataDNX-·-Routing）"><a href="#Jericho-Ramon（StrataDNX-·-Routing）" class="headerlink" title="Jericho + Ramon（StrataDNX · Routing）"></a>Jericho + Ramon（StrataDNX · Routing）</h3><p>Jericho 是包处理器 &#x2F; 流量管理器（FAP），负责查表、队列、QoS、安全；Ramon 是纯 fabric 交换单元（FE），只做 cell 级交叉交换。两者用专用 fabric 接口互连，拼成 DDC 分布式机框。</p><table><thead><tr><th>项目</th><th>数值</th></tr></thead><tbody><tr><td>单芯片带宽</td><td>0.9T（Jericho+）→ 28.8T（Jericho3-AI）</td></tr><tr><td>缓冲</td><td>HBM 深缓冲，GB 级（最高 8GB&#x2F;芯片）</td></tr><tr><td>转发表</td><td>百万级路由，可外置 KBP 扩展</td></tr><tr><td>典型场景</td><td>运营商核心&#x2F;边缘、DCI、AI 后端 fabric</td></tr></tbody></table><h3 id="Tomahawk（StrataXGS-·-Datacenter-Switching）"><a href="#Tomahawk（StrataXGS-·-Datacenter-Switching）" class="headerlink" title="Tomahawk（StrataXGS · Datacenter Switching）"></a>Tomahawk（StrataXGS · Datacenter Switching）</h3><p>一颗 SoC 完成全部交换与路由，做成一台固定盒式交换机，部署在数据中心 leaf-spine 拓扑的每一层。每代带宽翻倍，是 hyperscaler（超大规模云厂商）的默认选择。</p><table><thead><tr><th>项目</th><th>数值</th></tr></thead><tbody><tr><td>单芯片带宽</td><td>3.2T（TH1，2014）→ 102.4T（TH6，2025）</td></tr><tr><td>缓冲</td><td>片上共享浅缓冲，MB 级（16MB → 约 165MB）</td></tr><tr><td>转发表</td><td>较小（UFT 128K 起），面向数据中心规模</td></tr><tr><td>典型场景</td><td>云数据中心 ToR&#x2F;Leaf&#x2F;Spine、AI scale-out</td></tr></tbody></table><h2 id="02-架构图：两种组网哲学"><a href="#02-架构图：两种组网哲学" class="headerlink" title="02 架构图：两种组网哲学"></a>02 架构图：两种组网哲学</h2><p>最核心的区别在拓扑层面：Tomahawk 是<strong>一颗芯片一台设备</strong>，多台设备用标准以太网（ECMP）组网；Jericho+Ramon 是<strong>多颗芯片一台设备</strong>——线卡芯片和 fabric 芯片被拆到不同白盒里，用线缆代替机框背板，对外是一台逻辑路由器。</p><pre><code class="highlight mermaid">flowchart TD    subgraph NCF[&quot;NCF（Network Cloud Fabric）— Ramon 芯片 · 只交换 cell，不做包处理&quot;]        R1[Ramon FE&lt;br/&gt;cell crossbar]        R2[Ramon FE&lt;br/&gt;cell crossbar]        R3[Ramon FE&lt;br/&gt;cell crossbar]    end    subgraph NCP[&quot;NCP（Network Cloud Packet）— Jericho 芯片（FAP）&quot;]        J1[Jericho FAP&lt;br/&gt;NCP 白盒 · 线卡&lt;br/&gt;VOQ · HBM 深缓冲]        J2[Jericho FAP&lt;br/&gt;NCP 白盒 · 线卡&lt;br/&gt;VOQ · HBM 深缓冲]        J3[Jericho FAP&lt;br/&gt;NCP 白盒 · 线卡&lt;br/&gt;VOQ · HBM 深缓冲]        J4[Jericho FAP&lt;br/&gt;NCP 白盒 · 线卡&lt;br/&gt;VOQ · HBM 深缓冲]    end    R1 --- J1    R1 --- J2    R1 --- J3    R1 --- J4    R2 --- J1    R2 --- J2    R2 --- J3    R2 --- J4    R3 --- J1    R3 --- J2    R3 --- J3    R3 --- J4    J1 --&gt; N1[网络端口&lt;br/&gt;业务流量]    J2 --&gt; N2[网络端口&lt;br/&gt;业务流量]    J3 --&gt; N3[网络端口&lt;br/&gt;业务流量]    J4 --&gt; N4[网络端口&lt;br/&gt;业务流量]</code></pre><p><em>图 1 · DDC（分布式分解式机框）：传统机框的”线卡 + fabric 卡 + 背板”被拆成 NCP &#x2F; NCF 独立白盒 + 机架间线缆。Jericho 的前面板一半端口接业务（网络端口）、一半接 NCF（fabric 端口）。整个系统由 NCC 控制器统一管理，对外 &#x3D; 一台逻辑路由器。</em></p><pre><code class="highlight mermaid">flowchart TD    subgraph Spine[&quot;Spine 层 — Tomahawk 单芯片交换机（只连 Leaf）&quot;]        S1[Tomahawk&lt;br/&gt;51.2T · 共享浅缓冲]        S2[Tomahawk&lt;br/&gt;51.2T · 共享浅缓冲]    end    subgraph Leaf[&quot;Leaf / ToR 层 — Tomahawk 单芯片交换机&quot;]        L1[Tomahawk&lt;br/&gt;一颗芯片 = 一台交换机]        L2[Tomahawk&lt;br/&gt;cut-through 低时延]        L3[Tomahawk&lt;br/&gt;PFC / ECN 无损以太网]        L4[Tomahawk&lt;br/&gt;RoCEv2 / RDMA]    end    S1 --- L1    S1 --- L2    S1 --- L3    S1 --- L4    S2 --- L1    S2 --- L2    S2 --- L3    S2 --- L4    L1 --&gt; R1[服务器 / GPU 机架]    L2 --&gt; R2[服务器 / GPU 机架]    L3 --&gt; R3[服务器 / GPU 机架]    L4 --&gt; R4[服务器 / GPU 机架]</code></pre><p><em>图 2 · Tomahawk 的世界：每台交换机自成一体，扩展靠多台设备按 leaf-spine（Clos）组网，设备之间是标准以太网，没有专用 fabric 接口，也没有跨设备的统一调度。</em></p><pre><code class="highlight mermaid">flowchart LR    A[以太网包进入&lt;br/&gt;变长帧 · 查表&lt;br/&gt;Elastic Pipe 处理] --&gt; B[入口 Jericho 切片&lt;br/&gt;切成定长 cell&lt;br/&gt;按出口进 VOQ 排队]    B --&gt; C[Ramon fabric 喷洒&lt;br/&gt;cell 均匀分发到全部链路&lt;br/&gt;信用流控 · 无拥塞无丢包&lt;br/&gt;FE 只交换，不改包]    C --&gt; D[出口 Jericho 重组&lt;br/&gt;cell → 包 · 整形&lt;br/&gt;层级 QoS 调度发出]    D --&gt; E[出]</code></pre><p><em>图 3 · cell 交换是 DNX 的灵魂：定长 cell 让 fabric 调度与包长解耦，喷洒（spraying）让每条 fabric 链路负载一致，信用（credit）让发送方永远不会压垮接收方。对比：Tomahawk 是整包 cut-through 转发——收到包头就开始转发，不切片、不重组，时延最低，但也没有跨端口的全局调度。</em></p><h2 id="03-Jericho-家族（StrataDNX）"><a href="#03-Jericho-家族（StrataDNX）" class="headerlink" title="03 Jericho 家族（StrataDNX）"></a>03 Jericho 家族（StrataDNX）</h2><p>Jericho 是 FAP（Fabric Access Processor）：既是线卡上的包处理器——查表、分类、policing、层级流量管理全在它身上——又握有通往 Ramon fabric 的专用接口。它为”路由”而生：转发表按互联网规模设计，缓冲按”吸收运营商网络突发”设计。</p><table><thead><tr><th>世代</th><th>型号</th><th>发布时间</th><th>带宽</th><th>工艺</th><th>端口速率</th><th>关键特性</th></tr></thead><tbody><tr><td>Jericho</td><td>BCM88650</td><td>2012-04</td><td>系统级 &gt;100T*</td><td>未公开</td><td>10&#x2F;40&#x2F;100G</td><td>首款 StrataDNX SoC；单流 200Gbps L2–L4 处理；深缓冲流量管理</td></tr><tr><td>Jericho+</td><td>BCM88680</td><td>2015-03</td><td>900Gbps&#x2F;芯片</td><td>28nm</td><td>10&#x2F;25&#x2F;40&#x2F;50&#x2F;100G</td><td>集成 fabric 接口；系统级 &gt;100Tbps；单级 fabric 建 9000×100G 核心</td></tr><tr><td>Jericho2</td><td>BCM88850 &#x2F; BCM88690</td><td>2018-03-06</td><td>10Tbps</td><td>16nm</td><td>100&#x2F;200&#x2F;400G</td><td>Elastic Pipe；HBM2 2.5D 封装深缓冲；208×50G PAM4 SerDes；最高 260 万 IPv4 路由</td></tr><tr><td><strong>Jericho2c+ ★</strong></td><td>BCM88800</td><td>2020-09-10</td><td>14.4Tbps</td><td>7nm</td><td>100&#x2F;200&#x2F;400G</td><td>全端口线速 MACsec&#x2F;IPsec；HBM 深缓冲；层级流量管理器；KBP 扩展；支持 SONiC</td></tr><tr><td>Jericho3</td><td>BCM88830</td><td>未核实</td><td>—</td><td>—</td><td>—</td><td>标准路由版未能从公开渠道核实独立规格，见下方说明</td></tr><tr><td><strong>Jericho3-AI ★</strong></td><td>BCM88890</td><td>2023-04-18</td><td>28.8Tbps</td><td>5nm</td><td>200&#x2F;400&#x2F;800G</td><td>为 AI 集群优化：完美负载均衡（喷洒）、端到端调度、32K GPU@800G、零影响故障切换</td></tr></tbody></table><p>* 初代 Jericho 的 2012 年新闻稿只给系统级数字（配 FE1600 构建 &gt;100Tbps、最高 4000 个 100GbE 端口的平台），未公布单芯片带宽。</p><h3 id="Jericho-·-BCM88650（2012）—-配-FE1600（BCM88750）"><a href="#Jericho-·-BCM88650（2012）—-配-FE1600（BCM88750）" class="headerlink" title="Jericho · BCM88650（2012）— 配 FE1600（BCM88750）"></a>Jericho · BCM88650（2012）— 配 FE1600（BCM88750）</h3><ul><li>2012 年 4 月 30 日发布，被称为”世界上最高密度的 100GbE 交换解决方案”，可构建超过 100Tbps、最高 4000 个 100GbE 端口的交换平台。<code>[官方]</code></li><li>单芯片可对单条 200Gbps 流量做 L2–L4 线速处理（高级包分类 + 深缓冲流量管理），面向数据中心、运营商以太网和分组传送网。<code>[官方]</code></li><li>技术源头：Broadcom 2009 年底收购的 Dune Networks 的高端交换 fabric 技术——DNX 的整套 cell&#x2F;VOQ&#x2F;信用机制都源于此。<code>[媒体 EE Times]</code></li></ul><h3 id="Jericho-·-BCM88680（2015）—-28nm-·-配-BCM88770（FE3600）"><a href="#Jericho-·-BCM88680（2015）—-28nm-·-配-BCM88770（FE3600）" class="headerlink" title="Jericho+ · BCM88680（2015）— 28nm · 配 BCM88770（FE3600）"></a>Jericho+ · BCM88680（2015）— 28nm · 配 BCM88770（FE3600）</h3><ul><li>单芯片处理 900Gbps 流量，最多 9 个 100G 全双工端口的 L2–L4 处理，集成深缓冲流量管理与 fabric 接口；是 Dune 可扩展交换产品线第七代。<code>[官方产品页]</code></li><li>与 BCM88770 fabric element 搭配，可构建超过 100Tbps 的单级 fabric 核心&#x2F;边缘交换机，或多机框互连的可扩展核心平台（最多 9000 个 100GbE 端口）。<code>[官方产品页]</code></li></ul><h3 id="Jericho2-·-BCM88850-BCM88690（2018）—-16nm-·-配-FE9600"><a href="#Jericho2-·-BCM88850-BCM88690（2018）—-16nm-·-配-FE9600" class="headerlink" title="Jericho2 · BCM88850 &#x2F; BCM88690（2018）— 16nm · 配 FE9600"></a>Jericho2 · BCM88850 &#x2F; BCM88690（2018）— 16nm · 配 FE9600</h3><p>带宽 <strong>10 Tbps</strong> · SerDes <strong>208×50G PAM4</strong> · 端口 <strong>最高 36×400G</strong> · 路由表 <strong>260 万 IPv4</strong> · 缓冲 <strong>HBM2 · 最高 8GB*</strong></p><ul><li>2018 年 3 月 6 日与 FE9600 同步发布；相对 Jericho+ 带宽 5 倍、每 Gb 功耗降低 70%。<code>[官方新闻稿]</code></li><li>首款采用 <strong>2.5D 堆叠（HBM2）</strong> 的商用网络芯片，大规模片上缓冲；<strong>Elastic Pipe™</strong> 可编程包处理管线，向特定客户提供 C++ 可编程工具。<code>[媒体 EE Times]</code></li><li>支持 IPv4&#x2F;IPv6、MPLS、Segment Routing——典型的运营商路由协议栈。<code>[媒体 TechTarget]</code></li></ul><p>* 8GB 为第三方存档的官方 PR 口径（双 HBM 配置）；另有媒体（Gazettabyte）称 Jericho2 为”4.8T 容量”，与官方 10Tbps 口径不同，见「口径说明」。</p><h3 id="Jericho2c-·-BCM88800（2020）★-当前运营商主力-—-7nm"><a href="#Jericho2c-·-BCM88800（2020）★-当前运营商主力-—-7nm" class="headerlink" title="Jericho2c+ · BCM88800（2020）★ 当前运营商主力 — 7nm"></a>Jericho2c+ · BCM88800（2020）★ 当前运营商主力 — 7nm</h3><p>带宽 <strong>14.4 Tbps</strong> · 构成 <strong>7.2T 网络 + 7.2T fabric</strong> · 接口 <strong>144×100G</strong> · 功耗 <strong>约 350W（前代 400W）*</strong></p><ul><li>2020 年 9 月 10 日宣布 sampling，14.4Tbps 路由能力，全网络端口<strong>线速集成安全（MACsec&#x2F;IPsec）</strong>——加密不再需要外挂芯片。<code>[官方新闻稿]</code></li><li><strong>2 颗芯片即组成 36×400G 线卡</strong>（每芯片 18×400G）且集成安全；此前同样配置需要 2×Jericho2 + 19 颗专用 MAC 芯片 &#x3D; 21 颗——占板面积、复杂度、功耗、成本全面下降。<code>[官方新闻稿]</code></li><li>相对前代 3 倍路由性能、功耗减半；基于 HBM 的深包缓冲 + 运营商级 <strong>Hierarchical Traffic Manager</strong>（层级流量管理器，端到端 VOQ）；通过外置 <strong>KBP</strong> 扩展转发表、计数器与 ACL 规模；支持 SONiC。<code>[官方新闻稿]</code></li><li>与 Ramon 配套单机框吞吐超过 300Tbps；无缝兼容既有 Jericho2&#x2F;Ramon 方案。采用方包括 Arista 7280R3 系列、Cisco NCS5500 线卡。<code>[官方新闻稿]</code> <code>[媒体 SDxCentral]</code></li><li>部署案例：AT&amp;T 的核心&#x2F;边缘网向 DDC 拓扑迁移采用 Jericho2，Jericho2c+ 用于进一步扩容并增加安全连接。<code>[官方新闻稿引 AT&amp;T 表态]</code></li></ul><p>* 功耗数字来自 Linley Group 分析（die shrink 后 400W → 350W，一部分预算用于加端口、一部分为净节能），经第三方转述。<code>[第三方]</code></p><blockquote><p><strong>Jericho3（BCM88830）标准路由版 — 公开资料存疑</strong>：未能从公开渠道核实标准路由版 Jericho3（BCM88830）的独立发布时间、带宽、工艺与端口规格。已核实的关键事实是：行业媒体 Gazettabyte（2023-06-07）明确指出 Jericho3 世代的<strong>首款</strong>芯片是面向 AI 的 Jericho3-AI。白盒厂商语境中的”Jericho3 系统”通常也指 Jericho3-AI 芯片的系统。如需 BCM88830 详情，建议查 Broadcom 官方产品页或数据手册。</p></blockquote><h3 id="Jericho3-AI-·-BCM88890（2023）★-重点-—-5nm-TSMC-·-配-Ramon3"><a href="#Jericho3-AI-·-BCM88890（2023）★-重点-—-5nm-TSMC-·-配-Ramon3" class="headerlink" title="Jericho3-AI · BCM88890（2023）★ 重点 — 5nm TSMC · 配 Ramon3"></a>Jericho3-AI · BCM88890（2023）★ 重点 — 5nm TSMC · 配 Ramon3</h3><p>带宽 <strong>28.8 Tbps</strong> · SerDes <strong>共 304 个</strong> · 下行 <strong>144×106G PAM4</strong> · 上行 fabric <strong>160 个 SerDes</strong> · 端口 <strong>18×800G &#x2F; 36×400G &#x2F; 72×200G</strong></p><ul><li>2023 年 4 月 18 日发布，28.8Tbps，5nm，数百亿晶体管；定位直接对标 NVIDIA InfiniBand 的 AI 集群后端网络。<code>[官方新闻稿]</code></li><li><strong>AI 优化四要素</strong>：① 完美负载均衡——流量均匀喷洒到 fabric 全部链路；② 无拥塞操作——端到端流量调度、无流碰撞、无抖动；③ 超高基数——单集群 32,000 个 GPU @800Gbps；④ 零影响故障切换——sub-10ns 自动路径收敛，不影响作业完成时间。<code>[官方新闻稿]</code></li><li>Fabric 总带宽 26Pb&#x2F;s（约 4 倍于前代），每 Gb 功耗降低 40%；官方称 NCCL 测试中作业完成时间比 InfiniBand 方案短约 10%。<code>[官方新闻稿]</code></li><li><strong>流量模型</strong>：28.8T 容量一半接机架内 GPU 的 NIC、一半接 fabric；14.4T 的 fabric 链路被当作一条巨大的逻辑管道，流量均匀”喷洒”出去，目的端 Jericho3-AI 再重组——GPU 对喷洒完全无感知，不存在 ECMP 哈希碰撞问题。<code>[媒体 Gazettabyte]</code></li><li><strong>接收端流控</strong>：应对 incast（多对一汇聚），流量在发送端排队，接收端按需调度每个发送端”每次发一点”；只有需要减速的 GPU 降速，不误伤相邻 GPU。<code>[媒体 Gazettabyte]</code></li><li>包处理管线比核心&#x2F;边缘路由版 Jericho 更简单（为 AI 场景降本降时延）；SerDes 支持 4 米铜缆直连 GPU-ToR、支持 linear-drive 光模块（省 DSP、省功耗）。<code>[媒体 Gazettabyte]</code></li></ul><h2 id="04-Ramon-家族（Fabric-Element）"><a href="#04-Ramon-家族（Fabric-Element）" class="headerlink" title="04 Ramon 家族（Fabric Element）"></a>04 Ramon 家族（Fabric Element）</h2><p>Ramon 是 DNX 家族里”沉默的另一半”：一颗低功耗、高带宽、基于 cell 的交叉开关（crossbar）。它<strong>不查表、不改包、不做任何包处理</strong>，只负责把入口 Jericho 送来的 cell 以最快速度送到出口 Jericho。传统机框里它就是 fabric 卡，DDC 里它就是 NCF 白盒。</p><table><thead><tr><th>世代</th><th>型号 &#x2F; 商品名</th><th>发布时间</th><th>Fabric 带宽</th><th>配套 Jericho</th><th>说明</th></tr></thead><tbody><tr><td>Ramon</td><td>FE1600（BCM88750）</td><td>2012-04</td><td>未公开</td><td>Jericho</td><td>与初代 Jericho 同步发布</td></tr><tr><td>Ramon+</td><td>FE3600（BCM88770）</td><td>约 2016</td><td>未公开</td><td>Jericho+</td><td>Broadcom 官方 BCM88680 页面明确搭配 BCM88770</td></tr><tr><td>Ramon2</td><td>FE9600</td><td>2018-03-06</td><td>9.6Tbps</td><td>Jericho2</td><td>192×50G PAM4 SerDes；每 Gb 功耗比 FE3600 降 50%+</td></tr><tr><td><strong>Ramon3</strong></td><td>BCM88780</td><td>Jericho3 世代</td><td>系统级 51.2T*</td><td>Jericho3 &#x2F; Jericho3-AI</td><td>单芯片规格未公开，见下方</td></tr></tbody></table><h3 id="Jericho-与-Ramon-如何互连"><a href="#Jericho-与-Ramon-如何互连" class="headerlink" title="Jericho 与 Ramon 如何互连"></a>Jericho 与 Ramon 如何互连</h3><ul><li><strong>专用 fabric 接口（Fabric Interface, FI）</strong>：Jericho 芯片上的 SerDes 分成两组——一组做网络端口，一组专连 Ramon。以 Jericho3-AI 为例：共 304 个 SerDes，144 个下行接网络，160 个上行接 Ramon3 fabric。<code>[媒体 The Next Platform]</code></li><li><strong>包切片（cell-slicing）</strong>：包在入口 Jericho 被切成定长 cell，经 fabric 接口<strong>均匀喷洒（perfect load balancing）</strong>到所有 fabric 链路，Ramon 只做 cell 级交叉交换，目的 Jericho 重组。<code>[官方 PR 存档]</code></li><li><strong>基于信用的流控（credit-based flow control）</strong>：FE 与 FAP 之间发送 cell 前必须持有对方授予的信用，从机制上保证 fabric 内部无拥塞、无丢包。<code>[官方 PR 存档]</code></li><li><strong>分工边界</strong>：StrataDNX &#x3D; FAP + FE。Jericho（FAP）管包处理、层级流量管理、VOQ；Ramon（FE）只管 cell 交换。这是它和”一颗芯片全包”的 Tomahawk 最根本的架构差异。<code>[官方博客]</code></li></ul><h3 id="Ramon3-·-BCM88780-—-系统级数据（白盒口径）"><a href="#Ramon3-·-BCM88780-—-系统级数据（白盒口径）" class="headerlink" title="Ramon3 · BCM88780 — 系统级数据（白盒口径）"></a>Ramon3 · BCM88780 — 系统级数据（白盒口径）</h3><ul><li>2024 年 10 月 DriveNets &#x2F; Accton 发布的 AI 网络白盒 <strong>NCF-2（Accton AS9936-128D）</strong> 基于 Ramon-3，提供 <strong>128 个 800G fabric 端口</strong>；DriveNets 称该白盒为 51.2Tbps、高效 cell 交换、低功耗低时延。<code>[媒体 新闻稿 / DriveNets 博客]</code></li><li>同期发布的 <strong>NCP-5（Accton ASA926-18XKE）</strong> 基于 Jericho3-AI：18×800G 网络端口 + 20×800G fabric 端口——一组真实的 NCP&#x2F;NCF 搭配样本。<code>[媒体 新闻稿]</code></li></ul><p>* Ramon3 单芯片规格（SerDes 数量、工艺）未公开；白盒”51.2Tbps &#x2F; 128×800G”存在口径疑问（128×800G &#x3D; 102.4T），见「口径说明」。</p><h2 id="05-DDC-系统架构与关键机制"><a href="#05-DDC-系统架构与关键机制" class="headerlink" title="05 DDC 系统架构与关键机制"></a>05 DDC 系统架构与关键机制</h2><p>DDC（Distributed Disaggregated Chassis，分布式分解式机框）把传统纵向集成机框——同一厂商的硬件加软件、线卡插在背板上经 fabric 卡互连——彻底拆开：全部由标准白盒 + 线缆组成，对外仍表现为<strong>一台逻辑路由器</strong>。2019 年 AT&amp;T 把 DDC 硬件规范贡献给 OCP，此后 Edgecore、Accton、Delta 等白盒厂商纷纷跟进，软件侧有商业 NOS 与 SONiC，用户可自由选择硬件与软件厂商。</p><table><thead><tr><th>DDC 角色</th><th>白盒形态</th><th>芯片</th><th>对应传统机框部件</th></tr></thead><tbody><tr><td>NCP（Network Cloud Packet forwarder）</td><td>1RU&#x2F;2RU 白盒，1–2 颗 FAP</td><td>Jericho2 &#x2F; Jericho2c+</td><td>线卡（Line Card）</td></tr><tr><td>NCF（Network Cloud Fabric）</td><td>白盒</td><td>Ramon 系列</td><td>Fabric 卡</td></tr><tr><td>NCC（Network Cloud Controller）</td><td>控制器</td><td>—</td><td>主控 &#x2F; 路由引擎</td></tr></tbody></table><p>NCP 前面板分两组端口：<strong>网络端口</strong>（接业务&#x2F;服务器）+ <strong>fabric 端口</strong>（接 NCF）。<code>[官方博客]</code> DriveNets 自 2016 年起基于 DNX（Ramon + Jericho2）构建 Network Cloud：从 2.4Tbps 单白盒扩展到数百 Tbps 的白盒集群，全部作为一台逻辑路由器、单一命令行管理；2023 年推出 AI Fabric（Jericho3-AI + Ramon3）。<code>[媒体 DriveNets 博客]</code></p><h3 id="六个关键机制"><a href="#六个关键机制" class="headerlink" title="六个关键机制"></a>六个关键机制</h3><p><strong>Clos Fabric 拓扑（multi-stage Clos）</strong>：NCP（线卡）全连接到 NCF（fabric 卡），构成多级 Clos；规模不够就加级数。这是 DDC 的物理基础——<strong>机框背板被”拉长”成了机架间的线缆 fabric</strong>。用大量小芯片多级互连，实现任意规模的无阻塞交换。</p><p><strong>Cell 交换（cell-based switching）</strong>：包在入口 Jericho 被切成<strong>定长 cell</strong>，喷洒过 fabric，出口重组。定长使 fabric 的调度与包长彻底解耦：不管外面来的是 64 字节小包还是 9K 巨帧，fabric 内部永远是整齐划一的 cell 流，<strong>负载天然均衡</strong>，也不会被长包堵住。</p><p><strong>VOQ 虚拟输出队列（Virtual Output Queue）</strong>：入口 Jericho 为<strong>每个出口端口 × 每个优先级</strong>维护独立虚拟队列，从根上消除<strong>队头阻塞</strong>：去往拥塞出口的包，只堵在自己的 VOQ 里，绝不挡住去往空闲出口的包。Jericho2c+ 的层级流量管理器即基于端到端 VOQ。</p><p><strong>基于信用的流控（credit-based flow control）</strong>：发送 cell 前必须持有接收端授予的”信用”，接收端按自身缓冲能力发信用、收回信用。<strong>没有信用就不许发</strong>——从机制上保证 fabric 内部永不拥塞、永不丢包，比以太网 PFC 的”出事后暂停”精细得多。</p><p><strong>HBM 深缓冲（deep buffer）</strong>：Jericho2 起集成 <strong>HBM2</strong>（官方口径约为片上 SRAM 缓冲的 160 倍；第三方数据：双 HBM 配置最高 8GB 包存储）。GB 级缓冲用来吸收突发流量、支撑运营商级 QoS，以及在 AI 场景吸收 incast 汇聚冲击——这是 Tomahawk 的 MB 级片上缓冲做不到的。</p><p><strong>AI Scheduled Fabric（Jericho3-AI + Ramon3）</strong>：AI 场景的演进形态：Jericho3-AI 作 leaf、Ramon 作 spine，<strong>全部智能在 leaf</strong>。入口 leaf 建 VOQ 缓存并向接收端 leaf 请求发送信用，<strong>接收端就绪才放行</strong>——数据喷洒 + 信用调度 + 接收端流控 + 微秒级故障恢复，整网无拥塞、无流碰撞、无抖动，正面竞争 InfiniBand。</p><h2 id="06-Tomahawk-家族（StrataXGS）"><a href="#06-Tomahawk-家族（StrataXGS）" class="headerlink" title="06 Tomahawk 家族（StrataXGS）"></a>06 Tomahawk 家族（StrataXGS）</h2><p>Tomahawk 的进化史简单粗暴：<strong>每代带宽翻倍</strong>。秘诀是 SerDes 速率与数量同步翻倍 + 工艺进步。它不追求大表和深缓冲，追求的是单位带宽的成本、功耗与时延——这正是云厂商数据中心的命脉。</p><pre><code class="highlight mermaid">flowchart LR    A[TH1&lt;br/&gt;3.2T] --&gt;|翻倍| B[TH2&lt;br/&gt;6.4T] --&gt;|翻倍| C[TH3&lt;br/&gt;12.8T] --&gt;|翻倍| D[TH4&lt;br/&gt;25.6T] --&gt;|翻倍| E[TH5&lt;br/&gt;51.2T] --&gt;|翻倍| F[TH6&lt;br/&gt;102.4T]</code></pre><p>Tomahawk 严格每代翻倍：3.2 → 6.4 → 12.8 → 25.6 → 51.2 → 102.4T。Jericho 单芯片带宽低于同期 Tomahawk——它的扩展性不在单芯片，而在 DDC 系统级（J2C+ 机框 &gt;300T、J3-AI fabric 26Pb&#x2F;s）。</p><table><thead><tr><th>世代</th><th>型号</th><th>发布时间</th><th>带宽</th><th>工艺</th><th>SerDes</th><th>典型端口配置</th><th>目标用途</th></tr></thead><tbody><tr><td>Tomahawk 1</td><td>BCM56960</td><td>2014-09-25</td><td>3.2Tbps</td><td>28nm</td><td>128×25G</td><td>32×100G &#x2F; 128×25G</td><td>云数据中心 ToR&#x2F;Leaf&#x2F;Spine，25G&#x2F;100G 升级</td></tr><tr><td>Tomahawk 2</td><td>BCM56970</td><td>2016-10-11</td><td>6.4Tbps</td><td>16nm FF+</td><td>256×25G</td><td>64×100G &#x2F; 128×50G</td><td>高密度 100G Spine&#x2F;ToR</td></tr><tr><td>Tomahawk 3</td><td>BCM56980</td><td>2017 年底 sampling</td><td>12.8Tbps</td><td>16nm</td><td>256×50G PAM4</td><td>32×400G &#x2F; 128×100G</td><td>100G&#x2F;400G 汇聚，RDMA&#x2F;存储</td></tr><tr><td>Tomahawk 4</td><td>BCM56990</td><td>2019 年底 sampling</td><td>25.6Tbps</td><td>7nm</td><td>512×50G PAM4</td><td>64×400G &#x2F; 256×100G</td><td>400G Spine，AI 集群</td></tr><tr><td><strong>Tomahawk 5 ★</strong></td><td>BCM78900</td><td>2022 发布 &#x2F; 2023-03 量产</td><td>51.2Tbps</td><td>5nm</td><td>512×100G PAM4</td><td>64×800G &#x2F; 256×200G</td><td>AI scale-out fabric，800G 时代</td></tr><tr><td><strong>Tomahawk 6 ★</strong></td><td>—</td><td>2025-06</td><td>102.4Tbps</td><td>3nm chiplet</td><td>100G&#x2F;200G</td><td>512×200G</td><td>百万 XPU 级 AI 集群</td></tr></tbody></table><p>关于”Tomahawk 1+”：检索未发现 Broadcom 官方的独立 “Tomahawk+” 世代——BCM56960 系列内有容量变体，但不构成单独一代，故不设条目。</p><h3 id="Tomahawk-1-·-BCM56960（2014）—-28nm-·-70-亿-晶体管"><a href="#Tomahawk-1-·-BCM56960（2014）—-28nm-·-70-亿-晶体管" class="headerlink" title="Tomahawk 1 · BCM56960（2014）— 28nm · 70 亿+晶体管"></a>Tomahawk 1 · BCM56960（2014）— 28nm · 70 亿+晶体管</h3><p>带宽 <strong>3.2 Tbps</strong> · 时延 <strong>亚 400ns 端口到端口</strong> · 缓冲 <strong>16MB（4×4MB）*</strong> · 转发表 <strong>UFT 128K*</strong></p><ul><li>2014 年 9 月 25 日发布，128×25G SerDes；32×100G &#x2F; 64×40-50G &#x2F; 128×25G；Smart-Buffer；支持 RoCE&#x2F;RoCEv2、BroadView 遥测、VXLAN&#x2F;NVGRE&#x2F;MPLS、OpenFlow 1.3。<code>[媒体 Converge Digest / LightReading]</code></li><li>定位：把数据中心 ToR 从 10G、Spine 从 40G 升级到 25G&#x2F;100G——25G 服务器接入时代的起点。<code>[媒体 LightReading]</code></li></ul><p>* 缓冲与表项来自 Cisco 技术幻灯片（第三方整理）。<code>[第三方]</code></p><h3 id="Tomahawk-2-·-BCM56970（2016）—-16nm-FF-TSMC"><a href="#Tomahawk-2-·-BCM56970（2016）—-16nm-FF-TSMC" class="headerlink" title="Tomahawk 2 · BCM56970（2016）— 16nm FF+ TSMC"></a>Tomahawk 2 · BCM56970（2016）— 16nm FF+ TSMC</h3><p>带宽 <strong>6.4 Tbps</strong> · SerDes <strong>256×25G</strong> · 缓冲 <strong>42MB*</strong> · 转发表 <strong>UFT 256K*</strong></p><ul><li>2016 年 10 月 11 日发布，业界首颗 64 端口 100GE 交换芯片；带宽与资源容量（路由、包存储、FlexGS）相对 TH1 全面翻倍。<code>[官方新闻稿]</code></li><li>Dynamic Flow Distribution（大规模 L3&#x2F;ECMP 负载分担）、增强 BroadView 遥测。<code>[官方新闻稿]</code></li></ul><p>* 缓冲与表项来自 Cisco 技术幻灯片（第三方整理）。<code>[第三方]</code></p><h3 id="Tomahawk-3-·-BCM56980（2018）—-16nm（与-TH2-同工艺）"><a href="#Tomahawk-3-·-BCM56980（2018）—-16nm（与-TH2-同工艺）" class="headerlink" title="Tomahawk 3 · BCM56980（2018）— 16nm（与 TH2 同工艺）"></a>Tomahawk 3 · BCM56980（2018）— 16nm（与 TH2 同工艺）</h3><p>带宽 <strong>12.8 Tbps</strong> · SerDes <strong>256×50G PAM4</strong> · 缓冲 <strong>约 64MB*</strong></p><ul><li>2017 年底 sampling、2018 年出货。与 TH2 采用<strong>相同 16FF+ 工艺</strong>，靠工程优化塞下 256 个 56G PAM4 SerDes 实现带宽翻倍——工艺不变、架构取胜的一代。<code>[媒体 EE Times]</code></li><li>12.8Tbps 共享 buffer 架构，incast 吸收能力 3–5 倍；官方宣称功耗每 100Gbps 降低 40%、成本每 100Gbps 降低最高 75%（相对竞品）。<code>[官方新闻稿]</code></li><li>IP 路由转发表 &gt;2 倍、ECMP 规模 2 倍、动态负载均衡、INT 带内遥测、大象流检测与重优先级；BroadView Gen 3。<code>[官方新闻稿]</code></li><li>定位：hyperscale 数据中心高基数 100G&#x2F;400G 部署、RDMA 存储负载。</li></ul><p>* 缓冲数字来自第三方爱好者站点整理，置信度低。<code>[第三方·低置信]</code></p><h3 id="Tomahawk-4-·-BCM56990（2020）—-7nm-TSMC-·-310-亿晶体管"><a href="#Tomahawk-4-·-BCM56990（2020）—-7nm-TSMC-·-310-亿晶体管" class="headerlink" title="Tomahawk 4 · BCM56990（2020）— 7nm TSMC · 310 亿晶体管"></a>Tomahawk 4 · BCM56990（2020）— 7nm TSMC · 310 亿晶体管</h3><p>带宽 <strong>25.6 Tbps</strong> · SerDes <strong>512×50G PAM4</strong> · 缓冲 <strong>约 113MB*</strong> · 遥测 <strong>4×1GHz ARM 核</strong></p><ul><li>2019 年底 sampling、2020 年出货；25.6Tbps 共享 buffer 架构，incast 吸收 5 倍。<code>[官方新闻稿]</code></li><li>新型高级负载均衡机制（基本消除 hash polarization 哈希极化）；IFA 2.0 带内遥测；4 颗 1GHz ARM 核做流式遥测。<code>[官方新闻稿]</code></li><li>早期采用者：阿里云、谷歌云、微软、腾讯、Uber。<code>[媒体 Tom&#39;s Hardware]</code></li></ul><p>* 缓冲数字来自第三方硬件整理站点，置信度低。<code>[第三方·低置信]</code></p><h3 id="Tomahawk-5-·-BCM78900（2022）★-—-5nm-单芯片（monolithic）"><a href="#Tomahawk-5-·-BCM78900（2022）★-—-5nm-单芯片（monolithic）" class="headerlink" title="Tomahawk 5 · BCM78900（2022）★ — 5nm 单芯片（monolithic）"></a>Tomahawk 5 · BCM78900（2022）★ — 5nm 单芯片（monolithic）</h3><p>带宽 <strong>51.2 Tbps</strong> · SerDes <strong>512×100G PAM4</strong> · 端口 <strong>64×800G</strong> · 缓冲 <strong>约 165MB*</strong> · 遥测 <strong>6×ARM 核</strong></p><ul><li>2022 年发布、2023 年 3 月量产出货；首颗 5nm 商用交换芯片，开启 800G 时代。<code>[官方新闻稿]</code></li><li><strong>Cognitive Routing（认知路由）</strong> + 动态 flowlet 导向 + 端到端拥塞控制，专为 AI&#x2F;ML 的大象流、低熵流量设计；51.2Tbps 共享 buffer 架构，官方宣称 RoCEv2 最低尾延迟。<code>[官方新闻稿]</code></li><li>单遍 VxLAN 路由桥接；支持 Clos 与非 Clos 拓扑（torus、Dragonfly、Dragonfly+、Megafly）；高精度 PTP&#x2F;SyncE 时间同步。<code>[官方新闻稿]</code></li><li>定位：统一数据中心基础设施 + AI&#x2F;ML 训练集群 scale-out fabric。</li></ul><p>* 缓冲数字来自白盒厂商（Micas）800G 交换机物料：165.2MB &#x2F; 每 ITM 82.6MB，置信度低，但与代际趋势一致。<code>[第三方·低置信]</code></p><h3 id="Tomahawk-6（2025）★-—-3nm-chiplet-架构"><a href="#Tomahawk-6（2025）★-—-3nm-chiplet-架构" class="headerlink" title="Tomahawk 6（2025）★ — 3nm chiplet 架构"></a>Tomahawk 6（2025）★ — 3nm chiplet 架构</h3><p>带宽 <strong>102.4 Tbps</strong> · SerDes <strong>100G &#x2F; 200G</strong> · 端口 <strong>512×200G</strong> · 光互连 <strong>支持 CPO 共封装光学</strong></p><ul><li>2025 年 6 月发布，带宽再翻倍至 102.4Tbps；首次采用 <strong>3nm chiplet（芯粒）架构</strong>；下一代 cognitive routing + 增强共享 buffer 架构。<code>[媒体 行业媒体]</code></li><li>同时支持 AI 的 scale-out 与 scale-up 以太网拓扑，面向数十万乃至百万 XPU 的超大 AI fabric。<code>[媒体 行业媒体]</code></li></ul><p><strong>附带分支 — Tomahawk Ultra（2025 年 3 月）</strong>：与 TH6 平行的分支而非 TH5 的后继：同为 51.2Tbps，但主打 <strong>250ns 超低延迟</strong>、每秒 760 亿+包处理，并引入 LLR（链路层重试）+ CBFC（基于信用的流控）实现零丢包，面向 HPC 与 AI scale-up——注意它借用的正是 DNX 家族的”信用流控”思想，两条产品线在 AI 时代开始互相借鉴。<code>[媒体 FS 对比]</code></p><h2 id="07-头对头对比与选型"><a href="#07-头对头对比与选型" class="headerlink" title="07 头对头对比与选型"></a>07 头对头对比与选型</h2><p>把两家的差异压缩到一张表：左列是单芯片路线（Tomahawk），右列是分布式 fabric 路线（Jericho+Ramon）。没有谁全面胜出——它们是为两种完全不同的网络而优化的。</p><table><thead><tr><th>对比维度</th><th>Tomahawk（StrataXGS · 单芯片）</th><th>Jericho + Ramon（StrataDNX · 分布式）</th></tr></thead><tbody><tr><td>架构</td><td>单颗 SoC 完成交换+路由，一台设备即一台交换机（固定盒式）</td><td>FAP（包处理）+ FE（cell 交换）多芯片；NCP&#x2F;NCF 白盒组成 DDC，对外为一台逻辑路由器</td></tr><tr><td>单芯片带宽</td><td>3.2T（2014）→ 102.4T（2025），每代翻倍</td><td>0.9T（J+）→ 10T（J2）→ 14.4T（J2C+）→ 28.8T（J3-AI），单芯片低于同期 Tomahawk</td></tr><tr><td>系统扩展</td><td>靠多台设备 Clos 组网扩展（标准以太网 ECMP）</td><td>DDC 天然可扩展：J2C++Ramon 单机框 &gt;300Tbps；J3-AI+Ramon3 fabric 达 26Pb&#x2F;s、32K GPU</td></tr><tr><td>缓冲</td><td>片上共享浅缓冲：16MB（TH1）→ 42MB（TH2）→ 约 64MB（TH3）→ 约 113MB（TH4）→ 约 165MB（TH5）</td><td>深缓冲：片上 SRAM + HBM2（GB 级，J2 双 HBM 最高 8GB&#x2F;芯片），吸收突发、零丢包</td></tr><tr><td>转发表</td><td>较小：UFT 128K（TH1）&#x2F; 256K（TH2），面向数据中心路由规模</td><td>大：Jericho2 芯片级 260 万 IPv4 路由；可外置 KBP 扩展至互联网级全表</td></tr><tr><td>时延</td><td>超低：TH1 亚 400ns 端口延迟；Tomahawk Ultra 250ns；cut-through 风格</td><td>较高：cell 切片 + VOQ + 调度带来额外时延，但换来确定性与无损（J3-AI：无拥塞、无抖动）</td></tr><tr><td>流控 &#x2F; 无损</td><td>依赖 PFC&#x2F;ECN + 端到端拥塞控制（TH5 cognitive routing）；Ultra 引入 CBFC&#x2F;LLR</td><td>fabric 内天生无损：cell + VOQ + 基于信用的流控；AI 场景端到端调度</td></tr><tr><td>典型用途</td><td>云数据中心 ToR&#x2F;Leaf&#x2F;Spine、AI scale-out fabric、高性能 DCI spine</td><td>运营商核心&#x2F;边缘路由、DCI、DDC 分布式机框、AI 后端 scheduled fabric</td></tr><tr><td>功耗</td><td>每代每 Gb 功耗大幅下降（TH3 宣称相对竞品每 100G 降 40%）；5nm&#x2F;3nm 持续优化</td><td>J2C+ 相对 J2 功耗减半（400W → 350W，Linley）；但多芯片 + HBM 的系统总功耗高于同等带宽的 Tomahawk</td></tr><tr><td>成本结构</td><td>单芯片 BOM 简单，每 100G 成本最低（TH3 宣称相对竞品降 75%）→ hyperscaler 最爱</td><td>多芯片（FAP+FE+HBM&#x2F;KBP）BOM 复杂、单端口成本高；但省的是系统级成本：J2C+ 把 21 颗芯片的线卡压到 2 颗，DDC 用白盒替代昂贵纵向集成机框</td></tr></tbody></table><h3 id="选型逻辑"><a href="#选型逻辑" class="headerlink" title="选型逻辑"></a>选型逻辑</h3><p><strong>选 Tomahawk，当你需要……</strong></p><ul><li><strong>带宽密度、时延、每比特成本</strong>优先；</li><li>路由表不大、流量以数据中心东西向为主；</li><li>云数据中心 ToR&#x2F;Leaf&#x2F;Spine、AI scale-out 集群。</li></ul><p><strong>选 Jericho+Ramon，当你需要……</strong></p><ul><li><strong>互联网级全路由表、深缓冲吸收突发</strong>；</li><li>运营商级 QoS 与线速安全（MACsec&#x2F;IPsec）；</li><li>机框级扩展，或 AI 后端需要<strong>确定性无损 fabric</strong>；</li><li>运营商核心&#x2F;边缘、DCI、DDC、AI backend。</li></ul><p>一个正在发生的趋势：AI 集群让两条线正面相遇——Tomahawk 5&#x2F;6 用 cognitive routing 和共享缓冲攻 AI scale-out，Jericho3-AI 用 scheduled fabric 攻 AI 后端；Tomahawk Ultra 又反过来引入信用流控。区别在缩小，但基因没变：**XGS 信”快”，DNX 信”稳”**。</p><h2 id="08-术语详解"><a href="#08-术语详解" class="headerlink" title="08 术语详解"></a>08 术语详解</h2><p>读交换芯片资料绕不开的词，按”组网拓扑 → fabric 机制 → 协议与场景”排列。每个词条都标注它在 Jericho&#x2F;Tomahawk 语境中的具体位置。</p><h3 id="Leaf（叶交换机-·-接入层）"><a href="#Leaf（叶交换机-·-接入层）" class="headerlink" title="Leaf（叶交换机 · 接入层）"></a>Leaf（叶交换机 · 接入层）</h3><p>Clos &#x2F; leaf-spine 架构的<strong>接入层</strong>交换机：下行接服务器（或 GPU），上行接 Spine。名字来自树形比喻——leaf 是树的叶子，spine 是主干。Tomahawk 常用于 Leaf&#x2F;ToR 角色；Jericho3-AI 在 AI scheduled fabric 中作 leaf，且”全部智能在 leaf”。</p><h3 id="Spine（脊交换机-·-汇聚层）"><a href="#Spine（脊交换机-·-汇聚层）" class="headerlink" title="Spine（脊交换机 · 汇聚层）"></a>Spine（脊交换机 · 汇聚层）</h3><p><strong>汇聚层</strong>交换机，只连接 Leaf、不直接接服务器，为任意两台 Leaf 之间提供高速互连路径。Leaf 数量决定 spine 的端口密度需求——这正是 Tomahawk 高基数（radix）的用武之地。在 DNX 的 AI fabric 中，Ramon 扮演 spine 角色，但它交换的是 cell 而非整包。</p><h3 id="ToR（Top-of-Rack-·-架顶交换机）"><a href="#ToR（Top-of-Rack-·-架顶交换机）" class="headerlink" title="ToR（Top of Rack · 架顶交换机）"></a>ToR（Top of Rack · 架顶交换机）</h3><p>安装在<strong>机柜顶部</strong>的接入交换机：本机柜的服务器用短跳线（铜缆&#x2F;光纤）上行到 ToR，再由 ToR 连向 spine。ToR 通常就是 leaf 的物理形态。Jericho3-AI 的典型部署就是 GPU 机柜的 ToR——其 SerDes 支持 4 米铜缆直连机柜内 GPU。</p><h3 id="Clos-网络（多级无阻塞交换网络）"><a href="#Clos-网络（多级无阻塞交换网络）" class="headerlink" title="Clos 网络（多级无阻塞交换网络）"></a>Clos 网络（多级无阻塞交换网络）</h3><p>由 Charles Clos 提出的多级交换结构：用<strong>大量小交换单元多级互连</strong>，拼出任意规模的无阻塞交换。数据中心的 leaf-spine 就是两级 Clos；DDC 里 NCP 全连 NCF 也是 Clos。特点是任意两点有多条等价路径——一条链路故障，还有别的路可走。</p><h3 id="Fabric（交换网-交换矩阵）"><a href="#Fabric（交换网-交换矩阵）" class="headerlink" title="Fabric（交换网 &#x2F; 交换矩阵）"></a>Fabric（交换网 &#x2F; 交换矩阵）</h3><p>广义指提供”任意端口到任意端口”互连的交换结构，可以是机框内部的背板，也可以是跨设备的互连平面。在 <strong>DDC 语境中特指由 Ramon（NCF）组成的交换平面</strong>；在 AI 语境中”fabric”又泛指整个集群互连网络（如”AI fabric”）。</p><h3 id="ECMP（Equal-Cost-Multi-Path-·-等价多路径）"><a href="#ECMP（Equal-Cost-Multi-Path-·-等价多路径）" class="headerlink" title="ECMP（Equal-Cost Multi-Path · 等价多路径）"></a>ECMP（Equal-Cost Multi-Path · 等价多路径）</h3><p>三层网络中，到达同一目的地有多条等价路径时，按<strong>流哈希</strong>（五元组 hash）把不同流分到不同路径上分担负载——标准以太网 Clos 的默认扩展方式。缺点：<strong>大象流哈希碰撞</strong>会把两条大流挤到同一条链路上造成不均与拥塞。Jericho3-AI 用”喷洒”替代 ECMP，正是为了根除这个问题。</p><h3 id="Cell（信元-·-定长数据单元）"><a href="#Cell（信元-·-定长数据单元）" class="headerlink" title="Cell（信元 · 定长数据单元）"></a>Cell（信元 · 定长数据单元）</h3><p>DNX fabric 内部传输的<strong>定长</strong>小数据单元。包在入口 Jericho 被切成 cell，喷洒过 fabric，出口重组。定长带来两个好处：fabric 调度与包长解耦（调度器只需数 cell，不用管包长），以及负载天然均衡。注意这与以太网帧、IP 包是完全不同层面的概念——cell 只存在于芯片之间的 fabric 内部。</p><h3 id="VOQ（Virtual-Output-Queue-·-虚拟输出队列）"><a href="#VOQ（Virtual-Output-Queue-·-虚拟输出队列）" class="headerlink" title="VOQ（Virtual Output Queue · 虚拟输出队列）"></a>VOQ（Virtual Output Queue · 虚拟输出队列）</h3><p>在<strong>入口侧</strong>为每个出口端口（×每个优先级）维护独立队列的排队方式。解决的是<strong>队头阻塞（Head-of-Line Blocking）</strong>：传统单一 FIFO 队列里，队头一个去拥塞出口的包会堵住后面所有包；VOQ 让每个出口各排各的队，互不影响。Jericho 的层级流量管理器基于端到端 VOQ；Jericho3-AI 的入口 leaf 为每个接收端建 VOQ。</p><h3 id="DDC（Distributed-Disaggregated-Chassis-·-分布式分解式机框）"><a href="#DDC（Distributed-Disaggregated-Chassis-·-分布式分解式机框）" class="headerlink" title="DDC（Distributed Disaggregated Chassis · 分布式分解式机框）"></a>DDC（Distributed Disaggregated Chassis · 分布式分解式机框）</h3><p>把传统机框<strong>拆散重组</strong>的系统形态：线卡变 NCP 白盒、fabric 卡变 NCF 白盒、主控变 NCC，之间用标准线缆互连，对外仍是一台逻辑路由器。好处是硬件软件解耦（白盒 + 任意 NOS）、按需扩容、摆脱单厂商绑定。AT&amp;T 2019 年向 OCP 贡献了 DDC 硬件规范。</p><h3 id="Line-Card-Fabric-Card（线卡-网板）"><a href="#Line-Card-Fabric-Card（线卡-网板）" class="headerlink" title="Line Card &#x2F; Fabric Card（线卡 &#x2F; 网板）"></a>Line Card &#x2F; Fabric Card（线卡 &#x2F; 网板）</h3><p><strong>线卡</strong>：提供业务端口、做包处理的板卡，DDC 中对应 NCP（Jericho）。<strong>Fabric 卡</strong>：只提供板卡间交换互连的板卡，DDC 中对应 NCF（Ramon）。传统机框里两者插在同一背板上；DDC 把背板换成了线缆，把板卡换成了独立白盒。</p><h3 id="FAP-FE（Fabric-Access-Processor-Fabric-Element）"><a href="#FAP-FE（Fabric-Access-Processor-Fabric-Element）" class="headerlink" title="FAP &#x2F; FE（Fabric Access Processor &#x2F; Fabric Element）"></a>FAP &#x2F; FE（Fabric Access Processor &#x2F; Fabric Element）</h3><p><strong>FAP</strong> &#x3D; Jericho：包处理 + 流量管理 + fabric 接入，是”有脑子”的芯片。<strong>FE</strong> &#x3D; Ramon：纯 cell 交叉交换，是”只有手脚”的芯片。一个 DNX 系统里 FAP 决定功能上限（表项、QoS、安全），FE 决定 fabric 的规模上限（能拼多大的机框）。</p><h3 id="Cut-through-vs-存储转发"><a href="#Cut-through-vs-存储转发" class="headerlink" title="Cut-through vs 存储转发"></a>Cut-through vs 存储转发</h3><p><strong>Cut-through（直通）</strong>：收到包头（目的 MAC）就开始转发，时延极低（Tomahawk 亚微秒级），但无法做整包校验与复杂调度。<strong>Store-and-forward（存储转发）</strong>：收完整包、校验后再转发，可靠但时延高。DNX 的 cell 交换是第三种形态——“切分后存储转发 + 全局调度”，以时延换无损与确定性。</p><h3 id="PFC（Priority-Flow-Control-·-802-1Qbb）"><a href="#PFC（Priority-Flow-Control-·-802-1Qbb）" class="headerlink" title="PFC（Priority Flow Control · 802.1Qbb）"></a>PFC（Priority Flow Control · 802.1Qbb）</h3><p>链路级暂停机制：接收端某个优先级队列快满时，发 PAUSE 帧让发送端<strong>停发该优先级</strong>的流量。是构建无损以太网、跑 RoCE 的基础机制。缺点是粒度粗（整条链路一个优先级一起停）、可能引发队头阻塞与死锁。DNX fabric 内部的信用流控比它精细得多——这也是 Ultra 一代 XGS 反过来学 DNX 的原因。</p><h3 id="ECN（Explicit-Congestion-Notification-·-RFC-3168）"><a href="#ECN（Explicit-Congestion-Notification-·-RFC-3168）" class="headerlink" title="ECN（Explicit Congestion Notification · RFC 3168）"></a>ECN（Explicit Congestion Notification · RFC 3168）</h3><p>IP 头里的拥塞标记位：交换机队列拥塞时<strong>不丢包，而是打标记</strong>；接收端收到标记后回告发送端降速。ECN 把”拥塞”从事后丢包变成事前信号，是 RoCEv2 + DCQCN 等端到端拥塞控制的感知基础，Tomahawk 的拥塞控制与之配合工作。</p><h3 id="RDMA-RoCE（远程直接内存访问-融合以太网-RDMA）"><a href="#RDMA-RoCE（远程直接内存访问-融合以太网-RDMA）" class="headerlink" title="RDMA &#x2F; RoCE（远程直接内存访问 &#x2F; 融合以太网 RDMA）"></a>RDMA &#x2F; RoCE（远程直接内存访问 &#x2F; 融合以太网 RDMA）</h3><p><strong>RDMA</strong> 允许一台机器直接读写另一台机器的内存，绕过双方 CPU 与操作系统内核，时延极低，是 AI 训练集群 GPU 间通信（集合通信）的刚需。<strong>RoCE</strong>（RoCEv2 基于 UDP&#x2F;IP）是把 RDMA 跑在以太网上的协议。关键约束：<strong>RoCE 要求无损网络</strong>——丢包会导致重传与性能崩塌。因此 AI&#x2F;存储网络要么用 PFC&#x2F;ECN 把以太网”驯化”成无损（Tomahawk 路线，TH5 宣称 RoCEv2 最低尾延迟），要么用天生无损的 scheduled fabric（Jericho3-AI + Ramon3 路线）。<strong>这是两大家族在 AI 集群中正面竞争的技术焦点。</strong></p><h3 id="Incast（多对一汇聚）"><a href="#Incast（多对一汇聚）" class="headerlink" title="Incast（多对一汇聚）"></a>Incast（多对一汇聚）</h3><p>多个发送端<strong>同时</strong>向同一个接收端发数据的流量模式（分布式存储、AI 参数同步的典型形态），会在接收端入口瞬间冲爆缓冲。考验交换机的就是这一项：Tomahawk 靠逐代变大的共享缓冲硬扛（TH3 宣称吸收能力 3–5 倍、TH4 达 5 倍）；Jericho 靠 HBM 深缓冲 + 接收端流控从源头调度。</p><h3 id="深缓冲-vs-浅缓冲"><a href="#深缓冲-vs-浅缓冲" class="headerlink" title="深缓冲 vs 浅缓冲"></a>深缓冲 vs 浅缓冲</h3><p><strong>浅缓冲</strong>（Tomahawk）：片上 SRAM、MB 级，包在芯片里停留时间短，时延低、时延抖动小，适合流量平稳的数据中心。<strong>深缓冲</strong>（Jericho）：HBM、GB 级，能把突发流量”存下来慢慢发”，适合广域网&#x2F;运营商网络的长肥管道与复杂 QoS。没有对错，只有场景——数据中心里缓冲太深反而会放大时延（bufferbloat）。</p><h3 id="SerDes-PAM4"><a href="#SerDes-PAM4" class="headerlink" title="SerDes &#x2F; PAM4"></a>SerDes &#x2F; PAM4</h3><p>芯片对外带宽 &#x3D; SerDes 数量 × 单通道速率。<strong>PAM4</strong> 用 4 个电平表示 2 bit，同样波特率下速率翻倍，是 50G 以上通道的标配：Jericho2 的 208×50G PAM4、TH5 的 512×100G PAM4 都是这么算出总带宽的。读规格表时先看 SerDes 阵列，带宽口径自然对得上。</p><h3 id="KBP（Knowledge-Based-Processor）"><a href="#KBP（Knowledge-Based-Processor）" class="headerlink" title="KBP（Knowledge-Based Processor）"></a>KBP（Knowledge-Based Processor）</h3><p>外挂在 Jericho 旁边的协处理芯片，用 TCAM 类存储扩展<strong>转发表、计数器与 ACL</strong> 的规模。片上表项再大也装不下互联网全表 + 运营商策略，KBP 让 DNX 系统把表规模”外置扩展”——这是路由场景特有的需求，数据中心交换机（Tomahawk）不需要这一挂。</p><h3 id="Scale-out-Scale-up（横向-纵向扩展）"><a href="#Scale-out-Scale-up（横向-纵向扩展）" class="headerlink" title="Scale-out &#x2F; Scale-up（横向 &#x2F; 纵向扩展）"></a>Scale-out &#x2F; Scale-up（横向 &#x2F; 纵向扩展）</h3><p><strong>Scale-out</strong>：加更多节点（GPU 服务器）横向扩集群，节点间走以太网&#x2F;InfiniBand——Tomahawk 5&#x2F;6 和 Jericho3-AI 的主战场。<strong>Scale-up</strong>：让单个”超级节点”内的 GPU 互连更强（传统上是 NVLink 的领地）——Tomahawk Ultra（250ns、零丢包）瞄准的正是让以太网打进 scale-up。</p><h3 id="DCI（Data-Center-Interconnect-·-数据中心互连）"><a href="#DCI（Data-Center-Interconnect-·-数据中心互连）" class="headerlink" title="DCI（Data Center Interconnect · 数据中心互连）"></a>DCI（Data Center Interconnect · 数据中心互连）</h3><p>连接两个（或多个）数据中心的广域链路及设备。DCI 流量要过长距离光纤，需要深缓冲吸收抖动、MACsec 线速加密、电信级 QoS——全是 Jericho 的强项（Arista&#x2F;Cisco 的 DCI 方案多用 Jericho2c+）；Tomahawk 则常在 DCI 的 spine 侧出现。两家在这个场景是”搭配”多于”竞争”。</p><h3 id="Chiplet-CPO（芯粒-共封装光学）"><a href="#Chiplet-CPO（芯粒-共封装光学）" class="headerlink" title="Chiplet &#x2F; CPO（芯粒 &#x2F; 共封装光学）"></a>Chiplet &#x2F; CPO（芯粒 &#x2F; 共封装光学）</h3><p><strong>Chiplet</strong>：把大芯片拆成多颗小芯粒再封装到一起，绕开单 die 面积与良率极限——Tomahawk 6（3nm chiplet）与 Jericho2 的 2.5D HBM 堆叠都是这条路的不同形态。<strong>CPO</strong>（Co-Packaged Optics）：把光引擎和交换芯片封在一起，缩短电互连距离、降功耗，TH6 已支持。</p><h2 id="09-口径说明与未核实事项"><a href="#09-口径说明与未核实事项" class="headerlink" title="09 口径说明与未核实事项"></a>09 口径说明与未核实事项</h2><p>交换芯片的营销数字口径历来不统一（单向&#x2F;双向、网络侧与 fabric 侧是否合计、统计包长条件）。以下是本页引用数据时已知的口径差异与未能核实之处，引用数字时请连同这些保留意见一起看。</p><ol><li><strong>Jericho3（BCM88830）标准路由版</strong>：未能从公开渠道核实其独立发布时间、带宽、工艺与端口规格。已核实的是 Jericho3 世代首款芯片为 Jericho3-AI（2023-04-18）。如需 BCM88830 详情，建议通过 Broadcom 官方产品页或数据手册确认。</li><li><strong>Jericho2 带宽口径</strong>：官方新闻稿为 10Tbps；Gazettabyte 称”4.8T + 8GB HBM”；第三方称 BCM88690 为 4.8Tbps 全双工（&gt;284B 包）。可能为不同统计口径（单向&#x2F;双向、包长条件），本页正文采用官方 10Tbps。</li><li><strong>Ramon3 单芯片规格</strong>：仅核实到系统级（Accton NCF-2 白盒：128×800G fabric 端口，DriveNets 称 51.2Tbps）；单芯片 SerDes 数量、工艺、带宽未公开。”128×800G &#x3D; 102.4T”与白盒标称 51.2Tbps 存在口径疑问（可能端口按 400G 计或为双芯片配置），未深究。</li><li><strong>Tomahawk 缓冲容量</strong>（TH3 约 64MB &#x2F; TH4 约 113MB &#x2F; TH5 约 165MB）：来自第三方爱好者站点与白盒厂商物料，置信度低，仅反映代际趋势；官方未公开具体 MB 数。TH1&#x2F;TH2 的 16MB&#x2F;42MB 来自 Cisco 技术幻灯片。</li><li><strong>早期 Jericho（BCM88650）单芯片带宽&#x2F;工艺</strong>：2012 年新闻稿只给出系统级（&gt;100Tbps、4000×100G），未核实单芯片带宽与工艺；Jericho+ 已确认为 28nm &#x2F; 2015-03。</li><li>**”Tomahawk 1+”**：无官方独立世代，不设条目。</li><li>本页范围限定 Jericho &#x2F; Ramon &#x2F; Tomahawk 主线，未覆盖 Jericho4（2025-08 发布）与 Qumran 系列（Jericho 的单芯片低端分支）。</li></ol><h2 id="10-来源"><a href="#10-来源" class="headerlink" title="10 来源"></a>10 来源</h2><h3 id="官方来源（新闻稿-产品页-博客）"><a href="#官方来源（新闻稿-产品页-博客）" class="headerlink" title="官方来源（新闻稿 &#x2F; 产品页 &#x2F; 博客）"></a>官方来源（新闻稿 &#x2F; 产品页 &#x2F; 博客）</h3><ul><li>Jericho2 + FE9600 发布（2018-03-06）：<a href="https://www.telecomtv.com/content/tracker/broadcom-ships-jericho2-industrys-highest-bandwidth-ethernet-switch-router-at-10-terabits-per-second-30197/amp/">TelecomTV 转载</a></li><li>Jericho2c+ sampling（2020-09-10）：<a href="https://www.einpresswire.com/article/525934982/broadcom-samples-industry-s-highest-performing-routing-chip-at-14-4-terabits-per-second">EIN Presswire 转载</a></li><li>Jericho3-AI 发布（2023-04-18）：<a href="https://www.hpcwire.com/off-the-wire/broadcom-unveils-high-performance-fabric-for-ai-networks/">HPCwire 转载</a></li><li>BCM88680（Jericho+）产品页：<a href="https://www.broadcom.com/products/ethernet-connectivity/switching/stratadnx/bcm88680/">broadcom.com</a></li><li>DDC 官方博客：<a href="https://broadcom.com/blog/reducing-job-completion-time-in-ai-ml-clusters">broadcom.com&#x2F;blog</a></li><li>Jericho2 官方 PR 存档（cell &#x2F; credit &#x2F; VOQ）：<a href="https://people.ucsc.edu/~warner/Bufs/Jericho2-PR.pdf">UCSC 存档 PDF</a></li><li>Jericho（BCM88650）发布（2012-04-30）：<a href="https://www.edn.com/broadcom-enables-massive-network-scalability-with-worlds-highest-density-100gbe-switch-solution/">EDN 转载</a></li><li>Tomahawk 2 发布（2016-10-11）：<a href="https://www.globenewswire.com/news-release/2016/10/11/878592/19933/en/Broadcom-First-to-Deliver-64-Ports-of-100GE-with-Tomahawk-II-6-4Tbps-Ethernet-Switch.html">GlobeNewswire 转载</a></li><li>Tomahawk 3 发布：<a href="https://www.telecomtv.com/content/tracker/broadcom-ships-tomahawk-3-industry-s-highest-bandwidth-ethernet-switch-chip-at-12-8-terabits-per-second-29700/amp/">TelecomTV 转载</a></li><li>Tomahawk 4 发布：<a href="https://app.researchpool.com/company/avgo-us11135f1012-broadcom-inc-WmuAguxXPk/press/broadcom-ships-tomahawk-4-industrys-highest-bandwidth-switch-chip-at-25-6-terabits-per-second/">researchpool 转载</a></li><li>Tomahawk 5 发布：<a href="https://www.nasdaq.com/press-release/broadcom-ships-tomahawk-5-industrys-highest-bandwidth-switch-chip-to-accelerate-ai-ml">Nasdaq 转载</a></li></ul><h3 id="行业媒体"><a href="#行业媒体" class="headerlink" title="行业媒体"></a>行业媒体</h3><ul><li>EE Times（Jericho2 &#x2F; HBM2 &#x2F; 2.5D；Jericho+ 28nm）：<a href="https://www.eetimes.com/document.asp?doc_id=1333033">报道一</a>、<a href="https://www.eetimes.com/bcoms-jericho2-rides-2-5d-stack/?_ga=mc=RSS_EET_EDT">报道二</a>；TH2&#x2F;TH3 同为 16FF+：<a href="https://www.eetimes.com/bcom-shifts-switch-to-12-8-tbits-s/?_ga">报道</a></li><li>Gazettabyte（Jericho3-AI 深度）：<a href="https://www.gazettabyte.com/home/2023/6/7/broadcoms-first-jericho3-takes-on-ais-networking-challenge.html?printerFriendly=true">gazettabyte.com</a></li><li>The Next Platform（Jericho3-AI 304 SerDes；TH5 5nm）：<a href="https://www.nextplatform.com/connect/2023/04/27/broadcom-takes-on-infiniband-with-jericho3-ai-switch-chips/1640605">nextplatform.com</a></li><li>Packet Pushers（scheduled fabric &#x2F; credit &#x2F; VOQ）：<a href="https://packetpushers.net/blog/a-look-at-broadcoms-jericho3-ai-ethernet-fabric-schedules-credits-and-cells/">packetpushers.net</a></li><li>ServeTheHome（Jericho3-AI 规格 &#x2F; TH3 &#x2F; TH4）：<a href="https://www.servethehome.com/broadcom-jericho3-ai-ethernet-switch-launched-saying-nvidia-infiniband-is-bad-for-ai/">Jericho3-AI</a>、<a href="https://www.servethehome.com/new-broadcom-tomahawk-3-switch-chip-for-12-8tbps-networking/">Tomahawk 3</a></li><li>SDxCentral（Jericho2c+）：<a href="https://www.sdxcentral.com/articles/news/broadcom-next-gen-jericho-chip-gains-speed-security/2020/09/">sdxcentral.com</a></li><li>TechTarget（Jericho2 260 万路由）：<a href="https://www.techtarget.com/searchnetworking/news/252467389/Arrcus-upgrades-ArcOS-to-support-Jericho2-based-routers">techtarget.com</a></li><li>LightReading &#x2F; Converge Digest（Tomahawk 1 发布）：<a href="https://www.lightreading.com/semiconductors/broadcom-unveils-next-gen-ethernet-switch-chip">lightreading.com</a>、<a href="https://convergedigest.com/broadcoms-strataxgs-tomahawk-switch/">convergedigest.com</a></li><li>DriveNets（DDC &#x2F; Network Cloud；Ramon3 白盒）：<a href="https://drivenets.com/blog/drivenets-and-broadcom-share-vision-for-routing-and-ai-innovation/">愿景</a>、<a href="https://drivenets.com/blog/ai-networking-moves-ahead-with-drivenets-and-broadcom-jericho3-ai/">AI 网络</a>、白盒发布（经 Nasdaq）：<a href="https://www.nasdaq.com/press-release/drivenets-and-accton-technology-launch-highest-performance-ethernet-based-ai">nasdaq.com</a></li><li>TechInsights（TH5 5nm &#x2F; 2023-03 量产）：<a href="https://www.techinsights.com/zh-cn/node/56411">techinsights.com</a></li><li>techstrong.it（TH6 2025-06 &#x2F; 102.4T）：<a href="https://techstrong.it/featured/broadcoms-new-tomahawk-ultra-chip-pushes-ethernet-to-compete-with-nvidia/">techstrong.it</a>；TrendForce（TH6 3nm chiplet &#x2F; CPO）：<a href="https://www.trendforce.com/news/2026/03/13/news-serdes-wars-heat-up-broadcom-marvell-mediatek-battle-for-ai-interconnect-supremacy/">trendforce.com</a></li><li>FS（TH5 &#x2F; TH6 &#x2F; Ultra 对比）：<a href="https://www.fs.com/blog/broadcom-tomahawk-5-vs-tomahawk-6-vs-tomahawk-ultra-whats-changed-b44085.html">fs.com</a></li></ul><h3 id="第三方整理（低置信度，仅用于缓冲-配套细节）"><a href="#第三方整理（低置信度，仅用于缓冲-配套细节）" class="headerlink" title="第三方整理（低置信度，仅用于缓冲 &#x2F; 配套细节）"></a>第三方整理（低置信度，仅用于缓冲 &#x2F; 配套细节）</h3><ul><li>53bits 硬件总览：<a href="https://null.53bits.co.uk/index.php?page=hardware-overview-2">53bits.co.uk</a></li><li>UCSC 存档（Jericho2c+ Linley 分析）：<a href="https://people.ucsc.edu/~warner/Bufs/jericho2cplus.html">people.ucsc.edu</a></li><li>Cisco Tomahawk 1&#x2F;2 幻灯片：<a href="https://slidetodoc.com/tomahawk-2-asic-packet-walk-and-platform-overview/">slidetodoc.com</a></li><li>Micas TH5 交换机物料：<a href="https://vmblog.com/archive/2024/10/16/micas-networks-brings-ultra-high-performance-to-ai-ml-applications-with-800g-tomahawk-5-ethernet-switch.aspx">vmblog.com</a></li></ul><blockquote><p>资料来源：Broadcom 官方新闻稿&#x2F;产品页&#x2F;博客与行业媒体公开报道，检索于 2026-10-18。各厂商公布数字的统计口径不完全一致，请结合「口径说明与未核实事项」一节阅读；标注”低置信”的数字仅供参考。</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;博通的交换芯片有两条完全不同的技术路线：一条是为运营商路由而生的分布式多芯片架构（StrataDNX），一条是为云数据中心而生的单芯片高速交换（StrataXGS）。这一篇把两家的世代规格、系统架构、关键机制（cell 交换、VOQ、信用流控、深缓冲）以及 leaf、spi</summary>
      
    
    
    
    <category term="笔记" scheme="https://sqlmaps.com/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="网络" scheme="https://sqlmaps.com/tags/%E7%BD%91%E7%BB%9C/"/>
    
    <category term="交换芯片" scheme="https://sqlmaps.com/tags/%E4%BA%A4%E6%8D%A2%E8%8A%AF%E7%89%87/"/>
    
    <category term="Broadcom" scheme="https://sqlmaps.com/tags/Broadcom/"/>
    
  </entry>
  
  <entry>
    <title>UVM接口信号同步机制</title>
    <link href="https://sqlmaps.com/2026/08/19/UVM%E6%8E%A5%E5%8F%A3%E4%BF%A1%E5%8F%B7%E5%90%8C%E6%AD%A5%E6%9C%BA%E5%88%B6/"/>
    <id>https://sqlmaps.com/2026/08/19/UVM%E6%8E%A5%E5%8F%A3%E4%BF%A1%E5%8F%B7%E5%90%8C%E6%AD%A5%E6%9C%BA%E5%88%B6/</id>
    <published>2026-08-19T22:57:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-同步场景与应用"><a href="#1-同步场景与应用" class="headerlink" title="1. 同步场景与应用"></a>1. 同步场景与应用</h2><p>在UVM验证环境中，以下典型场景需要直接处理接口信号：</p><pre><code class="highlight mermaid">flowchart LR    A[序列内事务间隔控制] --&gt; B[总线时序管理]    C[错误状态过滤] --&gt; D[覆盖率采样控制]    E[中断响应机制] --&gt; F[ISR序列调度]    G[复位同步] --&gt; H[分析端数据采样]</code></pre><h2 id="2-核心实现方案"><a href="#2-核心实现方案" class="headerlink" title="2. 核心实现方案"></a>2. 核心实现方案</h2><h3 id="2-1-架构组件"><a href="#2-1-架构组件" class="headerlink" title="2.1 架构组件"></a>2.1 架构组件</h3><table><thead><tr><th>组件类型</th><th>功能描述</th><th>关键方法</th></tr></thead><tbody><tr><td>配置对象</td><td>封装虚拟接口和同步方法</td><td>wait_for_clock</td></tr><tr><td>事务类</td><td>定义传输数据格式</td><td>随机约束</td></tr><tr><td>基础序列</td><td>实现硬件感知的业务流</td><td>get_config</td></tr></tbody></table><h3 id="2-2-同步方法实现"><a href="#2-2-同步方法实现" class="headerlink" title="2.2 同步方法实现"></a>2.2 同步方法实现</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> bus_config <span class="keyword">extends</span> uvm_object;</span><br><span class="line">    <span class="keyword">virtual</span> bus_interface bus_if;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 等待指定时钟周期</span></span><br><span class="line">    <span class="keyword">task</span> wait_for_clock(<span class="keyword">int</span> cycles=<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">repeat</span>(cycles) @(<span class="keyword">posedge</span> bus_if<span class="variable">.clk</span>);</span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 等待复位信号有效</span></span><br><span class="line">    <span class="keyword">task</span> wait_for_reset();</span><br><span class="line">        @(<span class="keyword">posedge</span> bus_if<span class="variable">.reset</span>);</span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h2 id="3-关键代码实现"><a href="#3-关键代码实现" class="headerlink" title="3. 关键代码实现"></a>3. 关键代码实现</h2><h3 id="3-1-事务类定义"><a href="#3-1-事务类定义" class="headerlink" title="3.1 事务类定义"></a>3.1 事务类定义</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> transaction <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">    `uvm_object_utils(transaction)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">logic</span> [<span class="number">31</span>:<span class="number">0</span>] addr;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">logic</span> [<span class="number">31</span>:<span class="number">0</span>] write_data;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> read;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">int</span> delay;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">bit</span> error;</span><br><span class="line">    <span class="keyword">logic</span> [<span class="number">31</span>:<span class="number">0</span>] read_data;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">constraint</span> addr_alignment &#123;</span><br><span class="line">        addr[<span class="number">1</span>:<span class="number">0</span>] == <span class="number">0</span>;  <span class="comment">// 32位地址对齐</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">constraint</span> delay_range &#123;</span><br><span class="line">        delay <span class="keyword">inside</span> &#123;[<span class="number">1</span>:<span class="number">20</span>]&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="3-2-总线序列实现"><a href="#3-2-总线序列实现" class="headerlink" title="3.2 总线序列实现"></a>3.2 总线序列实现</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> bus_seq <span class="keyword">extends</span> uvm_sequence <span class="variable">#(transaction)</span>;</span><br><span class="line">    `uvm_object_utils(bus_seq)</span><br><span class="line">    </span><br><span class="line">    transaction txn;</span><br><span class="line">    bus_config bus_cfg;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">int</span> limit = <span class="number">25</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">task</span> body();</span><br><span class="line">        <span class="keyword">int</span> i = <span class="number">5</span>;</span><br><span class="line">        txn = transaction::type_id::create(<span class="string">&quot;txn&quot;</span>);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 获取配置对象</span></span><br><span class="line">        <span class="keyword">if</span>(!uvm_config_db <span class="variable">#(bus_config)::get(null, get_full_name()</span>, </span><br><span class="line">           <span class="string">&quot;config&quot;</span>, bus_cfg)) <span class="keyword">begin</span></span><br><span class="line">            `uvm_error(<span class="string">&quot;SEQ_ERROR&quot;</span>, <span class="string">&quot;总线配置对象获取失败&quot;</span>)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">repeat</span> (limit) <span class="keyword">begin</span></span><br><span class="line">            start_item(txn);</span><br><span class="line">            <span class="keyword">if</span>(!txn<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;</span><br><span class="line">                addr <span class="keyword">inside</span> &#123;[<span class="number">32&#x27;h0010_0000</span>:<span class="number">32&#x27;h0010_001C</span>];</span><br><span class="line">            &#125;) <span class="keyword">begin</span></span><br><span class="line">                `uvm_error(<span class="string">&quot;RAND_ERROR&quot;</span>, <span class="string">&quot;事务随机化失败&quot;</span>)</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            finish_item(txn);</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 动态调整时钟等待周期</span></span><br><span class="line">            bus_cfg<span class="variable">.wait_for_clock</span>(i);</span><br><span class="line">            i++;</span><br><span class="line">            </span><br><span class="line">            `uvm_info(<span class="string">&quot;SEQ_DEBUG&quot;</span>, <span class="built_in">$sformatf</span>(<span class="string">&quot;读取数据: 0x%h&quot;</span>, </span><br><span class="line">                     txn<span class="variable">.read_data</span>), UVM_LOW)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h2 id="4-应用优势分析"><a href="#4-应用优势分析" class="headerlink" title="4. 应用优势分析"></a>4. 应用优势分析</h2><ol><li><strong>时序精确控制</strong>：支持动态调整事务间隔</li><li><strong>异常状态处理</strong>：精确过滤无效覆盖率数据</li><li><strong>中断响应机制</strong>：实现硬件事件驱动的序列调度</li><li><strong>复位同步管理</strong>：确保验证组件状态一致性</li></ol><h2 id="5-扩展应用场景"><a href="#5-扩展应用场景" class="headerlink" title="5. 扩展应用场景"></a>5. 扩展应用场景</h2><table><thead><tr><th>应用场景</th><th>同步方法</th><th>实现要点</th></tr></thead><tbody><tr><td>中断服务例程</td><td>wait_for_interrupt</td><td>跨序列通信机制</td></tr><tr><td>低功耗模式验证</td><td>wait_for_power_ok</td><td>电源状态监控</td></tr><tr><td>错误注入测试</td><td>wait_for_error</td><td>错误检测与恢复机制</td></tr></tbody></table><blockquote><p>该方法为UVM验证环境提供了标准化的硬件信号同步解决方案，特别适用于需要硬件时序精确控制的复杂验证场景。后续将深入探讨中断处理机制的具体实现方法。</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-同步场景与应用&quot;&gt;&lt;a href=&quot;#1-同步场景与应用&quot; class=&quot;headerlink&quot; title=&quot;1. 同步场景与应用&quot;&gt;&lt;/a&gt;1. 同步场景与应用&lt;/h2&gt;&lt;p&gt;在UVM验证环境中，以下典型场景需要直接处理接口信号：&lt;/p&gt;
&lt;pre&gt;&lt;co</summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>UVM调试功能全解析</title>
    <link href="https://sqlmaps.com/2026/08/19/UVM%E8%B0%83%E8%AF%95%E5%8A%9F%E8%83%BD%E5%85%A8%E8%A7%A3%E6%9E%90/"/>
    <id>https://sqlmaps.com/2026/08/19/UVM%E8%B0%83%E8%AF%95%E5%8A%9F%E8%83%BD%E5%85%A8%E8%A7%A3%E6%9E%90/</id>
    <published>2026-08-19T22:57:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-调试功能概览"><a href="#1-调试功能概览" class="headerlink" title="1. 调试功能概览"></a>1. 调试功能概览</h2><pre><code class="highlight mermaid">flowchart LR    A[配置调试] --&gt; A1[命令行跟踪]    A --&gt; A2[组件配置打印]    A --&gt; A3[资源库转储]    B[工厂调试] --&gt; B1[类型注册追踪]    C[阶段调试] --&gt; C1[相位跟踪]    D[异议调试] --&gt; D1[对象跟踪]    E[TLM调试] --&gt; E1[连接拓扑分析]    F[通用调试] --&gt; F1[组件层次]    F --&gt; F2[消息控制]</code></pre><h2 id="2-核心调试功能详解"><a href="#2-核心调试功能详解" class="headerlink" title="2. 核心调试功能详解"></a>2. 核心调试功能详解</h2><h3 id="2-1-配置调试"><a href="#2-1-配置调试" class="headerlink" title="2.1 配置调试"></a>2.1 配置调试</h3><table><thead><tr><th>调试方法</th><th>命令行参数</th><th>使用场景</th></tr></thead><tbody><tr><td>配置数据库跟踪</td><td>+UVM_CONFIG_DB_TRACE</td><td>追踪set&#x2F;get操作</td></tr><tr><td>组件配置打印</td><td>print_config()</td><td>查看组件配置信息</td></tr><tr><td>资源库转储</td><td>uvm_config_db::dump()</td><td>显示当前资源配置</td></tr></tbody></table><p><strong>代码示例：</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 打印组件配置信息</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> my_env::end_of_elaboration_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.end_of_elaboration_phase</span>(phase);</span><br><span class="line">    print_config(<span class="number">1</span>, <span class="number">1</span>);  <span class="comment">// 递归打印带审计信息</span></span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 资源库转储</span></span><br><span class="line">uvm_config_db <span class="variable">#(int)::dump()</span>;</span><br></pre></td></tr></table></figure><h3 id="2-2-工厂调试"><a href="#2-2-工厂调试" class="headerlink" title="2.2 工厂调试"></a>2.2 工厂调试</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 打印工厂状态</span></span><br><span class="line">uvm_factory::get()<span class="variable">.print</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 典型输出：</span></span><br><span class="line"><span class="comment">// #### Factory Configuration (*)</span></span><br><span class="line"><span class="comment">// No instance or type overrides...</span></span><br><span class="line"><span class="comment">// All types registered: 44</span></span><br><span class="line"><span class="comment">// adpcm_driver</span></span><br><span class="line"><span class="comment">// adpcm_sequencer...</span></span><br></pre></td></tr></table></figure><h3 id="2-3-阶段跟踪"><a href="#2-3-阶段跟踪" class="headerlink" title="2.3 阶段跟踪"></a>2.3 阶段跟踪</h3><p><strong>启用方式：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+UVM_PHASE_TRACE</span><br></pre></td></tr></table></figure><p><strong>输出示例：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[PH/TRC/STRT] Phase &#x27;build&#x27; Starting</span><br><span class="line">[PH/TRC/DONE] Phase &#x27;build&#x27; Completed</span><br></pre></td></tr></table></figure><h3 id="2-4-异议跟踪"><a href="#2-4-异议跟踪" class="headerlink" title="2.4 异议跟踪"></a>2.4 异议跟踪</h3><p><strong>启用方式：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+UVM_OBJECTION_TRACE</span><br></pre></td></tr></table></figure><p><strong>输出示例：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[OBJTN_TRC] Object uvm_test_top raised 1 objection</span><br><span class="line">[OBJTN_TRC] Object uvm_top added 1 objection</span><br></pre></td></tr></table></figure><h3 id="2-5-TLM连接分析"><a href="#2-5-TLM连接分析" class="headerlink" title="2.5 TLM连接分析"></a>2.5 TLM连接分析</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 端口连接追踪</span></span><br><span class="line">m_driver<span class="variable">.seq_item_port</span><span class="variable">.debug_connected_to</span>();</span><br><span class="line">m_sequencer<span class="variable">.seq_item_export</span><span class="variable">.debug_provided_to</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出显示连接拓扑：</span></span><br><span class="line"><span class="comment">// uvm_test_top.m_driver.seq_item_port</span></span><br><span class="line"><span class="comment">// |_uvm_test_top.m_sequencer.seq_item_export</span></span><br></pre></td></tr></table></figure><h2 id="3-通用调试工具"><a href="#3-通用调试工具" class="headerlink" title="3. 通用调试工具"></a>3. 通用调试工具</h2><h3 id="3-1-组件层次结构"><a href="#3-1-组件层次结构" class="headerlink" title="3.1 组件层次结构"></a>3.1 组件层次结构</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">uvm_top<span class="variable">.print_topology</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出示例：</span></span><br><span class="line"><span class="comment">// UVM testbench topology:</span></span><br><span class="line"><span class="comment">// uvm_test_top      adpcm_test</span></span><br><span class="line"><span class="comment">//  m_driver         adpcm_driver</span></span><br><span class="line"><span class="comment">//   seq_item_port   uvm_seq_item_pull_port</span></span><br></pre></td></tr></table></figure><h3 id="3-2-消息控制"><a href="#3-2-消息控制" class="headerlink" title="3.2 消息控制"></a>3.2 消息控制</h3><table><thead><tr><th>控制方式</th><th>命令行参数</th><th>作用范围</th></tr></thead><tbody><tr><td>全局详细度设置</td><td>+UVM_VERBOSITY&#x3D;UVM_DEBUG</td><td>全环境</td></tr><tr><td>组件级详细度设置</td><td>+uvm_set_verbosity</td><td>指定组件</td></tr></tbody></table><h2 id="4-调试功能对比表"><a href="#4-调试功能对比表" class="headerlink" title="4. 调试功能对比表"></a>4. 调试功能对比表</h2><table><thead><tr><th>功能类别</th><th>跟踪方法</th><th>最佳使用阶段</th><th>输出类型</th></tr></thead><tbody><tr><td>配置跟踪</td><td>print_config()</td><td>end_of_elaboration</td><td>结构信息</td></tr><tr><td>工厂状态</td><td>factory.print()</td><td>connect_phase</td><td>注册类型列表</td></tr><tr><td>相位跟踪</td><td>+UVM_PHASE_TRACE</td><td>全程</td><td>阶段状态变更</td></tr><tr><td>TLM连接</td><td>debug_connected_to()</td><td>end_of_elaboration</td><td>端口连接拓扑</td></tr></tbody></table><h2 id="5-调试流程最佳实践"><a href="#5-调试流程最佳实践" class="headerlink" title="5. 调试流程最佳实践"></a>5. 调试流程最佳实践</h2><pre><code class="highlight mermaid">sequenceDiagram    participant Test    participant Env    participant Config    participant Factory    Test-&gt;&gt;Config: set虚拟接口    Config-&gt;&gt;Env: 传递配置    Env-&gt;&gt;Factory: 创建组件    Factory--&gt;&gt;Env: 返回实例    Env-&gt;&gt;Test: 完成构建    Note right of Test: print_topology()查看结构</code></pre><blockquote><p>提示：结合使用+UVM_CONFIG_DB_TRACE和print_topology()可快速定位配置传递问题</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-调试功能概览&quot;&gt;&lt;a href=&quot;#1-调试功能概览&quot; class=&quot;headerlink&quot; title=&quot;1. 调试功能概览&quot;&gt;&lt;/a&gt;1. 调试功能概览&lt;/h2&gt;&lt;pre&gt;&lt;code class=&quot;highlight mermaid&quot;&gt;flowchart </summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>UVM Sequence 学习记录</title>
    <link href="https://sqlmaps.com/2026/08/01/UVM-Sequence%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/"/>
    <id>https://sqlmaps.com/2026/08/01/UVM-Sequence%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/</id>
    <published>2026-08-01T14:13:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><ul><li><a href="#1-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF-uvm">1. 为什么是 UVM？</a></li><li><a href="#2-agentsequencesequencerdriver-%E5%9F%BA%E6%9C%AC%E5%85%B3%E7%B3%BB">2. Agent、Sequence、Sequencer、Driver 基本关系</a></li><li><a href="#3-transaction">3. Transaction</a></li><li><a href="#4-sequence">4. Sequence</a></li><li><a href="#5-%E5%90%AF%E5%8A%A8-sequence-%E7%9A%84%E6%96%B9%E6%B3%95">5. 启动 Sequence 的方法</a></li><li><a href="#6-virtual-sequence">6. Virtual Sequence</a></li><li><a href="#7-sequence-%E7%9A%84%E7%BB%86%E8%8A%82">7. Sequence 的细节</a></li><li><a href="#8-uvm-%E7%9A%84-transaction-level-modelingtlm">8. UVM 的 Transaction Level Modeling（TLM）</a></li><li><a href="#9-%E5%88%86%E6%9E%90%E6%8E%A5%E5%8F%A3-analysis-port">9. 分析接口 Analysis Port</a></li><li><a href="#10-%E5%8A%A0%E6%B7%B1%E7%90%86%E8%A7%A3-tlm-%E6%8A%80%E6%9C%AF">10. 加深理解 TLM 技术</a></li></ul><h2 id="1-为什么是-UVM？"><a href="#1-为什么是-UVM？" class="headerlink" title="1. 为什么是 UVM？"></a>1. 为什么是 UVM？</h2><ul><li>Verilog&#x2F;VHDL&#x2F;SystemC 设计的 TestBench</li><li>CL（SystemVerilog Base Class Library）</li><li>随机约束验证（random constrained verification）（核心）:是用仿真中的随机向量。</li></ul><p>有两个好处：</p><ul><li>约束随机，仿真非常适合发现bugs。</li><li>自动生成激励（长时间仿真等）。</li></ul><p>验证中的CCC指的是：</p><ul><li>checker</li><li>coverage（验证运行发生的情况，识别对设计的实践有多彻底）</li><li>constraint（有约束&#x3D;&#x3D;&#x3D;》auto checking的TB平台。有覆盖率空洞&#x3D;&#x3D;&#x3D;》调整约束）</li></ul><hr><h2 id="2-Agent、Sequence、Sequencer、Driver-基本关系"><a href="#2-Agent、Sequence、Sequencer、Driver-基本关系" class="headerlink" title="2. Agent、Sequence、Sequencer、Driver 基本关系"></a>2. Agent、Sequence、Sequencer、Driver 基本关系</h2><p><img src="https://img.sqlmaps.com/file/1788701556255_ext_06334ecf63.png" alt="image"></p><p>UVM中复用的基本单元是代理，有时也称为通用验证组件。</p><p>DUT上每个主要接口都有一个agent。接口是指总线接口、分组交换接口、串行接口或者其他接口。</p><p>每个agent都有一个标准结构，包括：</p><ul><li>下游路径上的sequencer和driver，他们生成激励，并将这些激励注入到DUT中。</li><li>上游路径上的monitor，观测接口上的引脚，将这些引脚组装成transaction，然后将这些transaction分发到验证环境的其余部分进行检查和功能覆盖率分析。</li></ul><p>验证环境之间的通信都是事务级别的。</p><p>在sequencer运行的这些事务最开始都是在sequence生成，所以sequencer和sequence之间的关系很重要：</p><ul><li>sequence是动态的，它们在sequencer上运行并生成transaction。</li><li>sequencer是准静态的，它们在UVM build phase的0时刻create。</li><li>monitor也生成transaction，并将这些transaction发送到验证环境的其他部分。</li></ul><h3 id="2-1-聚焦：sequencer-和-driver-的通信"><a href="#2-1-聚焦：sequencer-和-driver-的通信" class="headerlink" title="2.1 聚焦：sequencer 和 driver 的通信"></a>2.1 聚焦：sequencer 和 driver 的通信</h3><p>聚焦于 sequencer和driver之间的通信。</p><p>（sequencer和driver都是在验证环境的组件层次结构中实例化的UVM组件，driver是连接DUT和SV接口。driver通过从配置数据库中检索SV接口的位置，来找到他的位置，该配置数据库是有TOP层级set的）。</p><p> sequencer和driver之间的通信是事务级的，也就是TLM ports和TLM exports。类似于VHDL或者Verilog中的端口，允许你在组件之间通信，并且允许通信模块化。</p><p>这样各个组件就不需要知道它们正在通信的组件细节。</p><p>所以在这种情况下：</p><ul><li>driver通过port进行通信。</li><li>sequencer通过export进行通信。</li><li>driver和sequencer实际上都不知道对端组件的身份。</li></ul><p>常见的TLM是事务级建模，而TLM port和export实际上是从SystemC借鉴过来的。</p><p>正如所见，我们在sequencer上运行一个sequence，该sequence将生成transaction，并且通过事务级接口将这些事务传递给driver。</p><p><img src="https://img.sqlmaps.com/file/1788701777712_ext_bb6df419b8.png" alt="image"></p><p>正如所看见的，driver和sequencer之间有一个 pull接口。</p><p>也就是说，driver是通过 TLM端口（基本上是事务级的通信）从sequencer pulling或者得到 transaction。</p><p>这就意味着是使用函数调用进行的通信，其中每个函数调用的参数都是对transaction的引用，我们将在适当的时候看到所有的源代码。</p><hr><h2 id="3-Transaction"><a href="#3-Transaction" class="headerlink" title="3. Transaction"></a>3. Transaction</h2><p>让我们从一个transaction开始：</p><p><img src="https://img.sqlmaps.com/file/1788701579844_ext_13796d2242.png" alt="image"></p><p>定义一个数据类型，通过拓展类 <code>uvm_sequence_item</code> 的类。</p><p>此类是基于UVM的类库中的类之一，它表示可以从第二行的sequence生成的item。</p><p>使用 <code>uvm_object_utils</code> 为工厂自动化注册类；之前都是用 <code>uvm_component_utils</code> 将组件注册到工厂。</p><p>但是transaction并不是组件，它在组件层级结构没有父级。它只是一个对象，它使用UVM object相关信息进行注册，然后我们得到了transaction的各个字段。</p><p>本例是命令、地址和数据，因此在这里可以定义描述特定协议所需要的任何字段。我们在每个属性前面添加关键字rand，这样随机化的时候它们就会被随机化。</p><p>然后我们就有一些系统总体约束，这只是为了确保transaction对象在随机化的时候，各个字段至少具有合理的合法值。</p><p>接着是事务类的构造函数：transaction不是组件，在组件层次结构没有父级，因此构造函数没有父级参数，而是只有一个默认值的字符串name参数。</p><p>始终给transaction字符串名称包含默认值是一个好习惯，因为在UVM基类库中的某些地方，UVM会在不命名的情况下生成事务。</p><p>在定义事务类时，事务类包含的某些方法会非常方便。这里看到的第一个方法是“转换字符串”。</p><p>它只是一个函数，返回格式化为单个文本字符串的事务内容。</p><p>因此建议每当定义自己的事务类时，都提供一个转换字符串的方法，这在调试和打印时非常方便，只需使用 <code>$sformatf</code> 即可。</p><hr><h2 id="4-Sequence"><a href="#4-Sequence" class="headerlink" title="4. Sequence"></a>4. Sequence</h2><p><img src="https://img.sqlmaps.com/file/1788701754297_ext_b1cec7195a.png" alt="image"></p><p>sequence的作用主要是生成测试激励，sequence是在sequencer上运行的。</p><p>因此在sequencer上运行的sequence会生成transaction。</p><p>driver从运行在sequencer上的sequence获取transaction，然后驱动pins。monitor查看那些引脚摆动，将信息组装成进一步的transaction，然后分发到其余验证环境用于分析。</p><p>整个验证环境被划分为agent，每个agent对应DUT的接口。</p><p>然后可以通过所谓的virtual sequence协调或者编排多个agent的行为，因此virtual sequence会启动在几个不同sequencer上运行的多个sequence。每个sequencer都与DUT上不同的接口相关联。</p><p><img src="https://img.sqlmaps.com/file/1788701750474_ext_aa28b1cc3d.png" alt="image"></p><p>sequence是一个拓展了基类 <code>uvm_sequence</code> 的类对象，<code>uvm_sequence</code> 实际上是用 <code>sequence_item</code> 或者 <code>transaction</code> 的类型进行参数化，该sequence将会生成。<code>sequence_item</code> 是一个事务，但是如果要声明事务，从 <code>uvm_sequence_item</code> extend。在这种情况下，我们有一个类时钟和数据默认序列，我们自定义的sequence类拓展了 <code>uvm_sequence</code>，并且使用事务类型transaction参数。</p><p>TX sequence类，然后宏注册对象到工厂自动化。<code>uvm_object_utils</code><br>包含一个构造函数，像其他UVM objects一样，构造函数只有一个参数，也就是对象字符串的名称。</p><p>sequence 特点是有body task。</p><p>body task执行sequence 所做的的所有操作。sequence 可以执行很多不同的操作。</p><p>每一个sequence都会有一个body task，但task主体任务通常会不同。</p><p>body可以做：</p><ul><li>生成transaction。</li><li>可以 start 启动其他sequence。</li><li>或者sequence正在为DUT中的寄存器生成激励，此时sequence可以简单地通过UVM register读取和写入寄存器。</li></ul><p>如果在生成transaction 的作用下，拓展基类命名的 sequence item 是非常重要的。<br>如果使用sequence启动其他sequence或者使用sequence读取或者写入寄存器，transaction并不直接相关，因此它 甚至可以被省略。</p><h3 id="4-1-sequence-生成-transaction-的典型主体任务"><a href="#4-1-sequence-生成-transaction-的典型主体任务" class="headerlink" title="4.1 sequence 生成 transaction 的典型主体任务"></a>4.1 sequence 生成 transaction 的典型主体任务</h3><p><img src="https://img.sqlmaps.com/file/1788701729486_ext_9ab9b5c6da.png" alt="image"></p><p>此特定sequence 只仅仅生成了单个transaction，有时你的确会看到生成单个transaction。</p><p>更常见的是，一个sequence会生成多个transaction。</p><p>但是在此情况下，我们只从生成一个transaction的最小sequence 开始（四个步骤）：</p><ul><li>创建 交易对象。用create方法。data-type :: type_id::create（”req”）;&#x2F;&#x2F;工厂方法，使用工厂方法 来创建一个新的transaction对象<br> 注意：变量的名称 要和字符串参数的名称相同。这只是良好的编程习惯。</li><li>调用 start_item。start_item通知driver 此特定sequence 已经准备好发送请求。</li><li>然后从start_item 返回时，sequence 会随机化transaction对象，可能会带有一些内联的约束，我们稍后会看到一个内联约束的示例，如果随机化发生由于某种约束冲突而失败，那么我们将会收到一个错误。</li><li>sequence调用finish_item，而finish_item会完成sequence 和正在 pull的driver之间的特定的握手协议。也就是中介 从sequence pull 下transaction的driver之间的特定握手协议的生命周期。（通过调用finish_item 将事务发布给driver）</li></ul><p>上述四步的替代方法：uvm_do(req)、、</p><p>从编写过程式编码风格开始，明确调用 create；start_item；randomize 和 finish_item。</p><p>随着经验增加，可以用 <code>uvm_do</code> 宏，但是要非常小心，警惕作为初学者使用 <code>uvm_do</code>，可能会发现如果犯了一些错误，它是宏这一事实可能会隐藏真正正在发生的事情。</p><p>接着通过查看从sequence中获取事物的driver 来完成此笔交易。</p><h3 id="4-2-Driver-侧-run-phase"><a href="#4-2-Driver-侧-run-phase" class="headerlink" title="4.2 Driver 侧 run_phase"></a>4.2 Driver 侧 run_phase</h3><p><img src="https://img.sqlmaps.com/file/1788701818397_ext_ec4162a64f.png" alt="image"></p><p>这里是driver的run phase方法。</p><p>因此，在driver会有一个无限循环：</p><ul><li>driver 调用 get_next_item 来从sequence请求下一个事务。</li><li>sequence提供transaction时，driver 正在调用do_drive方法。该方法将摆动的接口中的引脚 到DUT.。</li><li>最后，driver调用seq_item_port的item_done方法告知sequence已经完成。</li></ul><p>因此，在生成transaction的 sequencer上运行的sequence 与 pull 事务的driver 的run phase方法之间，实际上在后台进行握手。</p><h3 id="4-3-握手原理"><a href="#4-3-握手原理" class="headerlink" title="4.3 握手原理"></a>4.3 握手原理</h3><p><img src="https://img.sqlmaps.com/file/1788701779901_ext_bfaf7f47a4.png" alt="image"></p><p>假设 sequence 通过 调用start_item 来启动。</p><p>也就是如果sequence 调用start_item，则start_item 或者暂停，知道driver准备就绪，来获取下一个transaction。</p><p>因此如果我们假设首先调用start_item，那么start_item 实际上会阻塞，直到driver 调用get_next_item。</p><p>当get_next_item时，driver 会告诉sequence 他已经准备好 摆动引脚，因此此时 start_item 返回，sequence有机会在发送给driver之前对transaction进行随机化。</p><p>因此 sequence 会快速连续地从start_item 调用randomize 返回，然后调用finish_item，而对finish_item的调用会将 transaction 发送给 driver。</p><p>因此当调用finish_item时，driver端对get_next_item的调用会返回，然后轮到driver 处理该transaction，执行它需要执行的操作。例如：摆动接口的引脚。</p><p>在此期间，finish_item会被阻塞，直到driver 通过调用 item_done 向sequence宣布它已完成。</p><p>所以，driver通过调用 item_done 来完成操作。此时，sequence从阻塞方法 finish_item 返回。如果driver 首先调用get_next_item,我们将会得到一个非常不同的事件过程。</p><p><img src="https://img.sqlmaps.com/file/1788701651075_ext_46a286d018.png" alt="image"></p><p>如果driver 首先调用get_next_item,我们将会得到一个非常不同的事件的过程。</p><p>假设 driver 首先调用 get_next_item, 但此时，sequence尚未准备好，那么“get_next_item”将会一直阻塞，直到sequence 准备好为止。</p><p>get_next_item实际上会一直阻塞，直到调用 “finish_item”。</p><p>sequence准备好后，它将会调用 start_item。start_item看到driver已经准备就绪，因此它将立即返回。</p><p>然后，sequence可以随机化transaction 并调用 randomize，finish_item；finish_item将事务发送给driver，然后事情按照上一张幻灯片。</p><hr><h2 id="5-启动-Sequence-的方法"><a href="#5-启动-Sequence-的方法" class="headerlink" title="5. 启动 Sequence 的方法"></a>5. 启动 Sequence 的方法</h2><p><img src="https://img.sqlmaps.com/file/1788701827136_ext_f11ddb124c.png" alt="image"></p><h3 id="5-1-从另一个-sequence-启动-sequence"><a href="#5-1-从另一个-sequence-启动-sequence" class="headerlink" title="5.1 从另一个 sequence 启动 sequence"></a>5.1 从另一个 sequence 启动 sequence</h3><p>首先从另一个sequence启动sequence开始。</p><p>首先看一下父sequence的body。该父sequence 将启动子sequence。</p><p>一个sequence想要启动另一个sequence，典型步骤是：</p><ul><li>创建子sequence对象。再次使用工厂方法调用，因此它是一下类型，子序列类类型：：type_id：：create 方法。确保参数字符串名字和变量名称匹配。</li><li>父sequence通过调用启动方法来启动该子sequence运行。<br> start（）</li></ul><p><img src="https://img.sqlmaps.com/file/1788701715215_ext_7695b32c39.png" alt="image"></p><p>第一个参数时启动子sequence的sequencer的引用；第二个参数 是对父sequence的引用。总是 this。</p><p>所以我们在这个sequencer m_clkndata。m_sequencer 启动我们的子序列。并确保将父sequence的第二个参数设置为我们当前正在执行其body方法的当前sequence。</p><p>一个sequence想要启动另一个sequence。但是我们要做的事情更多，不仅仅是创建一个子sequence。创建子序列对象后，对其随机化是一个非常好的做法。</p><p><img src="https://img.sqlmaps.com/file/1788701652295_ext_46ea2b4fc0.png" alt="image"></p><p>因此更好的做法是：rand ，子sequence类恰好包含任何 rand变量，则对子sequence对象进行随机化，然后在sequencer上启动该随机序列的对象。</p><p>如果我们关心随机的稳定性，可能还想插入另一个步骤。</p><p>因此更完整的解决方案是：创建我们的子sequence，然后 调用设置项目上下文，以便于该序列对象设置一些上下文本信息。set_item_context来实现随机稳定性。</p><p>通常，随机稳定性内置于UVM中，因为UVM的大多数对象都是根据对象的层次路径名和UVM 组件层次结构中的组件进行传播的。</p><p>但是有一个例外，那就是sequence对象。因此，如果手动创建并随机化sequence对象，并且关心随机稳定性，最好插入ERT这个额外的步骤。</p><p>如第二步所示，我们随机化sequence对象之前，我们会根据要运行的sequencer的完整层次结构来回溯sequence对象。</p><p>为了完整启动，在启动sequence之前，我们要设置它phase的启动。设置starting phase的原因是为了告诉 sequence正在UVM哪个 phase阶段运行，以便于sequence可以对该phase raise 和drop。</p><h3 id="5-2-从组件启动-sequence"><a href="#5-2-从组件启动-sequence" class="headerlink" title="5.2 从组件启动 sequence"></a>5.2 从组件启动 sequence</h3><p>从组件启动sequence</p><p><img src="https://img.sqlmaps.com/file/1788701645263_ext_3f4df273dd.png" alt="image"></p><p>就3个不同：</p><ul><li>是在run_phase 执行的，而不是父sequence body</li><li>参数parent sequence都是null</li><li>我们已经知道此sequence的上下文。稍微不同方式确定phase，而不是通过调用获取。该phase阶段可以用作run phase方法的参数。因此我们在设置set starting phase 的调用使用 run phase的参数。</li></ul><hr><h2 id="6-Virtual-Sequence"><a href="#6-Virtual-Sequence" class="headerlink" title="6. Virtual Sequence"></a>6. Virtual Sequence</h2><p>virtual sequence</p><p><img src="https://img.sqlmaps.com/file/1788701635240_ext_3bba9d81d5.png" alt="image"></p><p>通常是在UVM中用于指恰好在外面的sequence和我们环境env中的agent。</p><p>他们的工作是协调正在产生的激励的行为，跨多个接口到DUT。</p><p>通常virtual sequence 会启动在agent的sequencer上运行的sequence。</p><p>但是virtual sequence本身并不在 agent sequencer上运行。它在某个env上运行。</p><p>什么是virtual sequence？</p><ul><li>virtual sequence 是一个sequence。也就是说它最终是extend 于UVM sequence。</li><li>是一个 在其他sequencer上启动sequence的sequence。</li><li>是一个 不产生transaction的sequence。&#x2F;&#x2F;不一定</li><li>是一个读写寄存器的sequence等 &#x2F;&#x2F;</li></ul><p>如果有一个sequence不生成transaction，则该sequence不需要在sequencer上运行。</p><p>sequence只需要在sequencer上运行，当sequence产生transaction。</p><p>如果没有生成transaction，则是否在sequencer运行是可选择的。</p><p>这就是专家建议：virtual sequence工作是启动其他sequence。本身不需要在virtual sequencer上运行。</p><p>virtual sequence工作就是为了 orchestrate 其他sequence的行为。</p><p><img src="https://img.sqlmaps.com/file/1788701666024_ext_4d8943f75d.png" alt="image"></p><p>和之前的sequence启动非常相似：</p><ul><li>create virtual sequence</li><li>随机化sequence object</li><li>额外步骤：设置一些变量，使得virtual sequence能够定位sequencer，它将能够start 子sequence 在sequencer</li></ul><p>因此，我们实际在virtual sequence 对象分配了几个变量（在我们start sequence之前），然而不是在sequencer上运行我们的virtual sequence。</p><p>我们已经在一个 空sequencer上运行sequencer。null作为start的参数。我们可以选择在sequencer上运行virtual sequence。</p><h3 id="6-1-从-sequence-获取配置信息"><a href="#6-1-从-sequence-获取配置信息" class="headerlink" title="6.1 从 sequence 获取配置信息"></a>6.1 从 sequence 获取配置信息</h3><p>从sequence获取配置信息</p><p>sequencer的一个挑战是我们如何访问sequence的配置信息。</p><p>remember，sequence通常会生成代表着激励的transaction，并且你可能希望使用配置数据库。或者使用配置数据库中的信息进行参数化。</p><p><img src="https://img.sqlmaps.com/file/1788701848688_ext_fdee343127.png" alt="image"></p><p>使用sequence的技巧。pick up 配置信息基于它所在的sequencer。配置特对象具有特定agent。<br>所以在env的build phase，我们使用config_db来set 配置对象与特定agent。同时还想配置对象和该agent中的sequencer相关联。显式地，这可以通过实例字符串中的通配符来完成。<br>但是相反，我们又两个单独的调用</p><p><img src="https://img.sqlmaps.com/file/1788701794764_ext_d27c5696fa.png" alt="image"></p><p>上面是我们的sequence。<br>我们的sequence 可以做的是检索配置对象，通过获取与正在运行sequence的sequencer相关联的配置对象。正在运行sequencer可以通过 get_sequencer() 来找到。get_sequencer实际上是基于uvm sequence类的一个方法。任何sequence可以通过get_sequencer 找到当前正在运行的sequencer。然后该sequence从配置中获取与该sequencer 相关联的配置对象。</p><p>我们定义了一个count。表示这个特定序列将生成多少个transaction事务。所以我们有一个for循环。最多由配置对象中的count的变量来确定和限制。每次循环都会创建一个新transaction，start事务。然后使用内联约束随机化事务。使得事物的数据值实际上是循环计数。所以在这，我们将生成一系列的事务。其中数据从0开始递增 并最终达到count-1。</p><hr><h2 id="7-Sequence-的细节"><a href="#7-Sequence-的细节" class="headerlink" title="7. Sequence 的细节"></a>7. Sequence 的细节</h2><p>sequence的细节：</p><p><img src="https://img.sqlmaps.com/file/1788701782994_ext_c55fb5c152.png" alt="image"></p><p>工作：<br>sequence是在sequencer上运行的。sequencer是可复用的验证组件，它们拓展了UVM组件类</p><p><img src="https://img.sqlmaps.com/file/1788701656877_ext_48323af239.png" alt="image"></p><p>在UVM build phase 构建组件层级结构时，你可以实例化sequencer和driver<br>。另一方面sequence是object对象，这些对象包含有一个body方法，该body方法在模拟运行时 动态执行。也就是在UVM的 run phase。单个sequence 通常会生成 丛driver pull的transaction。每一个driver内置一个TLM port端口。而uvm sequencer内置一个 TLM export端口。在UVM build phase，将port连接到 export。然后在run phase，在sequencer上运行sequence生成transaction（通过start_item 和finish_item）。driver通过 get从sequence中获取transaction。</p><p><img src="https://img.sqlmaps.com/file/1788701680617_ext_60f326a703.png" alt="image"></p><p>它的工作方式时 start_item 和finish_item。这些都是由sequence的body 做的。sequence和driver发出的调用get握手。因此，实际上，只有在调用get时才返回start_item。所以start_item和get 标记为一个同步点。sequence和driver之间的控制流仅会在start_item和get都被调用才会继续。因此当调用get时，start_item 将返回。然后 sequence 调用finish_item 来完成实际的transaction并将其发送给driver。回到driver，只有当finish_item被调用，我们才会从get返回。</p><p>UVM允许TLM通信，或者验证环境中所有基于component类的组件之间事务级建模连接。</p><p><img src="https://img.sqlmaps.com/file/1788701601323_ext_255fbf182a.png" alt="image"></p><p>在此图中，可以看到sequencer和driver之间的事务级连接，还有事务级连接 用于分发来自agent的transaction，在env的其他组件进行分析（覆盖率收集 checking）。<br>上图时将会在UVM环境遇到的TLM连接的类型</p><hr><h2 id="8-UVM-的-Transaction-Level-Modeling（TLM）"><a href="#8-UVM-的-Transaction-Level-Modeling（TLM）" class="headerlink" title="8. UVM 的 Transaction Level Modeling（TLM）"></a>8. UVM 的 Transaction Level Modeling（TLM）</h2><p>UVM的 transaction level modeling（TLM）</p><p>核心理解：</p><ul><li>本质是通过函数&#x2F;任务调用进行通信。</li><li>使用port和export做间接连接，降低组件耦合。</li></ul><p><img src="https://img.sqlmaps.com/file/1788701607831_ext_28db626979.png" alt="image"></p><p>事务级建模简化为基本的要素就是使用函数的调用进行通信。</p><p>所以在构造块之间进行通信，或者通过执行task来在我们的UVM环境中的组件，或者在一个组件中申明的函数可用于从另一个组件调用。</p><p>实际上，没有什么可以阻止driver直接从sequencer中调用get任务，前提是driver知道它的名称。</p><p>但是这会在driver和sequencer之间产生依赖关系，而且代码难以维护。</p><p>在UVM中，我们通过所谓的port和export做间接连接（借鉴于SystemC）。实际上UVM借鉴了SystemC的TLM1标准，在SV中重新实现。</p><p>现在不是driver直接调用sequencer的get，而是driver通过port连接到sequencer的export。因此export的作用是声明特定组件将提供特定任务或函数。</p><p><img src="https://img.sqlmaps.com/file/1788701661052_ext_4b5ed21a3e.png" alt="image"></p><p>所以在此例子中，uvm sequence item pull implementation。说我们的sequencer 提供了get任务的实现。</p><p><img src="https://img.sqlmaps.com/file/1788701725704_ext_88b8275c56.png" alt="image"><br>port声明特定组件需要 一个特定的任务可用  （require a get()）。 在本例中，uvm sequence item pull port 表示我们的driver 将调用get函数。</p><p>agent中，然后在top 实例化 sequencer时，我们将port 连接到export的driver。</p><p>这有效的签订了provider和特定方法的要求之间合同。</p><p>我们使用connect的 sequence item port的方法，UVM内置的，以便于将driver上的port连接到sequencer上的export。</p><p><img src="https://img.sqlmaps.com/file/1788701598858_ext_20a3b4e810.png" alt="image"></p><p>困惑：export，你假设有东西从sequencer传出。</p><p>从sequencer发出的并不是对get任务的调用（相反 export 反映了 sequencer 正在exporting的事实或者提供get任务）以便于driver可以调用它。</p><p>想象，task正在提供，从左到右完成事务从左到右的传递，但是get任务的调用却是从右到左。</p><p><img src="https://img.sqlmaps.com/file/1788701693220_ext_65d3072e3d.png" alt="image"></p><p>在这个例子，有个agent，我们有一个连接在driver的port和 sequencer的export。</p><p>所以这里：</p><ul><li>seq_item_port.connect(seqr.seq_item_export)。</li><li>这都是在connect phase之中。</li></ul><p><img src="https://img.sqlmaps.com/file/1788701715325_ext_74564feef9.png" alt="image"></p><p>driver的run phase：<br>调用 seq_item_port的方法 get_next_item。</p><p>TLM特定的协议：</p><ul><li>put（req）</li><li>get（req）</li><li>write（tx）</li></ul><p><img src="https://img.sqlmaps.com/file/1788701759505_ext_b2cff6998d.png" alt="image"></p><p>put用于发送事务，是一个阻塞方法，意味着put不会返回，直到transaction的接收方准备好接受下一个put调用。</p><p>结果就是，如果进行一系列调用，每个transaction都会从头到尾传递，所以put不会覆盖或者丢失对象。</p><p>这同样适用于get。</p><p>get也是阻塞方法：调用者通过get请求事务，而get实现会阻塞直到准备好返回transaction。</p><p>当get返回时，对象会从右侧队列中被有效移除，这样下次调用get时会收到流中的下一个事务。</p><p>也就是说，一系列put或者get调用可以稳定传递transaction流而不丢失。</p><p>第三种是write方法，和analysis port一起使用，为非阻塞方法。</p><p>它不消耗仿真时间、会立即返回。正因为如此，implementation一侧必须立即处理作为参数传递的transaction。</p><p><img src="https://img.sqlmaps.com/file/1788701845296_ext_fbdb4a0201.png" alt="image"></p><p>你可以使用这些put、get和write方法来实现push连接或者pull连接。这个slide里有每种连接的示例。</p><p>在TOP里，put调用在左侧生产者和右侧消费者之间实现push连接。生产者调用put把transaction推给消费者，消费者在底部执行put任务。</p><p>也有pull连接：左侧consumer调用get，从右侧生产者拉取事务。这里很容易混淆，所以要始终区分控制流方向和数据流方向：</p><ul><li>使用push连接时，控制从左到右流动，事务也是从左到右传递。</li><li>使用pull连接时，控制从左到右流动（消费者调用get），但事务从右到左返回给消费者。</li></ul><p>因此在TLM里：</p><ul><li>port允许组件调用组件外部声明的task或function。</li><li>export允许组件接收对组件内部实现的task或function的传入调用。</li></ul><p>圆圈表示export或imp：</p><ul><li>export是中间节点（waypoint）。</li><li>imp是路线终点（实际实现位置）。</li></ul><p>如果组件有export，它会把transaction继续传给子组件处理；如果组件有imp，则该组件本身必须提供对应方法实现。</p><p><img src="https://img.sqlmaps.com/file/1788701720013_ext_80fd6fbd6e.png" alt="image"></p><p>左侧有端口和对put方法的调用，这些方法沿着层次结构向上传递；在图的右侧我们有 export和对put方法的调用，这些方法沿着组件向下传递。</p><p>因此：</p><ul><li>port用于在组件外进行方法的调用。</li><li>export用于在组件内部进行方法的调用。</li></ul><p>在左侧，我们有一个子组件，通过其端口调用put，子组件的port连接到父组件的端口，直到组件层次结构的顶端，连接到右侧组件的export。</p><p>然后，export 连接到export，沿着层次结构向下传递，直到最终连接终止与imp。</p><p>而具有imp的组件有义务实际提供相应方法的实现。在此特定情况下为put任务。</p><p>port只是用于将方法调用从组件传递出去；export用于调用传递到组件内部；在top层次结构中，可以在port和export之间建立点对点的连接。</p><hr><h2 id="9-分析接口-Analysis-Port"><a href="#9-分析接口-Analysis-Port" class="headerlink" title="9. 分析接口 Analysis Port"></a>9. 分析接口 Analysis Port</h2><p>分析接口 analysis port</p><p><img src="https://img.sqlmaps.com/file/1788701570893_ext_0f523fcd2d.png" alt="image"></p><p>analysis port提供了一种广播机制。</p><p>analysis port允许agent发送事务进行分析，但是agent既不知道也不关心transaction的去向。</p><p>事实上，analysis port主要特性是根本不需要连接它们。</p><p>例子中，monitor上有一个分析端口，此端口连接到其父组件agent上的分析端口；但此agent上的分析端口不必连接到任何其他地方，或者它可以连接到另一个组件（subscriber）。</p><p><img src="https://img.sqlmaps.com/file/1788701810880_ext_e7ad0ecfcc.png" alt="image"></p><p>订阅者时可以订阅来接收的通过analysis port 发送的 transaction 的组件。</p><p>并且analysis port可以设置连接到0、1或者多个订阅者。这是分析口的主要特点。</p><p><img src="https://img.sqlmaps.com/file/1788701704624_ext_6a157664c1.png" alt="image"></p><p>它们不需要连接，也可以连接多个subscribers。这里的subscriber 有时UVM组件中的检查或者覆盖率收集组件。</p><p><img src="https://img.sqlmaps.com/file/1788701732289_ext_a768ac2b1e.png" alt="image"><br>我们通过analysis port调用的方法只有write。</p><p>monitor调用其分析端口的write方法后，该write会通过agent的analysis port向上传播，然后传递给连接到该analysis port的所有订阅者。</p><p>write方法只有一个输入参数。</p><p>write方法只能读取传入transaction的值，不允许修改；它接收的是事务值（只读语义）。</p><p>write方法是非阻塞的，必须立即返回，因此各个订阅者的write调用顺序不重要。实际上从monitor analysis port调用write时，无法控制各订阅者write的调用顺序。</p><p>提供乐意一对多的形式的连接。</p><p>一个分析口能够将多事务广播给多个订阅者，这个和常规port 和export形成对比。常规port和export严格来说是一个一对一的。</p><p><img src="https://img.sqlmaps.com/file/1788701619476_ext_3a17d787db.png" alt="image"></p><p>driver和sequencer之间有pull连接；driver调用get或者get_next_item从sequencer拉取事务。</p><p>另一方面，analysis port提供push连接。write方法会把transaction通过agent内的analysis port向外推送。</p><p>右侧driver port和sequencer export是点对点连接。</p><p>另一方面，我们也有子到父的连接示例：monitor的analysis port（子组件）连接到其父agent上的analysis port，然后agent上的analysis port再和多个订阅者上的export建立点对点连接。</p><p><img src="https://img.sqlmaps.com/file/1788701823883_ext_ed27f585e2.png" alt="image"></p><p>在类中 申明 analysis port。通过调用构造函数 new函数来 构造analysis port。analysis port 必须使用new不能用工厂方法（不支持机制））。</p><p><img src="https://img.sqlmaps.com/file/1788701579050_ext_10fdb720c2.png" alt="image"></p><p>查看设计和测试过程中发生引脚的摆动，将引脚摆动组装为事务对象，然后通过调用analysis port 的write方法将事务对象通过分析板发送出去。</p><p>这是UVM的典型编码模式，monitor通常会查看引脚的摆动，将引脚的摆动组装成transaction，并通过analysis port 发送事务。</p><p>现在组件层级结构向上移动了。</p><p><img src="https://img.sqlmaps.com/file/1788701584909_ext_1c6c9647a0.png" alt="image"></p><p>在此时agent的connect phase阶段。<br>可以在top建立两个连接，monitor上的analysis port 连接到  agent上的 analysis port。再次看到driver 上的 port 和 sequencer上的 export。</p><p>然后组件层级结构再向上移动，我们到达 特定agent的最终类，因此在 env的 build phase中，</p><p><img src="https://img.sqlmaps.com/file/1788701687864_ext_6234a0bc1d.png" alt="image"><br>我们实例化 agent的组件和订阅者或者覆盖率收集组件。</p><p>然后在此类的 connect phase，我们调用analysis port 的连接方法，将代理的analysis port 连接到订阅者上的analysis export。</p><p><img src="https://img.sqlmaps.com/file/1788701820097_ext_ef2aec839c.png" alt="image"><br>现在我们可以查看订阅者。</p><p>因此UVM订阅者是UVM标准基类之一，它extend了 UVM component。换句话说，UVM subscriber是另一种组件，就像driver monitor agent一样，都是各种组件。</p><p>UVM subscriber 特殊之处在于内置一个分析的imp。</p><p><img src="https://img.sqlmaps.com/file/1788701567258_ext_0df88ed986.png" alt="image"></p><p>在图上看到的export或者analysis imp实际上是在 uvm subscriber基类中实现的，extend了 component类。</p><p>使用此类时，只需要实现与该analysis imp关联的正确方法，每个具有analysis imp的组件必须提供相应的正确方法，因此在代码底部，可以看到正确方法的实现。</p><p>始终和覆盖率类的方法保持一致。顺便说一下，如果有一个订阅者，但是没有正确实现的方法，将会编译报错。</p><p>因此这个特定的subscriber被用来收集一些覆盖率，这是uvm subscriber 通常会做的事。</p><p>同时检查 subscriber 类是否具有 覆盖组，然后在正确的方法中，我们使用它获取传入的transaction，来分配一个局部变量，然后调用覆盖组的采样方法对覆盖率进行采样，并将这些值写入覆盖率数据库。</p><p>我们还会检查该特定覆盖组的覆盖率是否达到100%，以达到时将设置 m已经覆盖。</p><hr><h2 id="10-加深理解-TLM-技术"><a href="#10-加深理解-TLM-技术" class="headerlink" title="10. 加深理解 TLM 技术"></a>10. 加深理解 TLM 技术</h2><p>加深理解tlm技术。</p><ul><li>第一种：处理多个传入transaction。</li><li>第二种：存储分析事务以供以后使用（如果不想处理这些transaction）。</li></ul><h3 id="10-1-处理多个传入-transaction"><a href="#10-1-处理多个传入-transaction" class="headerlink" title="10.1 处理多个传入 transaction"></a>10.1 处理多个传入 transaction</h3><p>处理多个传入transaction</p><p><img src="https://img.sqlmaps.com/file/1788701750876_ext_ab7e5e78ec.png" alt="image"></p><p>处理多个传入的transaction，我们会生成一个 reference model。</p><p>RM通常必须处理多个传入数据流，在UVM中执行此操作，我们面临的挑战是每个transaction都需要有一个与之关联的正确方法write来处理传入analysis export。</p><p>但SV不支持函数重载，意味着在SV单个类中，不能有多个重名的方法，所以为了绕过SV语言的限制，UVM提供一个辅助宏 uvm_analysis_imp_decl(_0)。</p><p>随意使用这个宏的作用是声明是一个新类和一个关联的write方法。该类名为uvm_analysis_imp_0声明为参数宏的参数，这些宏创建了两个新类我们用它们来声明 analysis export变量。</p><p>还声明了两个新方法 write_0&#x2F;1来替代默认的 write方法。</p><p>请注意，我们的参考模型不是一个订阅者，而是一个组件，因为他有两个传入的事务流。如果我们只有一个传入transaction流，我们只能使用uvm subscriber。因为uvm subscriber只有一个analysis export。</p><h3 id="10-2-存储分析事务以供以后使用（如果不想处理这些transaction）"><a href="#10-2-存储分析事务以供以后使用（如果不想处理这些transaction）" class="headerlink" title="10.2 存储分析事务以供以后使用（如果不想处理这些transaction）"></a>10.2 存储分析事务以供以后使用（如果不想处理这些transaction）</h3><p>第二种 存储分析事务以供以后使用（如果不想处理这些transaction）</p><p>如果在订阅者中，你不想立即处理传入 transaction，而是将其保存以供以后使用，我们可以使用常规的 uvm component组件来代替uvm subscriber，然后在该组件内，将事务转发到fifo。</p><p><img src="https://img.sqlmaps.com/file/1788701776041_ext_b657164d23.png" alt="image"></p><p>换句话说，我们通过analysis export 接收传入的交易，然后在内部将该 transaction 发布到fifo，以便于在稍后可以在闲暇时使用它，uvm提供了一个fifo。uvm_tlm_analysis_fifo 专门用于此目的。</p><p>所以analysis export 和fifo均未注册工厂自动化，因此在new的构造函数中实例化这些对象，然后传入 analysis export 和 fifo组件上分 analysis export之间创建了子组件到父组件。</p><p>因此，通过analysis port传入的任何交易现在都将直接转发给fifo，fifo实际上具有uvm analysis imp 和内置的write方法。</p><p>然后在fifo 订阅者执行 run phase，在无限循环中，我们调用一个阻塞的get方法从fifo中获取下一个transaction。</p><p>因此，当我们第一次通过这个循环时，如果订阅者尚未从agent中收到任何analysis 交易，则get将阻塞，直到第一个analysis transaction。</p><p>换句话说，我们通过analysis export 接收传入的交易，然后在内部将该 transaction 发布到fifo，以便于在稍后可以在闲暇时使用它，uvm提供了一个fifo。uvm_tlm_analysis_fifo 专门用于此目的。</p><p>所以analysis export 和fifo均未注册工厂自动化，因此在new的构造函数中实例化这些对象，然后传入 analysis export 和 fifo组件上分 analysis export之间创建了子组件到父组件。</p><p>因此，通过analysis port传入的任何交易现在都将直接转发给fifo，fifo实际上具有uvm analysis imp 和内置的write方法。</p><p>然后在fifo 订阅者执行 run phase，在无限循环中，我们调用一个阻塞的get方法从fifo中获取下一个transaction。</p><p>因此，当我们第一次通过这个循环时，如果订阅者尚未从agent中收到任何analysis 交易，则get将阻塞，直到第一个analysis transaction。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;目录&quot;&gt;&lt;a href=&quot;#目录&quot; class=&quot;headerlink&quot; title=&quot;目录&quot;&gt;&lt;/a&gt;目录&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#1-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF-uvm&quot;&gt;1. 为什么是 UV</summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>Common 分解</title>
    <link href="https://sqlmaps.com/2026/08/01/Common%E5%88%86%E8%A7%A3/"/>
    <id>https://sqlmaps.com/2026/08/01/Common%E5%88%86%E8%A7%A3/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<table><thead><tr><th>1-时钟</th><th>1</th><th>1)  确定DUT中时钟的数量，频率范围;     2) 测试用例须覆盖各时钟各种标称频率的组合，对于多时钟，须检查各时钟之间频率差最大&#x2F;最小时DUT的工作状况。</th></tr></thead><tbody><tr><td>2</td><td>若DUT有多个时钟，验证环境要支持各时钟的任意相位关系。</td><td></td></tr><tr><td>3</td><td>无论单时钟还是多时钟，验证环境均要支持时钟不确定性。</td><td></td></tr><tr><td>4</td><td>如果DUT支持门控时钟，需要对门控时钟进行功能验证，包括clock  gating和ungating的切换</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>2-复位</td><td>1</td><td>确定DUT中复位信号的数量，并同设计，软件确定复位顺序。</td></tr><tr><td>2</td><td>复位后需要检查寄存器默认值。</td><td></td></tr><tr><td>3</td><td>复位后（包括二次复位）需要检查接口输出信号复位值，推荐使用断言检查。</td><td></td></tr><tr><td>5</td><td>二次复位后打流进行逻辑功能检查</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>3-寄存器</td><td>1</td><td>用CSR工具执行基础读写复位检查</td></tr><tr><td>2</td><td>用寄存器模型工具执行寄存器读写以及复位检查</td><td></td></tr><tr><td>3</td><td>在使用HBUS、RGR等总线对寄存器进行读写访问时，覆盖如下  种场景：     SCN-1:valid信号无效时，总线上其他信号驱动成X态     SCN-2:valid信号无效时，总线上其他信号驱动成0     SCN-3:valid信号无效时，总线上其他信号取反</td><td></td></tr><tr><td>4</td><td>读reserved地址不应引起总线长时间挂住</td><td></td></tr><tr><td>5</td><td>写reserved地址不应引起总线长时间挂住</td><td></td></tr><tr><td>6</td><td>写RO寄存器不应引起总线长时间挂住，寄存器不应该被改写</td><td></td></tr><tr><td>7</td><td>写清寄存器，读清寄存器等特殊操作寄存器验证</td><td></td></tr><tr><td>8</td><td>读WO寄存器不应引起总线长时间挂住，是否返回不期望的值</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>4-存储单元</td><td>1</td><td>总线上data除使用随机激励产生外，还需要使用下列特殊pattern     PAT-1:{N{8’b0101_0101}} (ie. 0x5555…5555)     PAT-2:{N{8’b1010_1010}} (ie. 0xaaaa…aaaa)     PAT-3:{N{8’b0000_0000}} (ie. 0x0000…0000)     PAT-4:{N{8’bffff_ffff}} (ie. 0xffff…ffff)     PAT-5:每两个pattern之间执行bit翻转</td></tr><tr><td>2</td><td>相同地址写-回读，使用所有特殊pattern，每两次写之间pattern翻转，检查存储单元相邻bit是否互相影响</td><td></td></tr><tr><td>3</td><td>写下一个地址，读上一个地址并比较上个地址写-读的数据是否相同，用来检查地址译码器是否正确。</td><td></td></tr><tr><td>4</td><td>片地址写-回读顺序操作，比较写-读的数据是否相同，用来检查地址译码器是否正确。</td><td></td></tr><tr><td>5</td><td>地址非对齐访问，写入数据不影响同一条地址线中其他字节</td><td></td></tr><tr><td>6</td><td>访问地址跨越bank边界，检查地址译码器是否正确。</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>5-ECC单元</td><td>1</td><td>Single  Error纠错</td></tr><tr><td>2</td><td>Double  Error检错</td><td></td></tr><tr><td>3</td><td>检查Syndrom功能</td><td></td></tr><tr><td>4</td><td>Error上报&#x2F;不上报</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>6-寄存器逻辑功能</td><td>1</td><td>中断相关寄存器，检查是否可以屏蔽中断，是否能够正确反映中断状态，是否可以清除，参考</td></tr><tr><td>2</td><td>通道&#x2F;业务开关类寄存器检查打开时对应的通道&#x2F;业务被触发，关闭时对应的通道&#x2F;业务被关闭，如果存在多个独立通道&#x2F;业务，则参考  - 19</td><td></td></tr><tr><td>3</td><td>在post_main_phase通过前门动态读取状态寄存器，并检查内容正确</td><td></td></tr><tr><td>4</td><td>阈值相关寄存器，覆盖阈值极大值，极小值，对于full  dynamic和limited dynamic配置，覆盖从极大值到极小值的变化</td><td></td></tr><tr><td>5</td><td>检查关联的配置寄存器是否全部有效组合都被覆盖。</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>7-边界信号</td><td>1</td><td>检查上电复位后端口输出信号默认值检查，不应有X态，不应有中断或异常报出，推荐用SVA检查</td></tr><tr><td>2</td><td>检查二次复位后端口输出信号默认值检查，不应有X态，不应有中断或异常报出，推荐用SVA检查</td><td></td></tr><tr><td>3</td><td>人为制造输入信号相位偏移，检查是不应对逻辑功能造成影响（不用的输入tie0或tie1）</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>8-接口总线</td><td>1</td><td>如果接口总线承载的是协议，则验证owner需要熟悉协议中每一个位域的功能和bit位置，并同设计以及上下游关联模块设计、验证owner确认每个位域理解相同，有测试用例覆盖</td></tr><tr><td>9-中断</td><td>1</td><td>优先级检查</td></tr><tr><td>2</td><td>中断输出信号为高电平指示，非脉冲指示</td><td></td></tr><tr><td>3</td><td>如果存在中断使能开关，验证开关功能正确</td><td></td></tr><tr><td>4</td><td>检查中断屏蔽寄存器的功能，以及同中断源的bitmap</td><td></td></tr><tr><td>5</td><td>检查中断状态寄存器的功能，以及同中断源的bitmap</td><td></td></tr><tr><td>6</td><td>检查清中断功能</td><td></td></tr><tr><td>7</td><td>检查中断可以频繁触发和清除</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>10-异常、错误处理</td><td>1</td><td>检查时序异常，数据异常时DUT的工作状态（包括DUT是否能对错误进行处理，丢弃，恢复）</td></tr><tr><td></td><td></td><td></td></tr><tr><td>11-robust</td><td>1</td><td>接口处于IDLE状态时，将开关&#x2F;使能类指示信号外的其他信号驱动成不同状态，然后使能接口，检查功能正确：     SCN-1：X态     SCN-2：Z态     SCN-3：各bit为0     SCN-4：各bit为1     SCN-5：同最后一次有效传输取反     SCN-6：保持最后一次有效传输的值</td></tr><tr><td>2</td><td>复位状态下输入各种类型的信号状态，检查逻辑不受影响</td><td></td></tr><tr><td>3</td><td>对于解耦的逻辑，某逻辑异常状态不影响其他逻辑</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>12-性能</td><td>1</td><td>明确SPEC中各性能指标，每一张性能图表(带宽，流量)要和DE核对，确认是否可测，如果不可测要注明</td></tr><tr><td></td><td></td><td></td></tr><tr><td>13-反压</td><td>1</td><td>TBD</td></tr><tr><td></td><td></td><td></td></tr><tr><td>14-FeedThrough</td><td>1</td><td>使用SVA和静态验证方式对RTL的FT进行连通性验证</td></tr><tr><td>2</td><td>通过功能验证检查FT对功能的影响符合预期</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>15-Cascade  Arbiter</td><td>1</td><td>Fixed Priority(FP)</td></tr><tr><td>2</td><td>Fair Round Robin(FRR)</td><td></td></tr><tr><td>3</td><td>Weight Round  Robin(WRR)</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>16-FIFO</td><td>1</td><td>使用断言检查full&#x2F;empty的逻辑关系，full和push信号不能同时有效，empty和pop信号不能同时有效，full和empty信号不能同时有效</td></tr><tr><td>2</td><td>使用断言检查push&#x2F;pop的时序，覆盖连续push，连续pop以及push  pop同时出现</td><td></td></tr><tr><td>3</td><td>覆盖empty撤销的同时触发pop场景，检查empty被拉起</td><td></td></tr><tr><td>4</td><td>覆盖full撤销的同时触发push场景，检查full被拉起</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>17-数据通路串扰</td><td>1</td><td>检查数据通道相互独立，处理业务时互不影响</td></tr><tr><td>2</td><td>如果通道可以单独复位，检查复位一个通道不影响其他通道业务</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>18-链表</td><td>1</td><td>链表长度检查：检查链表能申请的最大地址；如果设计中有长度记录寄存器，仿真结束后前门读取该寄存器检查链表长度</td></tr><tr><td>2</td><td>检查链表内部发生错误时，是否触发中断&#x2F;异常上报</td><td></td></tr><tr><td>3</td><td>检查链表内部申请、释放指针是否重复</td><td></td></tr><tr><td>4</td><td>检查上、下链的性能</td><td></td></tr><tr><td>5</td><td>背靠背重复上下链</td><td></td></tr><tr><td></td><td></td><td></td></tr><tr><td>99-其他</td><td>1</td><td>gen_frr_arb复位信号连接检查</td></tr><tr><td></td><td></td><td></td></tr></tbody></table>]]></content>
    
    
      
      
    <summary type="html">&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1-时钟&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;1)  确定DUT中时钟的数量，频率范围;     2) 测试用例须覆盖各时钟各种标称频率的组合，对于多时钟，须检查各时钟之间频率差最大&amp;#x2F;最小时DUT的工作状况。&lt;/th</summary>
      
    
    
    
    <category term="验证方法" scheme="https://sqlmaps.com/categories/%E9%AA%8C%E8%AF%81%E6%96%B9%E6%B3%95/"/>
    
    
    <category term="验证方法" scheme="https://sqlmaps.com/tags/%E9%AA%8C%E8%AF%81%E6%96%B9%E6%B3%95/"/>
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
  </entry>
  
  <entry>
    <title>SystemVerilog 宏使用指南</title>
    <link href="https://sqlmaps.com/2026/08/01/SystemVerilog%E5%AE%8F%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/"/>
    <id>https://sqlmaps.com/2026/08/01/SystemVerilog%E5%AE%8F%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><h3 id="什么是宏？"><a href="#什么是宏？" class="headerlink" title="什么是宏？"></a>什么是宏？</h3><p>宏是使用 &#96;define 编译器指令创建的代码片段。它们基本上有 3 个部分 - 名称、一些文本和可选参数。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> macroname(ARGS) macrotext</span></span><br></pre></td></tr></table></figure><p>在编译时，代码中出现的 <code>macroname 都会被替换为 </code>macrotext 字符串，并且 <code>ARGS 是可以在 </code>macrotext 中使用的变量。</p><h3 id="为什么要使用宏？"><a href="#为什么要使用宏？" class="headerlink" title="为什么要使用宏？"></a>为什么要使用宏？</h3><p>在编写测试平台和用例时，经常会遇到代码重复的问题。比如，需要在多个地方打印字节数组，会出现类似这样的重复代码：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> ii=<span class="number">0</span>; ii&lt;numbytes; ii++) <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">if</span> ((ii !=<span class="number">0</span>) &amp;&amp; (ii % <span class="number">16</span> == <span class="number">0</span>))</span><br><span class="line">        <span class="built_in">$display</span>(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    <span class="built_in">$display</span>(<span class="string">&quot;0x%x &quot;</span>, bytearray[ii]);</span><br><span class="line"><span class="keyword">end</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">//2</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> ii=<span class="number">20</span>; ii&lt;<span class="number">100</span>; ii++) <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">if</span> (ii % <span class="number">16</span> == <span class="number">0</span>)</span><br><span class="line">        <span class="built_in">$display</span>(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    <span class="built_in">$display</span>(<span class="string">&quot;0x%x &quot;</span>, pkt[ii]);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>通过定义宏，可以将 5 行重复代码简化为 1 行调用，不仅减少了代码量，还提升了可读性。更重要的是，如果需要修改打印格式，只需在宏定义处修改一次即可！</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> print_bytes(ARR, STARTBYTE, NUMBYTES) \</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> ii=STARTBYTE; ii&lt;STARTBYTE+NUMBYTES; ii++) <span class="keyword">begin</span> \</span><br><span class="line">        <span class="keyword">if</span> ((ii != <span class="number">0</span>) &amp;&amp; (ii % <span class="number">16</span> == <span class="number">0</span>)) \</span><br><span class="line">            <span class="built_in">$display</span>(<span class="string">&quot;\n&quot;</span>); \</span><br><span class="line">        <span class="built_in">$display</span>(<span class="string">&quot;0x%x &quot;</span>, ARR[ii]); \</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用宏后，代码的意图更加明确</span></span><br><span class="line">`print_bytes(bytearray, <span class="number">0</span>, numbytes)</span><br><span class="line">`print_bytes(pkt, <span class="number">20</span>, <span class="number">80</span>)</span><br></pre></td></tr></table></figure><p>宏特别适用于专用的打印功能等场景。虽然功能上不如 <code>uvm_info</code> 强大，但对于简单场景已经足够。如果团队成员都使用统一的宏，就能获得一致的输出格式，让所有人都能更轻松地阅读仿真日志。</p><p><strong>团队宏使用建议：</strong></p><ol><li>建立团队宏库，统一管理常用宏定义</li><li>制定宏命名规范，例如使用 <code>*_utils</code> 后缀（如 <code>print_byte_utils</code>）</li><li>将宏定义集中放在 <code>macro_utils.sv</code> 文件中，并在基础包中引用</li><li>在合适的场景下优先使用宏，减少重复代码，提升开发效率</li></ol><p>通过以上方式，宏可以成为团队设计&#x2F;验证方法论的重要组成部分。</p><h2 id="宏语法"><a href="#宏语法" class="headerlink" title="宏语法"></a>宏语法</h2><h3 id="宏命名规则"><a href="#宏命名规则" class="headerlink" title="宏命名规则"></a>宏命名规则</h3><p>宏名称的命名规则很简单：可以使用任何名称，但不能使用编译器指令关键字，如 <code>define、</code>ifdef、<code>endif、</code>else、<code>elseif、</code>include 等。如果错误地使用了这些关键字，编译器会报错：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> <span class="keyword">include</span>(ARG) `&quot;ARG.master`&quot;</span></span><br></pre></td></tr></table></figure><p><strong>Mentor Graphics Questa:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">** Error: macros_one.sv(4): (vlog-2264) Cannot redefine compiler directives:</span><br><span class="line">`include.</span><br></pre></td></tr></table></figure><p><strong>Synopsys VCS:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">Error-[IUCD] Illegal use of compiler directive</span><br><span class="line">  Illegal use of compiler directive: `include is illegal in this context.</span><br><span class="line">  &quot;macros_one.sv&quot;, 28</span><br><span class="line">  Source info:         $display(`include(clock));</span><br><span class="line"></span><br><span class="line">**重要提醒：** 宏的命名空间是全局的，编译顺序决定了宏的有效性。无论宏定义在类内还是类外，一旦被编译器识别，就可以在任何地方使用。如果重新定义宏，编译器会发出警告，需要特别注意这些日志信息：</span><br><span class="line"></span><br><span class="line">** Warning: macros2.sv(7): (vlog-2263) Redefinition of macro: </span><br><span class="line">    &#x27;debug&#x27; (previously defined near macros2.sv(3)) .</span><br><span class="line"></span><br><span class="line">    Parsing design file &#x27;macros4.sv&#x27;</span><br><span class="line"></span><br><span class="line">    Warning-[TMR] Text macro redefined</span><br><span class="line">    macros2.sv, 7</span><br><span class="line">      Text macro (debug) is redefined. The last definition will override previous </span><br><span class="line">      ones.</span><br><span class="line">      In macros2.sv, 3, it was defined as $display(&quot;%s, %0d: %s&quot;, `__FILE__, </span><br><span class="line">      `__LINE__, msg)</span><br></pre></td></tr></table></figure><h3 id="反引号特殊用法详解"><a href="#反引号特殊用法详解" class="headerlink" title="反引号特殊用法详解"></a>反引号特殊用法详解</h3><p>SystemVerilog 中有 3 个特殊的反引号操作符需要重点掌握：</p><h4 id="1-字符串化操作符-“"><a href="#1-字符串化操作符-“" class="headerlink" title="1. 字符串化操作符 `“"></a>1. 字符串化操作符 `“</h4><p>`“ 操作符用于将宏参数转换为字符串。如果宏文本用普通双引号（”）括起来，参数不会被替换，会被当作普通字符串处理。而 `“（双引号前的反引号）则告诉编译器：</p><ul><li>保留双引号字符</li><li>替换双引号内的参数</li><li>展开嵌入的其他宏</li></ul><p>让我们通过示例来理解：</p><p><strong>示例 1.1</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Example 1.1 */</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_bad(MOD) &quot;MOD.master&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_good(MOD) `&quot;MOD.master`&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">program</span> <span class="keyword">automatic</span> test;</span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        <span class="built_in">$display</span>(`append_front_bad(clock1));</span><br><span class="line">        <span class="built_in">$display</span>(`append_front_good(clock1));</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endprogram</span>: test</span><br></pre></td></tr></table></figure><p><strong>运行结果</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># MOD.master</span><br><span class="line"># clock1.master</span><br></pre></td></tr></table></figure><p><strong>分析：</strong></p><ul><li><code>append_front_bad</code> - 接受参数 MOD，期望将其与”.master”拼接。但由于使用了普通双引号，参数不会被替换，输出结果为字符串”MOD.master”</li><li><code>append_front_good</code> - 正确的版本。通过在双引号前使用反引号，告诉编译器在宏展开时替换参数 MOD</li></ul><h4 id="2-标记拼接操作符"><a href="#2-标记拼接操作符" class="headerlink" title="2. 标记拼接操作符 ``"></a>2. 标记拼接操作符 ``</h4><p>`` （双反引号）是标记分隔符，帮助编译器明确区分宏参数和字符串的其他部分。当参数需要与其他字符紧密拼接时特别有用。</p><p><strong>示例 1.2</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Example 1.2 */</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_2a(MOD) `&quot;MOD.master`&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_2b(MOD) `&quot;MOD master`&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_2c_bad(MOD) `&quot;MOD_master`&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_2c_good(MOD) `&quot;MOD``_master`&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_middle(MOD) `&quot;top_``MOD``_master`&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_end(MOD) `&quot;top_``MOD`&quot;</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> append_front_3(MOD) `&quot;MOD``.master`&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">program</span> <span class="keyword">automatic</span> test;</span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        <span class="comment">/* Example 1.2 */</span></span><br><span class="line">        <span class="built_in">$display</span>(`append_front_2a(clock2a));</span><br><span class="line">        <span class="built_in">$display</span>(`append_front_2b(clock2b));</span><br><span class="line">        <span class="built_in">$display</span>(`append_front_2c_bad(clock2c));</span><br><span class="line">        <span class="built_in">$display</span>(`append_front_2c_good(clock2c));</span><br><span class="line">        <span class="built_in">$display</span>(`append_front_3(clock3));</span><br><span class="line">        <span class="built_in">$display</span>(`append_middle(clock4));</span><br><span class="line">        <span class="built_in">$display</span>(`append_end(clock5));</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endprogram</span>: test</span><br></pre></td></tr></table></figure><p><strong>运行结果</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># clock2a.master</span><br><span class="line"># clock2b master</span><br><span class="line"># MOD_master</span><br><span class="line"># clock2c_master</span><br><span class="line"># clock3.master</span><br><span class="line"># top_clock4_master</span><br><span class="line"># top_clock5</span><br></pre></td></tr></table></figure><p><strong>分析：</strong></p><ul><li><code>append_front_2a/2b</code> - 空格和句点是天然的标记分隔符，编译器可以清楚识别宏参数。2a 使用句点分隔，2b 使用空格分隔</li><li><code>append_front_2c_bad</code> - 当参数后直接跟下划线等字符时，编译器无法确定参数的边界</li><li><code>append_front_2c_good</code> - 通过双反引号明确分隔参数和后续字符，确保正确替换</li><li><code>append_middle/append_end</code> - 展示了在字符串中间和末尾使用双反引号的效果</li><li><code>append_front_3</code> - 在天然分隔符处使用双反引号不会产生影响</li></ul><h4 id="3-转义双引号操作符-“"><a href="#3-转义双引号操作符-“" class="headerlink" title="3. 转义双引号操作符 `\`“"></a>3. 转义双引号操作符 `\`“</h4><p>`\`“ - 当宏被扩展时，会生成文字双引号 &quot;。如果需要在宏展开后的文本中包含双引号字符，请使用此操作符。</p><p><strong>示例 1.3</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Example 1.3 */</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> complex_string(ARG1, ARG2) \</span></span><br><span class="line">    `<span class="string">&quot;This `\`&quot;</span>Blue``ARG1`\`<span class="string">&quot; is Really `\`&quot;</span>ARG2`\`<span class="string">&quot;`&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">program</span> <span class="keyword">automatic</span> test;</span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        <span class="built_in">$display</span>(`complex_string(Beast, Black));</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endprogram</span>: test</span><br></pre></td></tr></table></figure><p><strong>运行结果</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># This &quot;BlueBeast&quot; is Really &quot;Black&quot;</span><br></pre></td></tr></table></figure><p>通过上述示例可以看出，复杂的字符串拼接和转义可以通过这些操作符灵活实现。</p><h3 id="补充说明"><a href="#补充说明" class="headerlink" title="补充说明"></a>补充说明</h3><ul><li>宏可以嵌套调用其他宏</li><li>允许在宏中使用注释</li><li>宏定义中可以使用条件编译指令（ifdef 等）</li></ul><h2 id="参数传递技巧"><a href="#参数传递技巧" class="headerlink" title="参数传递技巧"></a>参数传递技巧</h2><p>关于宏参数的几个重要特性：</p><ol><li><strong>默认参数值</strong> - 参数可以设置默认值</li><li><strong>可选参数</strong> - 可以通过留空位置跳过参数，即使该参数没有默认值（如示例中的 <code>test2(,,)</code>）</li><li><strong>字符串参数处理</strong> - 需要根据参数在宏文本中的位置来决定是否添加引号</li></ol><p>以 <code>debug1</code> 和 <code>debug2</code> 为例：在 <code>debug1</code> 中，MODNAME 位于引号内，因此调用时不需要加引号；而 <code>debug2</code> 中的 MODNAME 位于引号外，因此需要传入带引号的字符串。</p><p><strong>示例 2</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Example 2 */</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> test1(A) $display(`&quot;1 Color A`&quot;)</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> test2(A=blue, B, C=green) $display(`&quot;3 Colors A, B, C`&quot;)</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> test3(A=str1, B, C=green) \</span></span><br><span class="line">    <span class="keyword">if</span> (A == <span class="string">&quot;orange&quot;</span>)<span class="built_in">$display</span>(<span class="string">&quot;Oooo .. I received an Orange!&quot;</span>); \</span><br><span class="line">    <span class="keyword">else</span> <span class="built_in">$display</span>(`<span class="string">&quot;3 Colors %s, B, C`&quot;</span>, A);</span><br><span class="line"></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> debug1(MODNAME, MSG) \</span></span><br><span class="line">    <span class="built_in">$display</span>(`<span class="string">&quot; ``MODNAME`` &gt;&gt; %s, %0d: %s`&quot;</span>, <span class="variable constant_">`__FILE__</span>, <span class="variable constant_">`__LINE__</span>, MSG)</span><br><span class="line"><span class="meta">`<span class="keyword">define</span> debug2(MODNAME, MSG) \</span></span><br><span class="line">    <span class="built_in">$display</span>(`<span class="string">&quot;%s &gt;&gt; %s, %0d: %s`&quot;</span>, MODNAME, <span class="variable constant_">`__FILE__</span>, <span class="variable constant_">`__LINE__</span>, MSG)</span><br><span class="line"></span><br><span class="line"><span class="keyword">program</span> <span class="keyword">automatic</span> test;</span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        <span class="keyword">string</span> str1, str2;</span><br><span class="line">        str1 = <span class="string">&quot;gray&quot;</span>;</span><br><span class="line">        str2 = <span class="string">&quot;orange&quot;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// No args provided even without default value</span></span><br><span class="line">        `test1();</span><br><span class="line">        `test2(,,);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Passing some args</span></span><br><span class="line">        `test1(black);</span><br><span class="line">        `test2(,pink,);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Passing a var (str1, str2) as an arg</span></span><br><span class="line">        `test3(str1,mistygreen,babypink);</span><br><span class="line">        `test3(str2,mistygreen,babypink);</span><br><span class="line"></span><br><span class="line">        `debug1(<span class="keyword">program</span>-block, <span class="string">&quot;this is a debug message&quot;</span>);</span><br><span class="line">        `debug2(<span class="string">&quot;program-block&quot;</span>, <span class="string">&quot;this is a debug message&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* The following will result in an Error</span></span><br><span class="line"><span class="comment">        * `test2(); // no args provided</span></span><br><span class="line"><span class="comment">        * `test2(,); // insufficient args provided</span></span><br><span class="line"><span class="comment">        *</span></span><br><span class="line"><span class="comment">        * // arg1 is used as a var in an if statement,</span></span><br><span class="line"><span class="comment">        * // This will compile fail because the macro</span></span><br><span class="line"><span class="comment">        * // will expand to *if ( == &quot;orange&quot;)*</span></span><br><span class="line"><span class="comment">        * `test(, blue, pink)</span></span><br><span class="line"><span class="comment">        */</span></span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endprogram</span>: test</span><br></pre></td></tr></table></figure><p><strong>运行结果</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 1 Color</span><br><span class="line"># 3 Colors blue, , green</span><br><span class="line"># 1 Color black</span><br><span class="line"># 3 Colors blue, pink, green</span><br><span class="line"># 3 Colors gray, mistygreen, babypink</span><br><span class="line"># Oooo .. I received an Orange!</span><br><span class="line">#  program-block &gt;&gt; macros2.sv, 31: this is a debug message</span><br><span class="line"># program-block &gt;&gt; macros2.sv, 32: this is a debug message</span><br></pre></td></tr></table></figure><h2 id="编码规范建议"><a href="#编码规范建议" class="headerlink" title="编码规范建议"></a>编码规范建议</h2><p>为了确保团队开发的一致性，建议遵循 UVM 的宏命名规范。通过分析 UVM 库源代码，可以总结出以下规则：</p><ol><li><strong>函数&#x2F;任务宏</strong> - 使用 UPPERCASE 宏名称和 lowercase 参数名称</li><li><strong>类&#x2F;代码片段宏</strong> - 使用 lowercase 宏名称和 UPPERCASE 参数名称  </li><li><strong>单词分隔</strong> - 使用下划线分隔，避免使用驼峰命名</li></ol><p>这些规范经过大量实践验证，有助于提升代码的可读性和维护性。</p><h2 id="UVM-宏实践示例"><a href="#UVM-宏实践示例" class="headerlink" title="UVM 宏实践示例"></a>UVM 宏实践示例</h2><p>以下是从 UVM 库中精选的宏定义，展示了标准的编码规范和实际应用场景：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//&gt; src/base/uvm_phase.svh</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> UVM_PH_TRACE(ID,MSG,PH,VERB) \</span></span><br><span class="line">   `uvm_info(ID, &#123;<span class="built_in">$sformatf</span>(<span class="string">&quot;Phase &#x27;%0s&#x27; (id=%0d) &quot;</span>, \</span><br><span class="line">       PH<span class="variable">.get_full_name</span>(), PH<span class="variable">.get_inst_id</span>()),MSG&#125;, VERB);</span><br><span class="line"></span><br><span class="line"><span class="comment">//&gt; src/macros/uvm_tlm_defines.svh</span></span><br><span class="line"><span class="comment">// Check out the MacroStyleGuide in use here</span></span><br><span class="line"><span class="comment">// [ 1.] If the Macro defines a function or a task,</span></span><br><span class="line"><span class="comment">// use UPPERCASE for macro name and lower case for args    </span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> UVM_BLOCKING_TRANSPORT_IMP_SFX(SFX, imp, REQ, RSP, req_arg, rsp_arg) \</span></span><br><span class="line">  <span class="keyword">task</span> transport( <span class="keyword">input</span> REQ req_arg, <span class="keyword">output</span> RSP rsp_arg); \</span><br><span class="line">    imp<span class="variable">.transport</span>``SFX(req_arg, rsp_arg); \</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// [ 2a.] For everything else (i.e., if Macro defines </span></span><br><span class="line"><span class="comment">// a snippet of code, class or a convenience definition),</span></span><br><span class="line"><span class="comment">// use lowercase with UPPERCASE args</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_analysis_imp_decl(SFX) \</span></span><br><span class="line">    <span class="keyword">class</span> uvm_analysis_imp``SFX <span class="variable">#(type T=int, type IMP=int)</span> \</span><br><span class="line">      <span class="keyword">extends</span> uvm_port_base <span class="variable">#(uvm_tlm_if_base #(T,T))</span>; \</span><br><span class="line">      `UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,`<span class="string">&quot;uvm_analysis_imp``SFX`&quot;</span>,IMP) \</span><br><span class="line">      <span class="keyword">function</span> <span class="keyword">void</span> write( <span class="keyword">input</span> T t); \</span><br><span class="line">        m_imp<span class="variable">.write</span>``SFX( t); \</span><br><span class="line">      <span class="keyword">endfunction</span> \</span><br><span class="line">      \</span><br><span class="line">    <span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// [ 2b.] Examples of lowercase+uppercase with snippets</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_error(ID, MSG) \</span></span><br><span class="line">   <span class="keyword">begin</span> \</span><br><span class="line">     <span class="keyword">if</span> (uvm_report_enabled(UVM_NONE,UVM_ERROR,ID)) \</span><br><span class="line">       uvm_report_error (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, <span class="string">&quot;&quot;</span>, <span class="number">1</span>); \</span><br><span class="line">   <span class="keyword">end</span></span><br><span class="line"><span class="comment">// [ 3.] Separate words with underscores, don&#x27;t use camelCase</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_non_blocking_transport_imp_decl(SFX) \</span></span><br><span class="line">    `uvm_nonblocking_transport_imp_decl(SFX)</span><br><span class="line"></span><br><span class="line"><span class="comment">//&gt; src/macros/uvm_sequence_defines.svh</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_do(SEQ_OR_ITEM) \</span></span><br><span class="line">  `uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -<span class="number">1</span>, &#123;&#125;)</span><br><span class="line"></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS) \</span></span><br><span class="line">  `uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -<span class="number">1</span>, CONSTRAINTS)</span><br><span class="line"></span><br><span class="line"> <span class="meta">`<span class="keyword">define</span> uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) \</span></span><br><span class="line">  <span class="keyword">begin</span> \</span><br><span class="line">  uvm_sequence_base __seq; \</span><br><span class="line">  `uvm_create_on(SEQ_OR_ITEM, SEQR) \</span><br><span class="line">  <span class="keyword">if</span> (!<span class="built_in">$cast</span>(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM, PRIORITY);\</span><br><span class="line">  <span class="keyword">if</span> ((__seq == <span class="literal">null</span> || !__seq<span class="variable">.do_not_randomize</span>) &amp;&amp; !SEQ_OR_ITEM<span class="variable">.randomize</span>() <span class="keyword">with</span> CONSTRAINTS ) <span class="keyword">begin</span> \</span><br><span class="line">    `uvm_warning(<span class="string">&quot;RNDFLD&quot;</span>, <span class="string">&quot;Randomization failed in uvm_do_with action&quot;</span>) \</span><br><span class="line">  <span class="keyword">end</span>\</span><br><span class="line">  <span class="keyword">if</span> (!<span class="built_in">$cast</span>(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM, PRIORITY); \</span><br><span class="line">  <span class="keyword">else</span> __seq<span class="variable">.start</span>(SEQR, <span class="keyword">this</span>, PRIORITY, <span class="number">0</span>); \</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_create_on(SEQ_OR_ITEM, SEQR) \</span></span><br><span class="line">  <span class="keyword">begin</span> \</span><br><span class="line">  uvm_object_wrapper w_; \</span><br><span class="line">  w_ = SEQ_OR_ITEM<span class="variable">.get_type</span>(); \</span><br><span class="line">  <span class="built_in">$cast</span>(SEQ_OR_ITEM , create_item(w_, SEQR, `<span class="string">&quot;SEQ_OR_ITEM`&quot;</span>));\</span><br><span class="line">  <span class="keyword">end</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;介绍&quot;&gt;&lt;a href=&quot;#介绍&quot; class=&quot;headerlink&quot; title=&quot;介绍&quot;&gt;&lt;/a&gt;介绍&lt;/h2&gt;&lt;h3 id=&quot;什么是宏？&quot;&gt;&lt;a href=&quot;#什么是宏？&quot; class=&quot;headerlink&quot; title=&quot;什么是宏？&quot;&gt;&lt;/a&gt;什么是宏</summary>
      
    
    
    
    <category term="SystemVerilog" scheme="https://sqlmaps.com/categories/SystemVerilog/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="SystemVerilog" scheme="https://sqlmaps.com/tags/SystemVerilog/"/>
    
  </entry>
  
  <entry>
    <title>UVM Checklist</title>
    <link href="https://sqlmaps.com/2026/08/01/UVM-Checklist/"/>
    <id>https://sqlmaps.com/2026/08/01/UVM-Checklist/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-基于-UVM-的-TB-架构"><a href="#1-基于-UVM-的-TB-架构" class="headerlink" title="1. 基于 UVM 的 TB 架构"></a>1. 基于 UVM 的 TB 架构</h2><ul><li>顶层模块 -&gt; Test -&gt; env -&gt; sub_env -&gt; agent -&gt; driver, sequencer, monitor</li><li>为每个测试用例创建 Testbench</li><li>测试用例代码保存在case库（xx_test_lib.sv）文件中（类似于将所有测试定义保存在一个文件中的 package）</li><li>测试库文件被包含在顶层模块中</li><li>UVM TB 中不使用 Program block</li></ul><h2 id="2-在-UVM-中运行测试"><a href="#2-在-UVM-中运行测试" class="headerlink" title="2. 在 UVM 中运行测试"></a>2. 在 UVM 中运行测试</h2><ul><li><code>vsim +novopt work.top +UVM_TESTNAME=测试名称</code></li><li>必须从顶层模块中的 <code>initial block</code> 调用 <code>run_test()</code></li><li>可以通过 <code>run_test(&quot;testname&quot;)</code> 运行测试，但不建议这样做，因为它将 Testbench 绑定到单个测试。</li><li>如果 <code>run_test()</code> 或者 <code>UVM_TESTNAME</code> 的 <code>testname</code> 没有在 UVM factory 中注册，模拟将导致致命错误。</li><li>如果没有在顶层模块中调用 <code>run_test()</code>，则 UVM phase 不会被调用。我们仍然可以调用全局 UVM 方法。</li></ul><h2 id="3-测试运行中的-Phases"><a href="#3-测试运行中的-Phases" class="headerlink" title="3. 测试运行中的 Phases"></a>3. 测试运行中的 Phases</h2><ul><li>build_phase</li><li>config_phase</li><li>end_of_elaboration_phase</li><li>start_of_simulation_phase</li><li>run_phase</li><li>extract</li><li>check</li><li>report</li></ul><h2 id="4-报告信息"><a href="#4-报告信息" class="headerlink" title="4. 报告信息"></a>4. 报告信息</h2><ul><li>使用 <code>+UVM_VERBOSITY</code> 和 <code>+UVM_SEVERITY</code> 来管理报告</li><li><code>UVM_VERBOSITY</code>: 通过模拟命令选项更改所有 UVM 组件的详细级别。</li><li><code>+uvm_set_verbosity</code> 选项有一个特定格式，允许控制详细级别更改适用于哪些阶段，以及在耗时阶段时准确应用的时间。</li><li>示例命令：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sim_cmd +uvm_set_verbosity=组件名称,id,详细级别,阶段名称,可选时间 </span><br><span class="line">sim_cmd +uvm_set_action=组件名称,id,严重性,操作 </span><br><span class="line">sim_cmd +uvm_set_severity=组件名称,id,当前严重性,新的严重性</span><br></pre></td></tr></table></figure><ul><li><p><code>uvm_report_info</code> &#x2F; <code>uvm_report_warning</code> &#x2F; <code>uvm_report_error</code> &#x2F; <code>uvm_report_fatal</code></p></li><li><p><code>uvm_report_info</code> 函数示例：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtual function void uvm_report_info(string id, string message, int verbosity = UVM_MEDIUM, string filename = &quot;&quot;, int line=0)</span><br></pre></td></tr></table></figure></li><li><p>序列项和序列使用与其关联的 sequencer 进行报告。如果未设置 sequencer，则将使用全局 reporter。</p></li><li><p><code>uvm_info</code> &#x2F; <code>uvm_warning</code> &#x2F; <code>uvm_error</code> &#x2F; <code>uvm_fatal</code> 宏：</p></li><li><p><code>uvm_info(ID, MSG, VERBOSITY)</code>：当 VERBOSITY 低于配置的 reporter 详细级别时，调用 <code>uvm_report_info</code>。</p></li><li><p><code>uvm_warning(ID, MSG)</code> &#x2F; <code>uvm_error(ID, MSG)</code> &#x2F; <code>uvm_fatal(ID, MSG)</code>：</p><ul><li>这些宏将使用 <code>UVM_NONE</code> 详细级别，因此无法通过设置 reporter 详细级别禁用它们，但可以通过设置消息的操作来关闭它们。</li></ul></li><li><p><code>UVM_VERBOSITY</code> 等级：</p><ul><li><code>UVM_NONE</code> &#x2F; <code>UVM_LOW</code> &#x2F; <code>UVM_MEDIUM</code> &#x2F; <code>UVM_HIGH</code> &#x2F; <code>UVM_FULL</code></li><li><code>UVM_NONE</code>: 报告始终打印，无法通过详细级别禁用。</li><li><code>UVM_LOW</code>: 报告仅在详细级别设置为 <code>UVM_LOW</code> 或以上（如 <code>UVM_MEDIUM/HIGH/FULL</code>）时发出。</li></ul></li><li><p><code>UVM_SEVERITY</code> 等级：</p><ul><li><code>UVM_INFO</code> &#x2F; <code>UVM_WARNING</code> &#x2F; <code>UVM_ERROR</code> &#x2F; <code>UVM_FATAL</code></li><li><code>UVM_FATAL</code>: 模拟在此级别使用 <code>$finish</code> 退出。</li></ul></li></ul><h2 id="5-TB-组件编码"><a href="#5-TB-组件编码" class="headerlink" title="5. TB 组件编码"></a>5. TB 组件编码</h2><h3 id="i-Driver"><a href="#i-Driver" class="headerlink" title="i. Driver"></a>i. Driver</h3><ul><li>从 <code>uvm_driver#(REQ, RSP)</code> 继承</li><li>实例化虚拟接口</li><li>声明配置变量，以提供从测试中更新组件行为的接口</li><li>使用 <code>uvm_component_utils</code> 注册到工厂</li><li>使用 <code>uvm_config_db#(virtual ubus_if)::get(this, &quot;&quot;, &quot;vif&quot;, vif)</code> 获取虚拟接口句柄</li><li>在 <code>run_phase</code> 中实现驱动功能</li><li>填写 id 信息后，将 <code>rsp</code> 返回给序列：<code>rsp.set_id_info(req)</code></li></ul><h3 id="ii-Sequencer"><a href="#ii-Sequencer" class="headerlink" title="ii. Sequencer"></a>ii. Sequencer</h3><ul><li>从 <code>uvm_sequencer#(REQ, RSP)</code> 继承</li><li>使用 <code>uvm_component_utils</code> 注册到工厂</li><li>也可以使用 <code>uvm_sequencer#(REQ, RSP)</code> 的 typedef 来定义 sequencer</li><li><code>uvm_sequencer_utils</code> 宏用于为 sequencer 提供自动化宏。</li></ul><h3 id="iii-Monitor"><a href="#iii-Monitor" class="headerlink" title="iii. Monitor"></a>iii. Monitor</h3><ul><li>从 <code>uvm_monitor</code> 继承（注意：没有参数）</li><li>使用 <code>uvm_analysis_port#(Tx_name)</code> 实例化分析端口</li><li>声明任何影响监控器行为的配置变量，并将这些变量注册到工厂</li><li>使用 <code>ap.write(tx)</code> 将收集到的事务传递给连接的分析端口。</li></ul><h2 id="6-配置对象"><a href="#6-配置对象" class="headerlink" title="6. 配置对象"></a>6. 配置对象</h2><ul><li>通用容器类，用于保存所有与环境相关的配置变量和接口句柄。</li></ul><h2 id="7-结束测试用例运行"><a href="#7-结束测试用例运行" class="headerlink" title="7. 结束测试用例运行"></a>7. 结束测试用例运行</h2><ul><li>使用 <code>global_stop_request()</code> 结束测试。在测试的 <code>run_phase</code> 中调用，测试运行时间结束后调用。<code>+UVM_USE_OVM_RUN_SEMANTIC</code> 应用于使 <code>global_stop_request()</code> 在 UVM 中生效。</li><li><code>raise_objection</code> 和 <code>drop_objection</code> 是终止测试的首选方式。所有 objections 被移除时会隐式调用 <code>global_stop_request</code>。</li><li>任何 <code>raise_objection</code> 都会使 <code>global_stop_request</code> 无效。</li></ul><h2 id="8-在整个-TB-层次结构中传递接口、配置对象"><a href="#8-在整个-TB-层次结构中传递接口、配置对象" class="headerlink" title="8. 在整个 TB 层次结构中传递接口、配置对象"></a>8. 在整个 TB 层次结构中传递接口、配置对象</h2><ul><li>设置虚拟接口句柄：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(virtual ubus_if)::set(null,&quot;ubus_example_tb0.*&quot;, &quot;vif&quot;,vif)</span>;</span><br></pre></td></tr></table></figure><h2 id="9-注册组件到工厂"><a href="#9-注册组件到工厂" class="headerlink" title="9. 注册组件到工厂"></a>9. 注册组件到工厂</h2><ul><li>创建 type_id，包括 <code>get</code>, <code>get_type</code>, <code>create</code> 方法</li><li>Type_id 示例：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(virtual ubus_if)::set(null,&quot;ubus_example_tb0.*&quot;, &quot;vif&quot;,vif)</span>;</span><br></pre></td></tr></table></figure><h2 id="10-注册对象到工厂"><a href="#10-注册对象到工厂" class="headerlink" title="10. 注册对象到工厂"></a>10. 注册对象到工厂</h2><h2 id="11-根据测试用例需求修改-Testbench-拓扑"><a href="#11-根据测试用例需求修改-Testbench-拓扑" class="headerlink" title="11. 根据测试用例需求修改 Testbench 拓扑"></a>11. 根据测试用例需求修改 Testbench 拓扑</h2><ul><li><code>set_inst_override</code></li><li><code>set_type_override</code></li><li><code>uvm_config_db</code></li><li><code>uvm_resource_db</code></li></ul><h2 id="12-TLM1-0-中的不同类型端口"><a href="#12-TLM1-0-中的不同类型端口" class="headerlink" title="12. TLM1.0 中的不同类型端口"></a>12. TLM1.0 中的不同类型端口</h2><p>注：TLM 也就是：使用函数的调用在compont通信 ｜&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;》 创建一个 block或者component 之前的通信。 亦或者是 一个component中声明的函数 可以被另一个组件调用。理论上讲，没有什么 可以阻止driver 从sequencer 调用 get 这个task。 但是 这让 driver和 sequencer 产生依赖关系，并且还使得 代码难以维护。因此，在UVM中，通过所谓ports 和exports间接连接。（exports 是已从export 中借出（borrow），看看是否在UVM中借出？？（systemc是如此））。此外 driver通过ports（ports是连接到sequencer的 exports） 调用task，VS.driver直接调用 get task。  exports作用是什么？是申明某一个componet，准备提供一个特定task （Provides the get() )）或者function； ports (  Requires a get)) 。准确的说，就是sequencer 提供port 所声明的get 任务的实现。ports是 某个组件 需要的 一项特定task是可用的，因为他要这样调用它。在sequence item 的pool port讲：我们的我们的 driver 准备调用 get function。， 在driver 实例化sequencer，当我们在顶层 讲 port 连接到export出口。</p><p>注：从sequencer 发出的不是 对get 任务的调用，而是 反应正在 输出的事实 或者 是 提供 一个获取任务。所以 driver 就能够 调用 它。</p><p>注：交易 和 任务 是从 左到右。 但是 get 任务本身是从 右到左。</p><p> <img src="https://img.sqlmaps.com/file/1788701636918_ext_3d3c755f26.png" alt="image"></p><p><img src="https://img.sqlmaps.com/file/1788701808984_ext_e5199b3d00.png" alt="image"></p><p><img src="https://img.sqlmaps.com/file/1788701800807_ext_d603ed0713.png" alt="image"></p><p><img src="https://img.sqlmaps.com/file/1788701568252_ext_0e83d68c3a.png" alt="image"></p><p>典型code：注意：analysis_port 是不支持工厂机制。</p><p><img src="https://img.sqlmaps.com/file/1788701590800_ext_1d6d802f3f.png" alt="image"></p><p><img src="https://img.sqlmaps.com/file/1788701742595_ext_a9dc3530a8.png" alt="image"></p><ol><li>port &#x2F; export &#x2F; fifo</li><li>TLM1.0 通信的不同模型：</li></ol><ul><li><p>Push 模型</p></li><li><p>Pull 模型</p></li><li><p>FIFO 模型</p></li><li><p>Analysis 模型 1:N。  export port是 1:1</p><p>注：put 通常 用于发送transcations，是一个阻塞的方法 （放下 才能put第二个。也就是 知道 transaction的 接收方reciver  已经准备好下一次 调用put） （trans 端到端到连接 是不会覆盖的）</p><p>注：get 通常 用于接受transcations，是一个阻塞的方法 （也就是 知道 transaction 发送侧 已经准备就绪 ， 已经准备好下一笔 数据） （trans 端到端到连接 是不会覆盖的）</p></li></ul><p>port 向上连接。export 传递 组件内部。</p><p><img src="https://img.sqlmaps.com/file/1788701615485_ext_32c743293e.png" alt="image"></p><p>uvm_analysis_port是 广播。可以连接到 不同 subscriber</p><p><img src="https://img.sqlmaps.com/file/1788701679157_ext_533dac51df.png" alt="image"></p><p>功能覆盖率 必须是t</p><p><img src="https://img.sqlmaps.com/file/1788701670182_ext_5215262b03.png" alt="image"></p><p>TOP ENV 实际有 agent 和 coverage</p><p><img src="https://img.sqlmaps.com/file/1788701830395_ext_f1fb78b3a0.png" alt="image"></p><p>subscriber class 是&#x3D;component类+ analysis_imp（必须有weite方法）</p><p><img src="https://img.sqlmaps.com/file/1788701761518_ext_b5e06ef4b4.png" alt="image"></p><p>这里 不需要 m_item 去new；可以访问 t；虽然不能修改。</p><p>问题1:处理 multiple incoming （）多个传入的数据流。</p><p>问题2:存储 trans 之后 分析。</p><p>参考模型： 往往需要处理多个数据事物。 每一个进入的 transaction 的数据流 需要与之 对应的 write 。它会处理接受分析的transaction 。（SV 不支持函数重载—- 咋处理 。 那就意味着 在一个class 中不能有多个 同名的方法 咋办—-使用 uvm_analysis_imp_decl）</p><p><img src="https://img.sqlmaps.com/file/1788701631565_ext_3b80cebac9.png" alt="image"></p><p>注意：ref 一般不能 使用 uvm scber 类；主要是 suber类；只有一个单一的imp分析 交易的流。</p><p>用户不想直接处理接受到的交易 咋办？？？？ （FIFO存起来）</p><p>那就用compont类； 将数据转发。到 fifo。。 这些都没有注册到工厂机制；</p><p><img src="https://img.sqlmaps.com/file/1788701701803_ext_71976e65d2.png" alt="image"></p><ol start="3"><li>可能的port连接：</li></ol><ul><li>port - export</li><li>export-export</li><li>Push 模型</li><li>Pull 模型</li><li>FIFO 模型</li><li>Analysis 模型</li></ul><h2 id="13-TLM2-0-中的不同-sockets-类型"><a href="#13-TLM2-0-中的不同-sockets-类型" class="headerlink" title="13. TLM2.0 中的不同 sockets 类型"></a>13. TLM2.0 中的不同 sockets 类型</h2><ol><li>sockets</li><li>block transport</li><li>non block transport</li><li>跟踪事务执行的时间和阶段</li></ol><h2 id="14-打印-Testbench-拓扑"><a href="#14-打印-Testbench-拓扑" class="headerlink" title="14. 打印 Testbench 拓扑"></a>14. 打印 Testbench 拓扑</h2><ul><li>支持不同格式的打印（table, tree, line）</li></ul><h2 id="15-Scoreboard-实现"><a href="#15-Scoreboard-实现" class="headerlink" title="15. Scoreboard 实现"></a>15. Scoreboard 实现</h2><ol><li>具有多个监控器连接的 Scoreboard</li></ol><ul><li>uvm_analysis_port_decl宏，用于创建多个write_*方法</li><li>基于 uvm _ analysis _ export &amp; uvm _ tlm _ analysis _ fifo 的实现</li></ul><h2 id="16-创建通用资源池"><a href="#16-创建通用资源池" class="headerlink" title="16. 创建通用资源池"></a>16. 创建通用资源池</h2><ul><li><code>uvm_pool</code></li><li><code>uvm_resources</code></li></ul><h2 id="17-串行通信协议的-PKT-数据项编码"><a href="#17-串行通信协议的-PKT-数据项编码" class="headerlink" title="17. 串行通信协议的 PKT 数据项编码"></a>17. 串行通信协议的 PKT 数据项编码</h2><ul><li>使用旋钮的概念生成特定于每个测试的多个有趣的场景</li></ul><h2 id="18-片上通信协议的事务数据项编码"><a href="#18-片上通信协议的事务数据项编码" class="headerlink" title="18. 片上通信协议的事务数据项编码"></a>18. 片上通信协议的事务数据项编码</h2><ul><li>使用旋钮的概念生成特定于每个测试的多个有趣的场景</li></ul><h2 id="19-UVM-中的标准连接类型"><a href="#19-UVM-中的标准连接类型" class="headerlink" title="19. UVM 中的标准连接类型"></a>19. UVM 中的标准连接类型</h2><h2 id="20-Sequence-coding"><a href="#20-Sequence-coding" class="headerlink" title="20. Sequence coding"></a>20. Sequence coding</h2><h2 id="21-虚拟序列编码"><a href="#21-虚拟序列编码" class="headerlink" title="21. 虚拟序列编码"></a>21. 虚拟序列编码</h2><h2 id="22-虚拟-sequencer"><a href="#22-虚拟-sequencer" class="headerlink" title="22. 虚拟 sequencer"></a>22. 虚拟 sequencer</h2><h2 id="23-执行序列"><a href="#23-执行序列" class="headerlink" title="23. 执行序列"></a>23. 执行序列</h2><h2 id="24-执行事务项"><a href="#24-执行事务项" class="headerlink" title="24. 执行事务项"></a>24. 执行事务项</h2><h2 id="25-使用默认序列将测试用例链接到序列"><a href="#25-使用默认序列将测试用例链接到序列" class="headerlink" title="25. 使用默认序列将测试用例链接到序列"></a>25. 使用默认序列将测试用例链接到序列</h2><h2 id="26-使用-uvm-objection-跟踪-Testbench-执行进度"><a href="#26-使用-uvm-objection-跟踪-Testbench-执行进度" class="headerlink" title="26. 使用 uvm_objection 跟踪 Testbench 执行进度"></a>26. 使用 uvm_objection 跟踪 Testbench 执行进度</h2><h2 id="27-创建序列库"><a href="#27-创建序列库" class="headerlink" title="27. 创建序列库"></a>27. 创建序列库</h2><h2 id="28-更新组件定义"><a href="#28-更新组件定义" class="headerlink" title="28. 更新组件定义"></a>28. 更新组件定义</h2><h2 id="29-使用-UVM-编写可重用的验证环境"><a href="#29-使用-UVM-编写可重用的验证环境" class="headerlink" title="29. 使用 UVM 编写可重用的验证环境"></a>29. 使用 UVM 编写可重用的验证环境</h2><h2 id="30-Testbench-中的寄存器层"><a href="#30-Testbench-中的寄存器层" class="headerlink" title="30. Testbench 中的寄存器层"></a>30. Testbench 中的寄存器层</h2><h2 id="31-工厂类"><a href="#31-工厂类" class="headerlink" title="31. 工厂类"></a>31. 工厂类</h2><h2 id="32-AHB-UVC-开发概念"><a href="#32-AHB-UVC-开发概念" class="headerlink" title="32. AHB UVC 开发概念"></a>32. AHB UVC 开发概念</h2><h2 id="33-AHB-互连验证"><a href="#33-AHB-互连验证" class="headerlink" title="33. AHB 互连验证"></a>33. AHB 互连验证</h2><h2 id="34-USB-2-0-核心验证"><a href="#34-USB-2-0-核心验证" class="headerlink" title="34. USB 2.0 核心验证"></a>34. USB 2.0 核心验证</h2><h2 id="35-uvm-root"><a href="#35-uvm-root" class="headerlink" title="35. uvm_root"></a>35. uvm_root</h2><ul><li>作为所有 UVM 组件的隐式顶层和 phase 控制器。用户无需直接实例化 <code>uvm_root</code>，UVM 会自动创建一个 用户可以通过全局变量uvm_top访问的 <code>uvm_root</code> 单实例。</li></ul><h2 id="36-uvm-report-info-uvm-report-warning-uvm-report-error-uvm-report-fatal-调用示例"><a href="#36-uvm-report-info-uvm-report-warning-uvm-report-error-uvm-report-fatal-调用示例" class="headerlink" title="36. uvm_report_info &#x2F; uvm_report_warning &#x2F; uvm_report_error &#x2F; uvm_report_fatal 调用示例"></a>36. <code>uvm_report_info</code> &#x2F; <code>uvm_report_warning</code> &#x2F; <code>uvm_report_error</code> &#x2F; <code>uvm_report_fatal</code> 调用示例</h2>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-基于-UVM-的-TB-架构&quot;&gt;&lt;a href=&quot;#1-基于-UVM-的-TB-架构&quot; class=&quot;headerlink&quot; title=&quot;1. 基于 UVM 的 TB 架构&quot;&gt;&lt;/a&gt;1. 基于 UVM 的 TB 架构&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;顶层模块 -</summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>UVM Monitor 与 Backpressure 控制</title>
    <link href="https://sqlmaps.com/2026/08/01/UVM-Monitor%E4%B8%8EBackpressure%E6%8E%A7%E5%88%B6/"/>
    <id>https://sqlmaps.com/2026/08/01/UVM-Monitor%E4%B8%8EBackpressure%E6%8E%A7%E5%88%B6/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>本文档介绍如何在UVM验证环境中正确实现monitor采集DUT输出，以及如何通过分类型backpressure机制控制数据包流。核心特性是<strong>数据包级反压控制</strong>，确保数据包传输的完整性和可靠性。</p><hr><h2 id="第一部分：基础设计原则"><a href="#第一部分：基础设计原则" class="headerlink" title="第一部分：基础设计原则"></a>第一部分：基础设计原则</h2><h3 id="核心原则"><a href="#核心原则" class="headerlink" title="核心原则"></a>核心原则</h3><ul><li><strong>只采样，不驱动</strong> - Monitor绝不能影响DUT行为</li><li><strong>使用正确的信号方向</strong> - input采样，output驱动</li><li><strong>时序同步</strong> - 使用clocking block确保时序正确</li><li><strong>分类型精细控制</strong> - 根据数据包类型实现独立流控</li><li><strong>数据包完整性</strong> - 正确处理SOP&#x2F;EOP边界和错误信号</li><li><strong>智能头部解析</strong> - 从高128字节头部提取类型和长度信息</li><li><strong>数据包级反压</strong> - backpressure只在完整数据包边界生效，避免中途中断</li></ul><h3 id="🎯-数据包级反压核心优势"><a href="#🎯-数据包级反压核心优势" class="headerlink" title="🎯 数据包级反压核心优势"></a>🎯 数据包级反压核心优势</h3><ol><li><strong>传输完整性</strong>: 数据包传输过程中不被反压打断</li><li><strong>边界对齐</strong>: 严格保持SOP&#x2F;EOP边界完整性</li><li><strong>状态一致</strong>: 避免传输状态机错乱</li><li><strong>性能提升</strong>: DUT能完整处理数据包，减少重传开销</li></ol><hr><h2 id="第二部分：Interface与Transaction设计"><a href="#第二部分：Interface与Transaction设计" class="headerlink" title="第二部分：Interface与Transaction设计"></a>第二部分：Interface与Transaction设计</h2><h3 id="1-优化的Interface定义"><a href="#1-优化的Interface定义" class="headerlink" title="1. 优化的Interface定义"></a>1. 优化的Interface定义</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> my_interface(<span class="keyword">input</span> clk, <span class="keyword">input</span> rst_n);</span><br><span class="line">    <span class="comment">// === DUT输出信号（Monitor采样）- 2048位数据包格式 ===</span></span><br><span class="line">    <span class="keyword">logic</span> [<span class="number">2047</span>:<span class="number">0</span>] data_out;         <span class="comment">// 2048位数据 (256字节)</span></span><br><span class="line">    <span class="keyword">logic</span>          sop_out;          <span class="comment">// 数据包开始标志</span></span><br><span class="line">    <span class="keyword">logic</span>          eop_out;          <span class="comment">// 数据包结束标志</span></span><br><span class="line">    <span class="keyword">logic</span>          vld_out;          <span class="comment">// 数据有效标志</span></span><br><span class="line">    <span class="keyword">logic</span>          err_out;          <span class="comment">// 错误标志</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 分类型反压信号 - 数据包级控制 ===</span></span><br><span class="line">    <span class="keyword">logic</span>          type0_backpressure; <span class="comment">// 控制数据类型0的数据包流</span></span><br><span class="line">    <span class="keyword">logic</span>          type1_backpressure; <span class="comment">// 控制数据类型1的数据包流  </span></span><br><span class="line">    <span class="keyword">logic</span>          type2_backpressure; <span class="comment">// 控制数据类型2的数据包流</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === DUT输入信号（Driver驱动）- 2048位数据包格式 ===</span></span><br><span class="line">    <span class="keyword">logic</span> [<span class="number">2047</span>:<span class="number">0</span>] data_in;          <span class="comment">// 2048位数据 (256字节)</span></span><br><span class="line">    <span class="keyword">logic</span>          sop_in;           <span class="comment">// 数据包开始标志</span></span><br><span class="line">    <span class="keyword">logic</span>          eop_in;           <span class="comment">// 数据包结束标志</span></span><br><span class="line">    <span class="keyword">logic</span>          vld_in;           <span class="comment">// 数据有效标志</span></span><br><span class="line">    <span class="keyword">logic</span>          err_in;           <span class="comment">// 错误标志</span></span><br><span class="line">    <span class="keyword">logic</span>          rdy_in;           <span class="comment">// DUT准备接收信号（可选）</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === Monitor clocking block - 严格只读 ===</span></span><br><span class="line">    <span class="keyword">clocking</span> mon_cb @(<span class="keyword">posedge</span> clk);</span><br><span class="line">        <span class="keyword">input</span> data_out, sop_out, eop_out, vld_out, err_out;</span><br><span class="line">        <span class="keyword">input</span> type0_backpressure, type1_backpressure, type2_backpressure;</span><br><span class="line">    <span class="keyword">endclocking</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === Driver clocking block - 输出+读取反压 ===</span></span><br><span class="line">    <span class="keyword">clocking</span> drv_cb @(<span class="keyword">posedge</span> clk);</span><br><span class="line">        <span class="keyword">output</span> data_in, sop_in, eop_in, vld_in, err_in;</span><br><span class="line">        <span class="keyword">input</span>  type0_backpressure, type1_backpressure, type2_backpressure, rdy_in;</span><br><span class="line">    <span class="keyword">endclocking</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === Modport定义 - 严格访问控制 ===</span></span><br><span class="line">    <span class="keyword">modport</span> monitor(<span class="keyword">clocking</span> mon_cb, <span class="keyword">input</span> clk, rst_n);</span><br><span class="line">    <span class="keyword">modport</span> driver(<span class="keyword">clocking</span> drv_cb, <span class="keyword">input</span> clk, rst_n);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 便利函数 - 获取反压状态数组 ===</span></span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">bit</span> [<span class="number">2</span>:<span class="number">0</span>] get_backpressure_status();</span><br><span class="line">        <span class="keyword">return</span> &#123;type2_backpressure, type1_backpressure, type0_backpressure&#125;;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 便利函数 - 检查特定类型反压 ===</span></span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">bit</span> is_type_backpressure_active(<span class="keyword">int</span> data_type);</span><br><span class="line">        <span class="keyword">case</span> (data_type)</span><br><span class="line">            <span class="number">0</span>: <span class="keyword">return</span> type0_backpressure;</span><br><span class="line">            <span class="number">1</span>: <span class="keyword">return</span> type1_backpressure;</span><br><span class="line">            <span class="number">2</span>: <span class="keyword">return</span> type2_backpressure;</span><br><span class="line">            <span class="keyword">default</span>: <span class="keyword">return</span> <span class="number">1&#x27;b1</span>; <span class="comment">// 未知类型默认阻塞</span></span><br><span class="line">        <span class="keyword">endcase</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endinterface</span></span><br></pre></td></tr></table></figure><h3 id="2-增强的Transaction类定义"><a href="#2-增强的Transaction类定义" class="headerlink" title="2. 增强的Transaction类定义"></a>2. 增强的Transaction类定义</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// === 反压事务类型定义 ===</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">enum</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] &#123;</span><br><span class="line">    BP_TYPE0 = <span class="number">2&#x27;b00</span>,  <span class="comment">// 类型0反压</span></span><br><span class="line">    BP_TYPE1 = <span class="number">2&#x27;b01</span>,  <span class="comment">// 类型1反压</span></span><br><span class="line">    BP_TYPE2 = <span class="number">2&#x27;b10</span>   <span class="comment">// 类型2反压</span></span><br><span class="line">&#125; bp_type_e;</span><br><span class="line"></span><br><span class="line"><span class="comment">// === 分类型反压事务 ===</span></span><br><span class="line"><span class="keyword">class</span> typed_backpressure_transaction <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">    bp_type_e       bp_type;            <span class="comment">// 反压类型</span></span><br><span class="line">    <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>]       affected_data_type; <span class="comment">// 受影响的数据类型</span></span><br><span class="line">    <span class="keyword">bit</span>             backpressure_active; <span class="comment">// 反压是否激活</span></span><br><span class="line">    <span class="keyword">realtime</span>        start_time;         <span class="comment">// 反压开始时间</span></span><br><span class="line">    <span class="keyword">realtime</span>        end_time;          <span class="comment">// 反压结束时间</span></span><br><span class="line">    <span class="keyword">int</span>             duration_ns;       <span class="comment">// 反压持续时间(ns)</span></span><br><span class="line">    <span class="keyword">bit</span>             packet_interrupted; <span class="comment">// 是否中断了数据包传输</span></span><br><span class="line">    </span><br><span class="line">    `uvm_object_utils_begin(typed_backpressure_transaction)</span><br><span class="line">        `uvm_field_enum(bp_type_e, bp_type, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(affected_data_type, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(backpressure_active, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(duration_ns, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(packet_interrupted, UVM_ALL_ON)</span><br><span class="line">    `uvm_object_utils_end</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;typed_backpressure_transaction&quot;</span>);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">        start_time = <span class="built_in">$realtime</span>;</span><br><span class="line">        packet_interrupted = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 数据包事务 - 支持2048位宽和头部/payload分离</span></span><br><span class="line"><span class="keyword">class</span> my_transaction <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">2047</span>:<span class="number">0</span>] data;          <span class="comment">// 完整2048位数据</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span>          sop;           <span class="comment">// 数据包开始</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span>          eop;           <span class="comment">// 数据包结束</span></span><br><span class="line">    <span class="keyword">bit</span>               vld;           <span class="comment">// 数据有效</span></span><br><span class="line">    <span class="keyword">bit</span>               err;           <span class="comment">// 错误标志</span></span><br><span class="line">    <span class="keyword">realtime</span>          timestamp;</span><br><span class="line">    <span class="keyword">int</span>               packet_id;     <span class="comment">// 数据包ID</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 头部相关字段（仅SOP周期有效）</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] header;        <span class="comment">// 高128字节头部 (data[2047:1024])</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>]    data_type;     <span class="comment">// 从头部提取的数据类型</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">int</span>          payload_length; <span class="comment">// 从头部提取的payload长度（字节）</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// payload相关字段</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] sop_payload;   <span class="comment">// SOP周期的payload部分 (data[1023:0])</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">2047</span>:<span class="number">0</span>] pure_payload;  <span class="comment">// 非SOP周期的纯payload数据</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 约束条件</span></span><br><span class="line">    <span class="keyword">constraint</span> c_data_type &#123; data_type <span class="keyword">inside</span> &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>&#125;; &#125;</span><br><span class="line">    <span class="keyword">constraint</span> c_payload_length &#123; </span><br><span class="line">        payload_length &gt;= <span class="number">0</span>; </span><br><span class="line">        payload_length &lt;= <span class="number">65535</span>;  <span class="comment">// 最大payload长度</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">constraint</span> c_sop_eop &#123; </span><br><span class="line">        sop == <span class="number">1</span> || eop == <span class="number">1</span>;  <span class="comment">// 必须有一个有效周期</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 数据组装约束</span></span><br><span class="line">    <span class="keyword">constraint</span> c_data_assembly &#123;</span><br><span class="line">        <span class="keyword">if</span> (sop) &#123;</span><br><span class="line">            <span class="comment">// SOP周期：高128字节是头部，低128字节是payload</span></span><br><span class="line">            data[<span class="number">2047</span>:<span class="number">1024</span>] == header[<span class="number">1023</span>:<span class="number">0</span>];        <span class="comment">// 头部信息</span></span><br><span class="line">            data[<span class="number">1023</span>:<span class="number">0</span>] == sop_payload[<span class="number">1023</span>:<span class="number">0</span>];      <span class="comment">// SOP的payload部分</span></span><br><span class="line">            <span class="comment">// 从头部提取信息</span></span><br><span class="line">            data_type == extract_type_from_header(header);</span><br><span class="line">            payload_length == extract_length_from_header(header);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 非SOP周期：全部256字节是payload</span></span><br><span class="line">            data == pure_payload;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    `uvm_object_utils_begin(my_transaction)</span><br><span class="line">        `uvm_field_int(data, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(sop, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(eop, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(vld, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(err, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(data_type, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(packet_id, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(payload_length, UVM_ALL_ON)</span><br><span class="line">    `uvm_object_utils_end</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;my_transaction&quot;</span>);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">        timestamp = <span class="built_in">$realtime</span>;</span><br><span class="line">        packet_id = -<span class="number">1</span>;</span><br><span class="line">        payload_length = <span class="number">0</span>;</span><br><span class="line">        data_type = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：获取头部信息</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] get_header();</span><br><span class="line">        <span class="keyword">return</span> sop ? data[<span class="number">2047</span>:<span class="number">1024</span>] : <span class="number">1024&#x27;h0</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：获取当前beat的payload</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] get_beat_payload();</span><br><span class="line">        <span class="keyword">return</span> sop ? data[<span class="number">1023</span>:<span class="number">0</span>] : data[<span class="number">2047</span>:<span class="number">1024</span>];  <span class="comment">// SOP周期取低128字节，非SOP取高128字节</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：从头部提取数据类型</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] extract_type_from_header(<span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] hdr);</span><br><span class="line">        <span class="keyword">return</span> hdr[<span class="number">1</span>:<span class="number">0</span>];  <span class="comment">// 假设类型在头部最低2位</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：从头部提取payload长度</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">int</span> extract_length_from_header(<span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] hdr);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">int</span>&#x27;(hdr[<span class="number">31</span>:<span class="number">2</span>]);  <span class="comment">// 假设长度在头部bit[31:2]</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：提取payload长度（从实际数据）</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">int</span> get_payload_length_from_header();</span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] hdr = get_header();</span><br><span class="line">        <span class="keyword">return</span> extract_length_from_header(hdr);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：提取数据类型（从实际数据）</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] get_data_type_from_header();</span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] hdr = get_header();</span><br><span class="line">        <span class="keyword">return</span> extract_type_from_header(hdr);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 辅助函数：计算当前beat的有效payload字节数</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">int</span> get_valid_payload_bytes(<span class="keyword">int</span> remaining_len);</span><br><span class="line">        <span class="keyword">if</span> (sop) <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// SOP周期：最多128字节payload</span></span><br><span class="line">            <span class="keyword">return</span> (remaining_len &gt; <span class="number">128</span>) ? <span class="number">128</span> : remaining_len;</span><br><span class="line">        <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 非SOP周期：最多256字节payload</span></span><br><span class="line">            <span class="keyword">return</span> (remaining_len &gt; <span class="number">256</span>) ? <span class="number">256</span> : remaining_len;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 增强的辅助函数 ===</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 验证头部完整性</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> validate_header();</span><br><span class="line">        <span class="keyword">if</span> (!sop) <span class="keyword">return</span> <span class="number">1</span>; <span class="comment">// 非SOP周期不需要验证头部</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] hdr = get_header();</span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] extracted_type = extract_type_from_header(hdr);</span><br><span class="line">        <span class="keyword">int</span> extracted_length = extract_length_from_header(hdr);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 验证类型合法性</span></span><br><span class="line">        <span class="keyword">if</span> (extracted_type &gt; <span class="number">2</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_warning(<span class="string">&quot;HEADER_VALIDATION&quot;</span>, </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Invalid data type %0d in header&quot;</span>, extracted_type))</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 验证长度合理性</span></span><br><span class="line">        <span class="keyword">if</span> (extracted_length &lt; <span class="number">0</span> || extracted_length &gt; <span class="number">65535</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_warning(<span class="string">&quot;HEADER_VALIDATION&quot;</span>, </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Invalid payload length %0d in header&quot;</span>, extracted_length))</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 计算预期的beat数量</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">int</span> calculate_expected_beats();</span><br><span class="line">        <span class="keyword">if</span> (payload_length &lt;= <span class="number">128</span>) <span class="keyword">return</span> <span class="number">1</span>; <span class="comment">// 只需SOP beat</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span> + ((payload_length - <span class="number">128</span>) + <span class="number">255</span>) / <span class="number">256</span>; <span class="comment">// SOP + 后续beats</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 数据包级别的事务（完整数据包）</span></span><br><span class="line"><span class="keyword">class</span> packet_transaction <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>]         data_type;</span><br><span class="line">    <span class="keyword">bit</span>                    has_error;</span><br><span class="line">    <span class="keyword">realtime</span>               start_time;</span><br><span class="line">    <span class="keyword">realtime</span>               end_time;</span><br><span class="line">    <span class="keyword">int</span>                    packet_id;</span><br><span class="line">    <span class="keyword">int</span>                    beat_count;           <span class="comment">// 数据包包含的beat数</span></span><br><span class="line">    <span class="keyword">int</span>                    total_payload_length; <span class="comment">// 实际payload总长度</span></span><br><span class="line">    <span class="keyword">int</span>                    expected_payload_length; <span class="comment">// 头部声明的payload长度</span></span><br><span class="line">    my_transaction         beats[$];             <span class="comment">// 组成数据包的所有beat</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 头部信息</span></span><br><span class="line">    <span class="keyword">bit</span> [<span class="number">127</span>:<span class="number">0</span>]            packet_header;        <span class="comment">// 从SOP提取的头部</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// payload数据</span></span><br><span class="line">    <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>]           payload_data[$];      <span class="comment">// 重组的payload数据</span></span><br><span class="line">    </span><br><span class="line">    `uvm_object_utils_begin(packet_transaction)</span><br><span class="line">        `uvm_field_int(data_type, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(has_error, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(packet_id, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(beat_count, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(total_payload_length, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_int(expected_payload_length, UVM_ALL_ON)</span><br><span class="line">        `uvm_field_queue_object(beats, UVM_ALL_ON)</span><br><span class="line">    `uvm_object_utils_end</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;packet_transaction&quot;</span>);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">        packet_id = -<span class="number">1</span>;</span><br><span class="line">        beat_count = <span class="number">0</span>;</span><br><span class="line">        has_error = <span class="number">0</span>;</span><br><span class="line">        total_payload_length = <span class="number">0</span>;</span><br><span class="line">        expected_payload_length = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查payload长度一致性</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> check_payload_length();</span><br><span class="line">        <span class="keyword">return</span> (total_payload_length == expected_payload_length);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><hr><h2 id="第三部分：Monitor实现"><a href="#第三部分：Monitor实现" class="headerlink" title="第三部分：Monitor实现"></a>第三部分：Monitor实现</h2><h3 id="2048位数据感知的Monitor"><a href="#2048位数据感知的Monitor" class="headerlink" title="2048位数据感知的Monitor"></a>2048位数据感知的Monitor</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_monitor <span class="keyword">extends</span> uvm_monitor;</span><br><span class="line">    `uvm_component_utils(my_monitor)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> my_interface<span class="variable">.monitor</span> vif;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Analysis Ports</span></span><br><span class="line">    uvm_analysis_port <span class="variable">#(my_transaction)</span> beat_ap;</span><br><span class="line">    uvm_analysis_port <span class="variable">#(packet_transaction)</span> packet_ap;</span><br><span class="line">    uvm_analysis_port <span class="variable">#(typed_backpressure_transaction)</span> typed_bp_ap;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 数据包重组相关</span></span><br><span class="line">    packet_transaction current_packet;</span><br><span class="line">    <span class="keyword">int</span> packet_id_counter = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">bit</span> packet_in_progress = <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 分类型反压状态跟踪 - 增强为数据包级</span></span><br><span class="line">    <span class="keyword">bit</span> [<span class="number">2</span>:<span class="number">0</span>] previous_bp_states = <span class="number">3&#x27;b000</span>;</span><br><span class="line">    <span class="keyword">realtime</span> bp_start_times[<span class="number">3</span>];</span><br><span class="line">    <span class="keyword">int</span> bp_counts[<span class="number">3</span>] = &#x27;&#123;<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>&#125;;</span><br><span class="line">    <span class="keyword">int</span> bp_interrupted_packets[<span class="number">3</span>] = &#x27;&#123;<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>&#125;; <span class="comment">// 被反压中断的数据包计数</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">        beat_ap = <span class="keyword">new</span>(<span class="string">&quot;beat_ap&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">        packet_ap = <span class="keyword">new</span>(<span class="string">&quot;packet_ap&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">        typed_bp_ap = <span class="keyword">new</span>(<span class="string">&quot;typed_bp_ap&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">        <span class="keyword">if</span>(!uvm_config_db<span class="variable">#(virtual my_interface)::get(this, &quot;&quot;, &quot;vif&quot;, vif))</span></span><br><span class="line">            `uvm_fatal(get_type_name(), <span class="string">&quot;Virtual interface not found!&quot;</span>)</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">        <span class="keyword">wait</span>(vif<span class="variable">.rst_n</span>);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">fork</span></span><br><span class="line">            collect_data_transactions();</span><br><span class="line">            monitor_typed_backpressure();</span><br><span class="line">            report_statistics();</span><br><span class="line">        <span class="keyword">join_none</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 采集数据事务 - 支持2048位数据包格式</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> collect_data_transactions();</span><br><span class="line">        my_transaction tr;</span><br><span class="line">        <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">            @(vif<span class="variable">.mon_cb</span> <span class="keyword">iff</span> vif<span class="variable">.mon_cb</span><span class="variable">.vld_out</span>);  <span class="comment">// 等待有效数据</span></span><br><span class="line">            </span><br><span class="line">            tr = my_transaction::type_id::create(<span class="string">&quot;tr&quot;</span>);</span><br><span class="line">            tr<span class="variable">.data</span> = vif<span class="variable">.mon_cb</span><span class="variable">.data_out</span>;</span><br><span class="line">            tr<span class="variable">.sop</span> = vif<span class="variable">.mon_cb</span><span class="variable">.sop_out</span>;</span><br><span class="line">            tr<span class="variable">.eop</span> = vif<span class="variable">.mon_cb</span><span class="variable">.eop_out</span>;</span><br><span class="line">            tr<span class="variable">.vld</span> = vif<span class="variable">.mon_cb</span><span class="variable">.vld_out</span>;</span><br><span class="line">            tr<span class="variable">.err</span> = vif<span class="variable">.mon_cb</span><span class="variable">.err_out</span>;</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 如果是SOP周期，从头部提取类型和长度信息</span></span><br><span class="line">            <span class="keyword">if</span> (tr<span class="variable">.sop</span>) <span class="keyword">begin</span></span><br><span class="line">                tr<span class="variable">.data_type</span> = tr<span class="variable">.get_data_type_from_header</span>();</span><br><span class="line">                tr<span class="variable">.payload_length</span> = tr<span class="variable">.get_payload_length_from_header</span>();</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 发送Beat级别事务</span></span><br><span class="line">            beat_ap<span class="variable">.write</span>(tr);</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 处理数据包重组</span></span><br><span class="line">            handle_packet_assembly(tr);</span><br><span class="line">            </span><br><span class="line">            `uvm_info(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Collected beat: sop=%0b, eop=%0b, type=%0d, len=%0d, data=0x%0h&quot;</span>, </span><br><span class="line">                tr<span class="variable">.sop</span>, tr<span class="variable">.eop</span>, tr<span class="variable">.data_type</span>, tr<span class="variable">.payload_length</span>, tr<span class="variable">.data</span>[<span class="number">63</span>:<span class="number">0</span>]), UVM_HIGH)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 数据包重组处理</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> handle_packet_assembly(my_transaction beat);</span><br><span class="line">        <span class="keyword">if</span> (beat<span class="variable">.sop</span>) <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 数据包开始</span></span><br><span class="line">            <span class="keyword">if</span> (packet_in_progress) <span class="keyword">begin</span></span><br><span class="line">                `uvm_warning(get_type_name(), <span class="string">&quot;New packet started before previous packet ended&quot;</span>)</span><br><span class="line">                <span class="comment">// 强制结束当前数据包</span></span><br><span class="line">                finalize_current_packet(<span class="number">1</span>); <span class="comment">// 标记为错误</span></span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            start_new_packet(beat);</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (packet_in_progress) <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 添加beat到当前数据包</span></span><br><span class="line">            current_packet<span class="variable">.beats</span><span class="variable">.push_back</span>(beat);</span><br><span class="line">            current_packet<span class="variable">.beat_count</span>++;</span><br><span class="line">            beat<span class="variable">.packet_id</span> = current_packet<span class="variable">.packet_id</span>;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span> (beat<span class="variable">.err</span>) <span class="keyword">begin</span></span><br><span class="line">                current_packet<span class="variable">.has_error</span> = <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (beat<span class="variable">.eop</span>) <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 数据包结束</span></span><br><span class="line">            <span class="keyword">if</span> (!packet_in_progress) <span class="keyword">begin</span></span><br><span class="line">                `uvm_warning(get_type_name(), <span class="string">&quot;EOP received without SOP&quot;</span>)</span><br><span class="line">            <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                finalize_current_packet(<span class="number">0</span>);</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 开始新数据包 - 提取头部信息</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> start_new_packet(my_transaction first_beat);</span><br><span class="line">        current_packet = packet_transaction::type_id::create(<span class="string">&quot;current_packet&quot;</span>);</span><br><span class="line">        current_packet<span class="variable">.packet_id</span> = packet_id_counter++;</span><br><span class="line">        current_packet<span class="variable">.start_time</span> = <span class="built_in">$realtime</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 从SOP周期提取头部信息</span></span><br><span class="line">        <span class="keyword">if</span> (first_beat<span class="variable">.sop</span>) <span class="keyword">begin</span></span><br><span class="line">            current_packet<span class="variable">.packet_header</span> = first_beat<span class="variable">.get_header</span>();</span><br><span class="line">            current_packet<span class="variable">.data_type</span> = first_beat<span class="variable">.get_data_type_from_header</span>();</span><br><span class="line">            current_packet<span class="variable">.expected_payload_length</span> = first_beat<span class="variable">.get_payload_length_from_header</span>();</span><br><span class="line">            </span><br><span class="line">            `uvm_info(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Started packet %0d, type=%0d, expected_payload=%0d bytes&quot;</span>, </span><br><span class="line">                current_packet<span class="variable">.packet_id</span>, current_packet<span class="variable">.data_type</span>, </span><br><span class="line">                current_packet<span class="variable">.expected_payload_length</span>), UVM_MEDIUM)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        packet_in_progress = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 完成当前数据包 - 验证payload长度</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> finalize_current_packet(<span class="keyword">bit</span> force_error = <span class="number">0</span>);</span><br><span class="line">        <span class="keyword">if</span> (current_packet != <span class="literal">null</span>) <span class="keyword">begin</span></span><br><span class="line">            current_packet<span class="variable">.end_time</span> = <span class="built_in">$realtime</span>;</span><br><span class="line">            <span class="keyword">if</span> (force_error) current_packet<span class="variable">.has_error</span> = <span class="number">1</span>;</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 计算实际payload总长度</span></span><br><span class="line">            calculate_total_payload_length();</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 检查payload长度一致性</span></span><br><span class="line">            <span class="keyword">if</span> (!current_packet<span class="variable">.check_payload_length</span>()) <span class="keyword">begin</span></span><br><span class="line">                `uvm_warning(get_type_name(), </span><br><span class="line">                    <span class="built_in">$sformatf</span>(<span class="string">&quot;Payload length mismatch in packet %0d: expected=%0d, actual=%0d&quot;</span>, </span><br><span class="line">                    current_packet<span class="variable">.packet_id</span>, current_packet<span class="variable">.expected_payload_length</span>, </span><br><span class="line">                    current_packet<span class="variable">.total_payload_length</span>))</span><br><span class="line">                current_packet<span class="variable">.has_error</span> = <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 发送完整数据包</span></span><br><span class="line">            packet_ap<span class="variable">.write</span>(current_packet);</span><br><span class="line">            </span><br><span class="line">            `uvm_info(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Completed packet %0d: %0d beats, payload %0d/%0d bytes, %s&quot;</span>, </span><br><span class="line">                current_packet<span class="variable">.packet_id</span>, current_packet<span class="variable">.beat_count</span>,</span><br><span class="line">                current_packet<span class="variable">.total_payload_length</span>, current_packet<span class="variable">.expected_payload_length</span>,</span><br><span class="line">                current_packet<span class="variable">.has_error</span> ? <span class="string">&quot;WITH ERROR&quot;</span> : <span class="string">&quot;OK&quot;</span>), UVM_MEDIUM)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        packet_in_progress = <span class="number">0</span>;</span><br><span class="line">        current_packet = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 计算总payload长度 - 基于2048位数据宽度</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> calculate_total_payload_length();</span><br><span class="line">        <span class="keyword">int</span> total_bytes = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> remaining_payload = current_packet<span class="variable">.expected_payload_length</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">foreach</span> (current_packet<span class="variable">.beats</span>[i]) <span class="keyword">begin</span></span><br><span class="line">            my_transaction beat = current_packet<span class="variable">.beats</span>[i];</span><br><span class="line">            <span class="keyword">int</span> this_beat_payload;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span> (beat<span class="variable">.sop</span>) <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// SOP周期：只有低128字节是payload</span></span><br><span class="line">                this_beat_payload = (remaining_payload &gt; <span class="number">128</span>) ? <span class="number">128</span> : remaining_payload;</span><br><span class="line">            <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 非SOP周期：全部256字节是payload</span></span><br><span class="line">                this_beat_payload = (remaining_payload &gt; <span class="number">256</span>) ? <span class="number">256</span> : remaining_payload;</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            total_bytes += this_beat_payload;</span><br><span class="line">            remaining_payload -= this_beat_payload;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        current_packet<span class="variable">.total_payload_length</span> = total_bytes;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 监控分类型反压信号 - 增强数据包级监控</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> monitor_typed_backpressure();</span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">2</span>:<span class="number">0</span>] current_bp_states;</span><br><span class="line">        typed_backpressure_transaction bp_tr;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">            @(vif<span class="variable">.mon_cb</span>);</span><br><span class="line">            </span><br><span class="line">            current_bp_states = &#123;vif<span class="variable">.mon_cb</span><span class="variable">.c_backpressure</span>, </span><br><span class="line">                               vif<span class="variable">.mon_cb</span><span class="variable">.b_backpressure</span>, </span><br><span class="line">                               vif<span class="variable">.mon_cb</span><span class="variable">.a_backpressure</span>&#125;;</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 检查每种反压信号的变化</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) <span class="keyword">begin</span></span><br><span class="line">                <span class="keyword">if</span> (current_bp_states[i] !== previous_bp_states[i]) <span class="keyword">begin</span></span><br><span class="line">                    bp_tr = typed_backpressure_transaction::type_id::create(<span class="string">&quot;bp_tr&quot;</span>);</span><br><span class="line">                    </span><br><span class="line">                    <span class="keyword">case</span> (i)</span><br><span class="line">                        <span class="number">0</span>: <span class="keyword">begin</span></span><br><span class="line">                            bp_tr<span class="variable">.bp_type</span> = typed_backpressure_transaction::TYPE_A;</span><br><span class="line">                            bp_tr<span class="variable">.affected_data_type</span> = <span class="number">0</span>;</span><br><span class="line">                        <span class="keyword">end</span></span><br><span class="line">                        <span class="number">1</span>: <span class="keyword">begin</span></span><br><span class="line">                            bp_tr<span class="variable">.bp_type</span> = typed_backpressure_transaction::TYPE_B;</span><br><span class="line">                            bp_tr<span class="variable">.affected_data_type</span> = <span class="number">1</span>;</span><br><span class="line">                        <span class="keyword">end</span></span><br><span class="line">                        <span class="number">2</span>: <span class="keyword">begin</span></span><br><span class="line">                            bp_tr<span class="variable">.bp_type</span> = typed_backpressure_transaction::TYPE_C;</span><br><span class="line">                            bp_tr<span class="variable">.affected_data_type</span> = <span class="number">2</span>;</span><br><span class="line">                        <span class="keyword">end</span></span><br><span class="line">                    <span class="keyword">endcase</span></span><br><span class="line">                    </span><br><span class="line">                    bp_tr<span class="variable">.backpressure_active</span> = current_bp_states[i];</span><br><span class="line">                    </span><br><span class="line">                    <span class="keyword">if</span> (current_bp_states[i]) <span class="keyword">begin</span></span><br><span class="line">                        <span class="comment">// 反压激活</span></span><br><span class="line">                        bp_start_times[i] = <span class="built_in">$realtime</span>;</span><br><span class="line">                        bp_counts[i]++;</span><br><span class="line">                        </span><br><span class="line">                        <span class="comment">// 检查是否会影响正在传输的数据包</span></span><br><span class="line">                        <span class="keyword">if</span> (packet_in_progress &amp;&amp; current_packet != <span class="literal">null</span> &amp;&amp; </span><br><span class="line">                            current_packet<span class="variable">.data_type</span> == i) <span class="keyword">begin</span></span><br><span class="line">                            `uvm_warning(<span class="string">&quot;BP_PACKET_IMPACT&quot;</span>, </span><br><span class="line">                                <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %s backpressure activated during packet %0d transmission&quot;</span>, </span><br><span class="line">                                bp_tr<span class="variable">.bp_type</span><span class="variable">.name</span>(), current_packet<span class="variable">.packet_id</span>))</span><br><span class="line">                            bp_interrupted_packets[i]++;</span><br><span class="line">                        <span class="keyword">end</span></span><br><span class="line">                        </span><br><span class="line">                        `uvm_info(<span class="string">&quot;TYPED_BP_MON&quot;</span>, </span><br><span class="line">                            <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %s backpressure ACTIVATED (affects data type %0d) - Packet-level control&quot;</span>, </span><br><span class="line">                            bp_tr<span class="variable">.bp_type</span><span class="variable">.name</span>(), bp_tr<span class="variable">.affected_data_type</span>), UVM_MEDIUM)</span><br><span class="line">                    <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                        <span class="comment">// 反压释放</span></span><br><span class="line">                        bp_tr<span class="variable">.duration_ns</span> = <span class="keyword">int</span>&#x27;((<span class="built_in">$realtime</span> - bp_start_times[i]) / <span class="number">1</span>ns);</span><br><span class="line">                        `uvm_info(<span class="string">&quot;TYPED_BP_MON&quot;</span>, </span><br><span class="line">                            <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %s backpressure RELEASED (duration: %0d ns)&quot;</span>, </span><br><span class="line">                            bp_tr<span class="variable">.bp_type</span><span class="variable">.name</span>(), bp_tr<span class="variable">.duration_ns</span>), UVM_MEDIUM)</span><br><span class="line">                    <span class="keyword">end</span></span><br><span class="line">                    </span><br><span class="line">                    typed_bp_ap<span class="variable">.write</span>(bp_tr);</span><br><span class="line">                <span class="keyword">end</span></span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            previous_bp_states = current_bp_states;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 统计报告 - 增强数据包级统计</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> report_statistics();</span><br><span class="line">        <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">            #<span class="number">10</span>us;</span><br><span class="line">            `uvm_info(<span class="string">&quot;BP_STATS&quot;</span>, </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;BP Events - A:%0d, B:%0d, C:%0d | Interrupted Packets - A:%0d, B:%0d, C:%0d&quot;</span>, </span><br><span class="line">                bp_counts[<span class="number">0</span>], bp_counts[<span class="number">1</span>], bp_counts[<span class="number">2</span>],</span><br><span class="line">                bp_interrupted_packets[<span class="number">0</span>], bp_interrupted_packets[<span class="number">1</span>], bp_interrupted_packets[<span class="number">2</span>]), UVM_LOW)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><hr><h2 id="第四部分：优化的智能Driver设计"><a href="#第四部分：优化的智能Driver设计" class="headerlink" title="第四部分：优化的智能Driver设计"></a>第四部分：优化的智能Driver设计</h2><h3 id="数据包级反压控制的Driver-完整优化版本"><a href="#数据包级反压控制的Driver-完整优化版本" class="headerlink" title="数据包级反压控制的Driver - 完整优化版本"></a>数据包级反压控制的Driver - 完整优化版本</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_driver <span class="keyword">extends</span> uvm_driver <span class="variable">#(my_transaction)</span>;</span><br><span class="line">    `uvm_component_utils(my_driver)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> my_interface<span class="variable">.driver</span> vif;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 分类型反压控制状态 - 优化版本 ===</span></span><br><span class="line">    <span class="keyword">typedef</span> <span class="keyword">struct</span> &#123;</span><br><span class="line">        <span class="keyword">bit</span> active;           <span class="comment">// 当前是否激活</span></span><br><span class="line">        <span class="keyword">bit</span> pending;         <span class="comment">// 是否等待生效</span></span><br><span class="line">        <span class="keyword">int</span> wait_cycles;     <span class="comment">// 等待周期数</span></span><br><span class="line">        <span class="keyword">int</span> transactions;    <span class="comment">// 已传输事务数</span></span><br><span class="line">        <span class="keyword">int</span> blocked_count;   <span class="comment">// 被阻塞事务数</span></span><br><span class="line">        <span class="keyword">realtime</span> last_active_time; <span class="comment">// 最后激活时间</span></span><br><span class="line">    &#125; bp_status_t;</span><br><span class="line">    </span><br><span class="line">    bp_status_t bp_status[<span class="number">3</span>]; <span class="comment">// 三种类型的反压状态</span></span><br><span class="line">    <span class="keyword">int</span> max_bp_wait = <span class="number">1000</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 数据包传输状态管理 - 优化版本 ===</span></span><br><span class="line">    <span class="keyword">typedef</span> <span class="keyword">struct</span> &#123;</span><br><span class="line">        <span class="keyword">bit</span> in_progress;          <span class="comment">// 是否正在传输</span></span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] packet_type;    <span class="comment">// 当前数据包类型</span></span><br><span class="line">        <span class="keyword">int</span> beat_count;           <span class="comment">// 当前beat计数</span></span><br><span class="line">        <span class="keyword">int</span> expected_beats;       <span class="comment">// 预期beat总数</span></span><br><span class="line">        <span class="keyword">realtime</span> start_time;      <span class="comment">// 传输开始时间</span></span><br><span class="line">        <span class="keyword">int</span> packet_id;           <span class="comment">// 数据包ID</span></span><br><span class="line">    &#125; packet_tx_status_t;</span><br><span class="line">    </span><br><span class="line">    packet_tx_status_t current_tx;</span><br><span class="line">    <span class="keyword">int</span> packet_id_counter = <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">        <span class="comment">// 初始化反压状态</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) <span class="keyword">begin</span></span><br><span class="line">            bp_status[i] = &#x27;&#123;<span class="keyword">default</span>: <span class="number">0</span>&#125;;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        current_tx = &#x27;&#123;<span class="keyword">default</span>: <span class="number">0</span>&#125;;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">        <span class="keyword">if</span>(!uvm_config_db<span class="variable">#(virtual my_interface)::get(this, &quot;&quot;, &quot;vif&quot;, vif))</span></span><br><span class="line">            `uvm_fatal(get_type_name(), <span class="string">&quot;Virtual interface not found!&quot;</span>)</span><br><span class="line">        uvm_config_db<span class="variable">#(int)::get(this, &quot;&quot;, &quot;max_bp_wait&quot;, max_bp_wait)</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">        <span class="keyword">wait</span>(vif<span class="variable">.rst_n</span>);</span><br><span class="line">        reset_signals();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">fork</span></span><br><span class="line">            drive_transactions();</span><br><span class="line">            monitor_typed_backpressure_driver();</span><br><span class="line">            manage_packet_level_backpressure();</span><br><span class="line">        <span class="keyword">join_none</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> reset_signals();</span><br><span class="line">        vif<span class="variable">.drv_cb</span><span class="variable">.data_in</span> &lt;= &#x27;<span class="number">0</span>;</span><br><span class="line">        vif<span class="variable">.drv_cb</span><span class="variable">.sop_in</span> &lt;= &#x27;<span class="number">0</span>;</span><br><span class="line">        vif<span class="variable">.drv_cb</span><span class="variable">.eop_in</span> &lt;= &#x27;<span class="number">0</span>;</span><br><span class="line">        vif<span class="variable">.drv_cb</span><span class="variable">.vld_in</span> &lt;= &#x27;<span class="number">0</span>;</span><br><span class="line">        vif<span class="variable">.drv_cb</span><span class="variable">.err_in</span> &lt;= &#x27;<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> drive_transactions();</span><br><span class="line">        my_transaction tr;</span><br><span class="line">        <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">            seq_item_port<span class="variable">.get_next_item</span>(tr);</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 验证事务有效性</span></span><br><span class="line">            <span class="keyword">if</span> (!validate_transaction(tr)) <span class="keyword">begin</span></span><br><span class="line">                `uvm_error(get_type_name(), <span class="string">&quot;Invalid transaction received&quot;</span>)</span><br><span class="line">                seq_item_port<span class="variable">.item_done</span>();</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 从SOP周期的头部获取数据类型</span></span><br><span class="line">            <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] data_type = tr<span class="variable">.sop</span> ? tr<span class="variable">.get_data_type_from_header</span>() : current_tx<span class="variable">.packet_type</span>;</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// === 数据包级反压检查逻辑 ===</span></span><br><span class="line">            <span class="keyword">if</span> (tr<span class="variable">.sop</span>) <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 新数据包开始 - 检查反压和传输状态</span></span><br><span class="line">                <span class="keyword">if</span> (can_start_new_packet(data_type)) <span class="keyword">begin</span></span><br><span class="line">                    start_new_packet_transmission(tr, data_type);</span><br><span class="line">                    drive_packet_beat(tr);</span><br><span class="line">                    update_transmission_stats(data_type, <span class="number">1</span>);</span><br><span class="line">                <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                    <span class="comment">// 数据包被阻塞</span></span><br><span class="line">                    handle_blocked_packet(tr, data_type);</span><br><span class="line">                    <span class="keyword">continue</span>; <span class="comment">// 重新尝试此事务</span></span><br><span class="line">                <span class="keyword">end</span></span><br><span class="line">            <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 数据包续传 - 不检查反压，确保传输完整性</span></span><br><span class="line">                <span class="keyword">if</span> (!current_tx<span class="variable">.in_progress</span>) <span class="keyword">begin</span></span><br><span class="line">                    `uvm_error(get_type_name(), </span><br><span class="line">                        <span class="string">&quot;Non-SOP beat received without active packet transmission&quot;</span>)</span><br><span class="line">                    seq_item_port<span class="variable">.item_done</span>();</span><br><span class="line">                    <span class="keyword">continue</span>;</span><br><span class="line">                <span class="keyword">end</span></span><br><span class="line">                </span><br><span class="line">                drive_packet_beat(tr);</span><br><span class="line">                current_tx<span class="variable">.beat_count</span>++;</span><br><span class="line">                </span><br><span class="line">                <span class="comment">// 检查EOP</span></span><br><span class="line">                <span class="keyword">if</span> (tr<span class="variable">.eop</span>) <span class="keyword">begin</span></span><br><span class="line">                    complete_packet_transmission();</span><br><span class="line">                <span class="keyword">end</span></span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            seq_item_port<span class="variable">.item_done</span>();</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 验证事务有效性 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> validate_transaction(my_transaction tr);</span><br><span class="line">        <span class="comment">// 验证SOP/EOP逻辑</span></span><br><span class="line">        <span class="keyword">if</span> (tr<span class="variable">.sop</span> &amp;&amp; current_tx<span class="variable">.in_progress</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_warning(get_type_name(), </span><br><span class="line">                <span class="string">&quot;SOP received while packet transmission in progress - forcing completion&quot;</span>)</span><br><span class="line">            force_complete_current_transmission();</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 验证头部（如果是SOP）</span></span><br><span class="line">        <span class="keyword">if</span> (tr<span class="variable">.sop</span> &amp;&amp; !tr<span class="variable">.validate_header</span>()) <span class="keyword">begin</span></span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 检查是否可以开始新数据包 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">bit</span> can_start_new_packet(<span class="keyword">int</span> data_type);</span><br><span class="line">        <span class="comment">// 检查传输状态</span></span><br><span class="line">        <span class="keyword">if</span> (current_tx<span class="variable">.in_progress</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_error(get_type_name(), </span><br><span class="line">                <span class="string">&quot;Cannot start new packet - transmission already in progress&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 检查该类型的反压状态</span></span><br><span class="line">        <span class="keyword">if</span> (bp_status[data_type]<span class="variable">.active</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_info(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;New packet blocked - type %0d backpressure active&quot;</span>, data_type), </span><br><span class="line">                UVM_MEDIUM);</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 开始新数据包传输 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> start_new_packet_transmission(my_transaction tr, <span class="keyword">int</span> data_type);</span><br><span class="line">        current_tx<span class="variable">.in_progress</span> = <span class="number">1</span>;</span><br><span class="line">        current_tx<span class="variable">.packet_type</span> = data_type;</span><br><span class="line">        current_tx<span class="variable">.beat_count</span> = <span class="number">1</span>;</span><br><span class="line">        current_tx<span class="variable">.expected_beats</span> = tr<span class="variable">.calculate_expected_beats</span>();</span><br><span class="line">        current_tx<span class="variable">.start_time</span> = <span class="built_in">$realtime</span>;</span><br><span class="line">        current_tx<span class="variable">.packet_id</span> = packet_id_counter++;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 向Sequencer报告数据包开始传输</span></span><br><span class="line">        m_sequencer<span class="variable">.notify_packet_start</span>(data_type);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 更新Driver状态到Sequencer</span></span><br><span class="line">        my_sequencer::driver_status_t status;</span><br><span class="line">        status<span class="variable">.transmission_active</span> = <span class="number">1</span>;</span><br><span class="line">        status<span class="variable">.current_type</span> = data_type;</span><br><span class="line">        status<span class="variable">.beat_count</span> = <span class="number">1</span>;</span><br><span class="line">        status<span class="variable">.start_time</span> = <span class="built_in">$realtime</span>;</span><br><span class="line">        m_sequencer<span class="variable">.update_driver_status</span>(status);</span><br><span class="line">        </span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="built_in">$sformatf</span>(<span class="string">&quot;Started packet %0d transmission: type=%0d, expected_beats=%0d, payload_len=%0d&quot;</span>, </span><br><span class="line">            current_tx<span class="variable">.packet_id</span>, data_type, current_tx<span class="variable">.expected_beats</span>, tr<span class="variable">.payload_length</span>), </span><br><span class="line">            UVM_MEDIUM)</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 完成数据包传输 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> complete_packet_transmission();</span><br><span class="line">        <span class="keyword">realtime</span> duration = <span class="built_in">$realtime</span> - current_tx<span class="variable">.start_time</span>;</span><br><span class="line">        </span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="built_in">$sformatf</span>(<span class="string">&quot;Completed packet %0d: type=%0d, %0d/%0d beats, duration=%.1f ns&quot;</span>, </span><br><span class="line">            current_tx<span class="variable">.packet_id</span>, current_tx<span class="variable">.packet_type</span>, </span><br><span class="line">            current_tx<span class="variable">.beat_count</span>, current_tx<span class="variable">.expected_beats</span>, duration / <span class="number">1</span>ns), </span><br><span class="line">            UVM_MEDIUM)</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 验证beat数量</span></span><br><span class="line">        <span class="keyword">if</span> (current_tx<span class="variable">.beat_count</span> != current_tx<span class="variable">.expected_beats</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_warning(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Beat count mismatch: expected %0d, actual %0d&quot;</span>, </span><br><span class="line">                current_tx<span class="variable">.expected_beats</span>, current_tx<span class="variable">.beat_count</span>))</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 重置传输状态</span></span><br><span class="line">        current_tx<span class="variable">.in_progress</span> = <span class="number">0</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 应用等待生效的反压</span></span><br><span class="line">        apply_pending_backpressures();</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 处理被阻塞的数据包 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> handle_blocked_packet(my_transaction tr, <span class="keyword">int</span> data_type);</span><br><span class="line">        bp_status[data_type]<span class="variable">.blocked_count</span>++;</span><br><span class="line">        </span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="built_in">$sformatf</span>(<span class="string">&quot;Packet blocked: type=%0d (total blocked: %0d)&quot;</span>, </span><br><span class="line">            data_type, bp_status[data_type]<span class="variable">.blocked_count</span>), UVM_MEDIUM)</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 将事务放回队列等待重试</span></span><br><span class="line">        seq_item_port<span class="variable">.put_response</span>(tr);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 应用等待生效的反压 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> apply_pending_backpressures();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) <span class="keyword">begin</span></span><br><span class="line">            <span class="keyword">if</span> (bp_status[i]<span class="variable">.pending</span>) <span class="keyword">begin</span></span><br><span class="line">                bp_status[i]<span class="variable">.active</span> = <span class="number">1</span>;</span><br><span class="line">                bp_status[i]<span class="variable">.pending</span> = <span class="number">0</span>;</span><br><span class="line">                bp_status[i]<span class="variable">.last_active_time</span> = <span class="built_in">$realtime</span>;</span><br><span class="line">                </span><br><span class="line">                `uvm_info(get_type_name(), </span><br><span class="line">                    <span class="built_in">$sformatf</span>(<span class="string">&quot;Applied pending backpressure for type %0d&quot;</span>, i), UVM_MEDIUM)</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 监控分类型反压信号 - 完全优化版本 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> monitor_typed_backpressure_driver();</span><br><span class="line">        <span class="keyword">bit</span> [<span class="number">2</span>:<span class="number">0</span>] current_signals, previous_signals = <span class="number">3&#x27;b000</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">            @(vif<span class="variable">.drv_cb</span>);</span><br><span class="line">            current_signals = vif<span class="variable">.get_backpressure_status</span>();</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// 检查每种反压信号的变化</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) <span class="keyword">begin</span></span><br><span class="line">                <span class="keyword">if</span> (current_signals[i] !== previous_signals[i]) <span class="keyword">begin</span></span><br><span class="line">                    handle_backpressure_change(i, current_signals[i]);</span><br><span class="line">                <span class="keyword">end</span></span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            previous_signals = current_signals;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 处理反压状态变化 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> handle_backpressure_change(<span class="keyword">int</span> type_idx, <span class="keyword">bit</span> new_state);</span><br><span class="line">        <span class="keyword">if</span> (new_state) <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 反压激活</span></span><br><span class="line">            <span class="keyword">if</span> (current_tx<span class="variable">.in_progress</span> &amp;&amp; current_tx<span class="variable">.packet_type</span> == type_idx) <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 正在传输该类型数据包，标记为待生效</span></span><br><span class="line">                bp_status[type_idx]<span class="variable">.pending</span> = <span class="number">1</span>;</span><br><span class="line">                `uvm_info(get_type_name(), </span><br><span class="line">                    <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %0d backpressure PENDING (packet %0d in transmission)&quot;</span>, </span><br><span class="line">                    type_idx, current_tx<span class="variable">.packet_id</span>), UVM_MEDIUM)</span><br><span class="line">            <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 立即生效</span></span><br><span class="line">                bp_status[type_idx]<span class="variable">.active</span> = <span class="number">1</span>;</span><br><span class="line">                bp_status[type_idx]<span class="variable">.last_active_time</span> = <span class="built_in">$realtime</span>;</span><br><span class="line">                `uvm_info(get_type_name(), </span><br><span class="line">                    <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %0d backpressure ACTIVATED immediately&quot;</span>, type_idx), UVM_MEDIUM)</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">        <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 反压释放</span></span><br><span class="line">            bp_status[type_idx]<span class="variable">.active</span> = <span class="number">0</span>;</span><br><span class="line">            bp_status[type_idx]<span class="variable">.pending</span> = <span class="number">0</span>;</span><br><span class="line">            `uvm_info(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %0d backpressure RELEASED&quot;</span>, type_idx), UVM_MEDIUM)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 更新传输统计 ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> update_transmission_stats(<span class="keyword">int</span> data_type, <span class="keyword">bit</span> success);</span><br><span class="line">        <span class="keyword">if</span> (success) <span class="keyword">begin</span></span><br><span class="line">            bp_status[data_type]<span class="variable">.transactions</span>++;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// === 强制完成当前传输（错误恢复） ===</span></span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> force_complete_current_transmission();</span><br><span class="line">        <span class="keyword">if</span> (current_tx<span class="variable">.in_progress</span>) <span class="keyword">begin</span></span><br><span class="line">            `uvm_warning(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Force completing packet %0d transmission&quot;</span>, current_tx<span class="variable">.packet_id</span>))</span><br><span class="line">            current_tx<span class="variable">.in_progress</span> = <span class="number">0</span>;</span><br><span class="line">            apply_pending_backpressures();</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> report_phase(uvm_phase phase);</span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="string">&quot;=== Enhanced Driver Statistics by Data Type ===&quot;</span>, UVM_LOW)</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) <span class="keyword">begin</span></span><br><span class="line">            <span class="keyword">real</span> block_rate = (bp_status[i]<span class="variable">.transactions</span> &gt; <span class="number">0</span>) ? </span><br><span class="line">                <span class="keyword">real</span>&#x27;(bp_status[i]<span class="variable">.blocked_count</span>) * <span class="number">100</span><span class="variable">.0</span> / </span><br><span class="line">                (bp_status[i]<span class="variable">.transactions</span> + bp_status[i]<span class="variable">.blocked_count</span>) : <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">                </span><br><span class="line">            `uvm_info(get_type_name(), </span><br><span class="line">                <span class="built_in">$sformatf</span>(<span class="string">&quot;Type %0d: %0d sent, %0d blocked (%.1f%%), %0d BP wait cycles&quot;</span>, </span><br><span class="line">                i, bp_status[i]<span class="variable">.transactions</span>, bp_status[i]<span class="variable">.blocked_count</span>, </span><br><span class="line">                block_rate, bp_status[i]<span class="variable">.wait_cycles</span>), UVM_LOW)</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="string">&quot;=== Packet-Level Backpressure Benefits ===&quot;</span>, UVM_LOW)</span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="string">&quot;✓ Zero packet fragmentation - complete transmission guaranteed&quot;</span>, UVM_LOW)</span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="string">&quot;✓ Perfect SOP/EOP alignment - no boundary corruption&quot;</span>, UVM_LOW)</span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="string">&quot;✓ Optimal DUT performance - full packet processing&quot;</span>, UVM_LOW)</span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="string">&quot;✓ Minimal retransmission overhead - smart pending mechanism&quot;</span>, UVM_LOW)</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><hr><h2 id="第五部分：数据包序列生成"><a href="#第五部分：数据包序列生成" class="headerlink" title="第五部分：数据包序列生成"></a>第五部分：数据包序列生成</h2><h3 id="2048位头部感知的序列生成"><a href="#2048位头部感知的序列生成" class="headerlink" title="2048位头部感知的序列生成"></a>2048位头部感知的序列生成</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 精确payload长度的序列 - 支持2048位数据宽度</span></span><br><span class="line"><span class="keyword">class</span> exact_payload_sequence <span class="keyword">extends</span> uvm_sequence <span class="variable">#(my_transaction)</span>;</span><br><span class="line">    `uvm_object_utils(exact_payload_sequence)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] packet_type;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">int</span> exact_payload_bytes;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">constraint</span> c_packet_type &#123; packet_type <span class="keyword">inside</span> &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>&#125;; &#125;</span><br><span class="line">    <span class="keyword">constraint</span> c_payload_bytes &#123; exact_payload_bytes <span class="keyword">inside</span> &#123;[<span class="number">50</span>:<span class="number">4000</span>]&#125;; &#125; <span class="comment">// 更大范围</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;exact_payload_sequence&quot;</span>);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">        my_transaction tr;</span><br><span class="line">        <span class="keyword">int</span> remaining_bytes = exact_payload_bytes;</span><br><span class="line">        <span class="keyword">int</span> beat_count = <span class="number">0</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 计算需要的beat数</span></span><br><span class="line">        <span class="keyword">int</span> total_beats = <span class="number">1</span>; <span class="comment">// 至少需要SOP beat</span></span><br><span class="line">        <span class="keyword">if</span> (exact_payload_bytes &gt; <span class="number">128</span>) <span class="keyword">begin</span></span><br><span class="line">            <span class="comment">// 需要额外的非SOP beat</span></span><br><span class="line">            total_beats += ((exact_payload_bytes - <span class="number">128</span>) + <span class="number">255</span>) / <span class="number">256</span>; <span class="comment">// 向上取整</span></span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">while</span> (remaining_bytes &gt; <span class="number">0</span>) <span class="keyword">begin</span></span><br><span class="line">            tr = my_transaction::type_id::create(<span class="built_in">$sformatf</span>(<span class="string">&quot;beat_%0d&quot;</span>, beat_count));</span><br><span class="line">            start_item(tr);</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span> (beat_count == <span class="number">0</span>) <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// SOP周期：构造头部和部分payload</span></span><br><span class="line">                <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] constructed_header = <span class="number">1024&#x27;h0</span>;</span><br><span class="line">                constructed_header[<span class="number">1</span>:<span class="number">0</span>] = packet_type;          <span class="comment">// 设置类型</span></span><br><span class="line">                constructed_header[<span class="number">31</span>:<span class="number">2</span>] = exact_payload_bytes; <span class="comment">// 设置长度</span></span><br><span class="line">                </span><br><span class="line">                <span class="keyword">assert</span>(tr<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;</span><br><span class="line">                    sop == <span class="number">1</span>;</span><br><span class="line">                    eop == (remaining_bytes &lt;= <span class="number">128</span>);</span><br><span class="line">                    header == constructed_header;</span><br><span class="line">                    data_type == packet_type;</span><br><span class="line">                    payload_length == exact_payload_bytes;</span><br><span class="line">                &#125;);</span><br><span class="line">                </span><br><span class="line">                remaining_bytes -= (remaining_bytes &gt; <span class="number">128</span>) ? <span class="number">128</span> : remaining_bytes;</span><br><span class="line">            <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 后续周期：纯payload</span></span><br><span class="line">                <span class="keyword">int</span> this_beat_payload = (remaining_bytes &gt; <span class="number">256</span>) ? <span class="number">256</span> : remaining_bytes;</span><br><span class="line">                <span class="keyword">assert</span>(tr<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;</span><br><span class="line">                    sop == <span class="number">0</span>;</span><br><span class="line">                    eop == (remaining_bytes &lt;= <span class="number">256</span>);</span><br><span class="line">                    data_type == packet_type;</span><br><span class="line">                &#125;);</span><br><span class="line">                remaining_bytes -= this_beat_payload;</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            finish_item(tr);</span><br><span class="line">            beat_count++;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="built_in">$sformatf</span>(<span class="string">&quot;Generated exact payload packet: type=%0d, %0d bytes, %0d beats&quot;</span>, </span><br><span class="line">            packet_type, exact_payload_bytes, beat_count), UVM_LOW)</span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 大payload数据包序列</span></span><br><span class="line"><span class="keyword">class</span> large_payload_sequence <span class="keyword">extends</span> uvm_sequence <span class="variable">#(my_transaction)</span>;</span><br><span class="line">    `uvm_object_utils(large_payload_sequence)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] packet_type;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">int</span> large_payload_bytes;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">constraint</span> c_packet_type &#123; packet_type <span class="keyword">inside</span> &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>&#125;; &#125;</span><br><span class="line">    <span class="keyword">constraint</span> c_payload_bytes &#123; </span><br><span class="line">        large_payload_bytes <span class="keyword">inside</span> &#123;[<span class="number">1000</span>:<span class="number">10000</span>]&#125;; <span class="comment">// 1KB-10KB大包</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;large_payload_sequence&quot;</span>);</span><br><span class="line">        <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">        my_transaction tr;</span><br><span class="line">        <span class="keyword">int</span> remaining_bytes = large_payload_bytes;</span><br><span class="line">        <span class="keyword">int</span> beat_count = <span class="number">0</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">while</span> (remaining_bytes &gt; <span class="number">0</span>) <span class="keyword">begin</span></span><br><span class="line">            tr = my_transaction::type_id::create(<span class="built_in">$sformatf</span>(<span class="string">&quot;large_beat_%0d&quot;</span>, beat_count));</span><br><span class="line">            start_item(tr);</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span> (beat_count == <span class="number">0</span>) <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// SOP周期</span></span><br><span class="line">                <span class="keyword">bit</span> [<span class="number">1023</span>:<span class="number">0</span>] large_header = <span class="number">1024&#x27;h0</span>;</span><br><span class="line">                large_header[<span class="number">1</span>:<span class="number">0</span>] = packet_type;</span><br><span class="line">                large_header[<span class="number">31</span>:<span class="number">2</span>] = large_payload_bytes;</span><br><span class="line">                <span class="comment">// 可以在头部添加更多信息，如时间戳、序列号等</span></span><br><span class="line">                large_header[<span class="number">63</span>:<span class="number">32</span>] = $urandom(); <span class="comment">// 随机时间戳</span></span><br><span class="line">                </span><br><span class="line">                <span class="keyword">assert</span>(tr<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;</span><br><span class="line">                    sop == <span class="number">1</span>;</span><br><span class="line">                    eop == (remaining_bytes &lt;= <span class="number">128</span>);</span><br><span class="line">                    header == large_header;</span><br><span class="line">                    data_type == packet_type;</span><br><span class="line">                    payload_length == large_payload_bytes;</span><br><span class="line">                &#125;);</span><br><span class="line">                </span><br><span class="line">                remaining_bytes -= (remaining_bytes &gt; <span class="number">128</span>) ? <span class="number">128</span> : remaining_bytes;</span><br><span class="line">            <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">                <span class="comment">// 非SOP周期</span></span><br><span class="line">                <span class="keyword">assert</span>(tr<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;</span><br><span class="line">                    sop == <span class="number">0</span>;</span><br><span class="line">                    eop == (remaining_bytes &lt;= <span class="number">256</span>);</span><br><span class="line">                    data_type == packet_type;</span><br><span class="line">                &#125;);</span><br><span class="line">                </span><br><span class="line">                <span class="keyword">int</span> this_beat_payload = (remaining_bytes &gt; <span class="number">256</span>) ? <span class="number">256</span> : remaining_bytes;</span><br><span class="line">                remaining_bytes -= this_beat_payload;</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">            </span><br><span class="line">            finish_item(tr);</span><br><span class="line">            beat_count++;</span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">        </span><br><span class="line">        `uvm_info(get_type_name(), </span><br><span class="line">            <span class="built_in">$sformatf</span>(<span class="string">&quot;Generated large payload packet: type=%0d, %0d bytes, %0d beats&quot;</span>, </span><br><span class="line">            packet_type, large_payload_bytes, beat_count), UVM_LOW)</span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><hr><h2 id="第六部分：UVM验证环境架构图与流程图"><a href="#第六部分：UVM验证环境架构图与流程图" class="headerlink" title="第六部分：UVM验证环境架构图与流程图"></a>第六部分：UVM验证环境架构图与流程图</h2><h3 id="📊-UVM验证环境分层架构"><a href="#📊-UVM验证环境分层架构" class="headerlink" title="📊 UVM验证环境分层架构"></a>📊 UVM验证环境分层架构</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line">┌─────────────────────────────────────────────────────────────────────────────────┐</span><br><span class="line">│                           UVM验证环境分层架构                                    │</span><br><span class="line">├─────────────────────────────────────────────────────────────────────────────────┤</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │</span><br><span class="line">│ ┃                        TEST LAYER (测试层)                                 ┃ │</span><br><span class="line">│ ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ ┃ │</span><br><span class="line">│ ┃ │  Light Traffic  │ │ Medium Traffic  │ │ Heavy Traffic   │ │ Stress Test  │ ┃ │</span><br><span class="line">│ ┃ │      Test       │ │      Test       │ │      Test       │ │              │ ┃ │</span><br><span class="line">│ ┃ │                 │ │                 │ │                 │ │              │ ┃ │</span><br><span class="line">│ ┃ │ • 轻载场景      │ │ • 中载场景      │ │ • 重载场景      │ │ • 极限测试   │ ┃ │</span><br><span class="line">│ ┃ │ • 基础功能      │ │ • 混合流量      │ │ • 高频反压      │ │ • 错误注入   │ ┃ │</span><br><span class="line">│ ┃ │ • 反压验证      │ │ • 负载均衡      │ │ • 性能验证      │ │ • 边界条件   │ ┃ │</span><br><span class="line">│ ┃ └─────────────────┘ └─────────────────┘ └─────────────────┘ └──────────────┘ ┃ │</span><br><span class="line">│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │</span><br><span class="line">│                               │                                                │</span><br><span class="line">│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │</span><br><span class="line">│ ┃                    ENVIRONMENT LAYER (环境层)                               ┃ │</span><br><span class="line">│ ┃                                                                             ┃ │</span><br><span class="line">│ ┃ ┌─────────────────────────────┐              ┌─────────────────────────────┐ ┃ │</span><br><span class="line">│ ┃ │        Data Agent           │              │    Backpressure Agent      │ ┃ │</span><br><span class="line">│ ┃ │ ┌─────────────────────────┐ │              │ ┌─────────────────────────┐ │ ┃ │</span><br><span class="line">│ ┃ │ │       Monitor           │ │              │ │    BP Controller        │ │ ┃ │</span><br><span class="line">│ ┃ │ │ • Beat采集              │ │              │ │ • 随机反压              │ │ ┃ │</span><br><span class="line">│ ┃ │ │ • Packet重组            │ │              │ │ • 周期反压              │ │ ┃ │</span><br><span class="line">│ ┃ │ │ • 反压状态监控          │ │              │ │ • 突发反压              │ │ ┃ │</span><br><span class="line">│ ┃ │ │ • 统计分析              │ │              │ │ • 自适应控制            │ │ ┃ │</span><br><span class="line">│ ┃ │ └─────────────────────────┘ │              │ └─────────────────────────┘ │ ┃ │</span><br><span class="line">│ ┃ │                             │              └─────────────────────────────┘ ┃ │</span><br><span class="line">│ ┃ │ ┌─────────────────────────┐ │                                             ┃ │</span><br><span class="line">│ ┃ │ │     Sequencer           │◄┼──────────────┐                             ┃ │</span><br><span class="line">│ ┃ │ │ • 反压状态桥梁          │ │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • 性能统计管理          │ │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • Driver状态跟踪        │ │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • 负载均衡算法          │ │              │                             ┃ │</span><br><span class="line">│ ┃ │ └─────────────────────────┘ │              │                             ┃ │</span><br><span class="line">│ ┃ │           ▲                 │              │                             ┃ │</span><br><span class="line">│ ┃ │ ┌─────────┴─────────┐       │              │                             ┃ │</span><br><span class="line">│ ┃ │ │      Driver       │       │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • 数据包级反压    │       │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • SOP/EOP对齐     │       │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • Pending机制     │       │              │                             ┃ │</span><br><span class="line">│ ┃ │ │ • 状态反馈        │       │              │                             ┃ │</span><br><span class="line">│ ┃ │ └───────────────────┘       │              │                             ┃ │</span><br><span class="line">│ ┃ └─────────────────────────────┘              │                             ┃ │</span><br><span class="line">│ ┃                                               │                             ┃ │</span><br><span class="line">│ ┃ ┌─────────────────────────────────────────────┼─────────────────────────┐   ┃ │</span><br><span class="line">│ ┃ │                Scoreboard &amp; Checker        │                         │   ┃ │</span><br><span class="line">│ ┃ │ • 数据完整性检查                            │                         │   ┃ │</span><br><span class="line">│ ┃ │ • 反压行为验证                              │                         │   ┃ │</span><br><span class="line">│ ┃ │ • 性能指标统计                              │                         │   ┃ │</span><br><span class="line">│ ┃ │ • 错误检测报告                              │                         │   ┃ │</span><br><span class="line">│ ┃ └─────────────────────────────────────────────┘                         │   ┃ │</span><br><span class="line">│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │</span><br><span class="line">│                                  │                                            │</span><br><span class="line">│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │</span><br><span class="line">│ ┃                      INTERFACE LAYER (接口层)                               ┃ │</span><br><span class="line">│ ┃                                                                             ┃ │</span><br><span class="line">│ ┃ ┌─────────────────────────────┐    ┌─────────────────────────────────────┐ ┃ │</span><br><span class="line">│ ┃ │      <span class="number">2048</span>位数据接口          │    │         反压控制接口                │ ┃ │</span><br><span class="line">│ ┃ │ ┌─────────────────────────┐ │    │ ┌─────────────────────────────────┐ │ ┃ │</span><br><span class="line">│ ┃ │ │ data[<span class="number">2047</span>:<span class="number">0</span>]            │ │    │ │ type0_backpressure             │ │ ┃ │</span><br><span class="line">│ ┃ │ │ sop/eop                 │ │    │ │ type1_backpressure             │ │ ┃ │</span><br><span class="line">│ ┃ │ │ vld/err                 │ │    │ │ type2_backpressure             │ │ ┃ │</span><br><span class="line">│ ┃ │ │ ───────────────────────│ │    │ │ ───────────────────────────────│ │ ┃ │</span><br><span class="line">│ ┃ │ │ • <span class="number">256</span>字节宽度           │ │    │ │ • 分类型独立控制               │ │ ┃ │</span><br><span class="line">│ ┃ │ │ • SOP:头部+Payload      │ │    │ │ • 数据包级生效                 │ │ ┃ │</span><br><span class="line">│ ┃ │ │ • 非SOP:纯Payload       │ │    │ │ • Pending延迟机制              │ │ ┃ │</span><br><span class="line">│ ┃ │ └─────────────────────────┘ │    │ └─────────────────────────────────┘ │ ┃ │</span><br><span class="line">│ ┃ └─────────────────────────────┘    └─────────────────────────────────────┘ ┃ │</span><br><span class="line">│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │</span><br><span class="line">│                               │                                                │</span><br><span class="line">│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │</span><br><span class="line">│ ┃                           DUT LAYER (设计层)                                ┃ │</span><br><span class="line">│ ┃                                                                             ┃ │</span><br><span class="line">│ ┃ ┌─────────────┐     ┌─────────────────┐     ┌─────────────────────────────┐ ┃ │</span><br><span class="line">│ ┃ │   Ingress   │────▶│  Packet Engine  │────▶│         Egress              │ ┃ │</span><br><span class="line">│ ┃ │             │     │                 │     │                             │ ┃ │</span><br><span class="line">│ ┃ │ • Header    │     │ • 类型识别处理  │     │ • 输出缓冲控制              │ ┃ │</span><br><span class="line">│ ┃ │   Parsing   │     │ • Payload处理   │     │ • 反压信号生成              │ ┃ │</span><br><span class="line">│ ┃ │ • Type      │     │ • 错误检测      │     │ • SOP/EOP生成               │ ┃ │</span><br><span class="line">│ ┃ │   Extract   │     │ • 流量控制      │     │ • Valid信号控制             │ ┃ │</span><br><span class="line">│ ┃ │ • Length    │     │ • 性能监控      │     │ • 错误传播                   │ ┃ │</span><br><span class="line">│ ┃ │   Validate  │     │                 │     │ • 基于类型的流控制         │ ┃ │</span><br><span class="line">│ ┃ └─────────────┘     └─────────────────┘     └─────────────────────────────┘ ┃ │</span><br><span class="line">│ └─────────────────────────────────────────────────────────────────────────┘ │</span><br><span class="line">└─────────────────────────────────────────────────────────────────────────────────┘</span><br></pre></td></tr></table></figure><hr><h3 id="🔄-Sequence控制激励产生流程图"><a href="#🔄-Sequence控制激励产生流程图" class="headerlink" title="🔄 Sequence控制激励产生流程图"></a>🔄 Sequence控制激励产生流程图</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">┌─────────────────────────────────────────────────────────────────────────────────┐</span><br><span class="line">│                        Sequence激励控制核心流程                                  │</span><br><span class="line">├─────────────────────────────────────────────────────────────────────────────────┤</span><br><span class="line">│                                                                                 │</span><br><span class="line">│  ┌─────────────┐                                                               │</span><br><span class="line">│  │    START    │                                                               │</span><br><span class="line">│  └──────┬──────┘                                                               │</span><br><span class="line">│         │                                                                      │</span><br><span class="line">│         ▼                                                                      │</span><br><span class="line">│  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  │</span><br><span class="line">│  ┃                   SEQUENCE CONTROL CENTER                                 ┃  │</span><br><span class="line">│  ┃                     (激励控制中心)                                        ┃  │</span><br><span class="line">│  ┃                                                                           ┃  │</span><br><span class="line">│  ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────┐ ┃  │</span><br><span class="line">│  ┃ │   系统状态分析  │ │   智能决策引擎  │ │   激励策略执行  │ │ 性能优化 │ ┃  │</span><br><span class="line">│  ┃ │                 │ │                 │ │                 │ │          │ ┃  │</span><br><span class="line">│  ┃ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌──────┐ │ ┃  │</span><br><span class="line">│  ┃ │ │反压状态[<span class="number">3</span>:<span class="number">0</span>]│ │ │ │ 保守模式    │ │ │ │数据包生成   │ │ │ │自适应│ │ ┃  │</span><br><span class="line">│  ┃ │ │ type0: ●    │ │ │ │ • 低风险    │ │ │ │• Type0小包  │ │ │ │速率  │ │ ┃  │</span><br><span class="line">│  ┃ │ │ type1: ○    │ │ │ │ • 稳定优先  │ │ │ │• Type1中包  │ │ │ │调整  │ │ ┃  │</span><br><span class="line">│  ┃ │ │ type2: ●    │ │ │ └─────────────┘ │ │ │• Type2大包  │ │ │ └──────┘ │ ┃  │</span><br><span class="line">│  ┃ │ └─────────────┘ │ │ ┌─────────────┐ │ │ └─────────────┘ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ ┌─────────────┐ │ │ │ 平衡模式    │ │ │ ┌─────────────┐ │ │ ┌──────┐ │ ┃  │</span><br><span class="line">│  ┃ │ │吞吐率统计   │ │ │ │ • 负载均衡  │ │ │ │时序控制     │ │ │ │负载  │ │ ┃  │</span><br><span class="line">│  ┃ │ │Type0: <span class="number">45</span>pps │ │ │ │ • 性能优化  │ │ │ │• 发送间隔   │ │ │ │均衡  │ │ ┃  │</span><br><span class="line">│  ┃ │ │Type1: <span class="number">32</span>pps │ │ │ └─────────────┘ │ │ │• 优先级     │ │ │ └──────┘ │ ┃  │</span><br><span class="line">│  ┃ │ │Type2: <span class="number">28</span>pps │ │ │ ┌─────────────┐ │ │ └─────────────┘ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ └─────────────┘ │ │ │ 激进模式    │ │ │ ┌─────────────┐ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ ┌─────────────┐ │ │ │ • 高吞吐量  │ │ │ │错误处理     │ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ │队列状态     │ │ │ │ • 压力测试  │ │ │ │• 重试机制   │ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ │Pending[<span class="number">3</span>]   │ │ │ └─────────────┘ │ │ │• 降级策略   │ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ │[<span class="number">5</span>, <span class="number">3</span>, <span class="number">8</span>]    │ │ │                 │ │ └─────────────┘ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ └─────────────┘ └─────────────────┘ └─────────────────┘ └──────────┘ ┃  │</span><br><span class="line">│  ┃ └─────────────────┘                                                      ┃  │</span><br><span class="line">│  ┃         │                           │                         │          ┃  │</span><br><span class="line">│  ┃         ▼                           ▼                         ▼          ┃  │</span><br><span class="line">│  ┃ ┌─────────────────────────────────────────────────────────────────────┐   ┃  │</span><br><span class="line">│  ┃ │                    决策输出与控制命令                                  │   ┃  │</span><br><span class="line">│  ┃ │ • 选择发送类型: Type1 (负载最轻)                                      │   ┃  │</span><br><span class="line">│  ┃ │ • 数据包大小: <span class="number">1024</span> bytes                                              │   ┃  │</span><br><span class="line">│  ┃ │ • 发送时机: 立即发送                                                   │   ┃  │</span><br><span class="line">│  ┃ │ • 优先级: 中等                                                         │   ┃  │</span><br><span class="line">│  ┃ │ • 控制命令: start_item() → 子<span class="keyword">sequence</span>调用 → finish_item()               │   ┃  │</span><br><span class="line">│  ┃ └─────────────────────────────────────────────────────────────────────┘   ┃  │</span><br><span class="line">│  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛  │</span><br><span class="line">│                                  │                                            │</span><br><span class="line">│                                  ▼                                            │</span><br><span class="line">│  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  │</span><br><span class="line">│  ┃                         SEQUENCER BRIDGE                                 ┃  │</span><br><span class="line">│  ┃                          (状态桥梁)                                       ┃  │</span><br><span class="line">│  ┃                                                                           ┃  │</span><br><span class="line">│  ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────┐ ┃  │</span><br><span class="line">│  ┃ │  反压状态跟踪   │ │  性能统计管理   │ │ Driver状态管理  │ │ 通信接口 │ ┃  │</span><br><span class="line">│  ┃ │                 │ │                 │ │                 │ │          │ ┃  │</span><br><span class="line">│  ┃ │ • BP信号监控    │ │ • 实时吞吐率    │ │ • 传输状态跟踪  │ │ • Mon→Seq │ ┃  │</span><br><span class="line">│  ┃ │ • 状态变化通知  │ │ • 延迟统计      │ │ • 完成/阻塞报告 │ │ • Drv→Seq │ ┃  │</span><br><span class="line">│  ┃ │ • 历史记录维护  │ │ • 负载均衡计算  │ │ • 错误状态反馈  │ │ • Seq→Drv │ ┃  │</span><br><span class="line">│  ┃ │ • 趋势分析      │ │ • 性能告警      │ │ • 资源使用统计  │ │ • 状态同步│ ┃  │</span><br><span class="line">│  ┃ └─────────────────┘ └─────────────────┘ └─────────────────┘ └──────────┘ ┃  │</span><br><span class="line">│  ┃         ▲                   ▲                   ▲               ▲        ┃  │</span><br><span class="line">│  ┃         │                   │                   │               │        ┃  │</span><br><span class="line">│  ┃   ┌─────┴─────┐       ┌─────┴─────┐       ┌─────┴─────┐   ┌─────┴─────┐ ┃  │</span><br><span class="line">│  ┃   │  Monitor  │       │Performance│       │  Driver   │   │  Control  │ ┃  │</span><br><span class="line">│  ┃   │ Feedback  │       │ Metrics   │       │ Feedback  │   │ Interface │ ┃  │</span><br><span class="line">│  ┃   └───────────┘       └───────────┘       └───────────┘   └───────────┘ ┃  │</span><br><span class="line">│  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛  │</span><br><span class="line">│                                  │                                            │</span><br><span class="line">│                                  ▼                                            │</span><br><span class="line">│  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  │</span><br><span class="line">│  ┃                        DRIVER RESPONSE                                   ┃  │</span><br><span class="line">│  ┃                         (响应执行)                                        ┃  │</span><br><span class="line">│  ┃                                                                           ┃  │</span><br><span class="line">│  ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────┐ ┃  │</span><br><span class="line">│  ┃ │  事务接收处理   │ │ 数据包级反压控制│ │  信号驱动执行   │ │ 状态反馈 │ ┃  │</span><br><span class="line">│  ┃ │                 │ │                 │ │                 │ │          │ ┃  │</span><br><span class="line">│  ┃ │ • get_next_item │ │ • SOP反压检查   │ │ • 接口信号驱动  │ │ • 完成通知│ ┃  │</span><br><span class="line">│  ┃ │ • 事务验证      │ │ • 传输中不中断  │ │ • 时序控制      │ │ • 阻塞报告│ ┃  │</span><br><span class="line">│  ┃ │ • 类型解析      │ │ • EOP后应用BP   │ │ • clk <span class="keyword">edge</span>同步  │ │ • 错误上报│ ┃  │</span><br><span class="line">│  ┃ │ • 有效性检查    │ │ • Pending机制   │ │ • valid控制     │ │ • 统计更新│ ┃  │</span><br><span class="line">│  ┃ └─────────────────┘ └─────────────────┘ └─────────────────┘ └──────────┘ ┃  │</span><br><span class="line">│  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛  │</span><br><span class="line">│                                                                               │</span><br><span class="line">│  ┌─────────────────────────────────────────────────────────────────────────┐ │</span><br><span class="line">│  │                             INTERFACE                                   │ │</span><br><span class="line">│  │ ┌─────────────────────────┐      ┌─────────────────────────────────────┐ │ │</span><br><span class="line">│  │ │     Data Signals        │      │        Backpressure Signals        │ │ │</span><br><span class="line">│  │ │ data[<span class="number">2047</span>:<span class="number">0</span>] sop eop    │◄────▶│  type0_backpressure type1_backpressure type2_backpressure        │ │ │</span><br><span class="line">│  │ │ vld err ready           │      │  (由DUT产生，影响Sequence决策)      │ │ │</span><br><span class="line">│  │ └─────────────────────────┘      └─────────────────────────────────────┘ │ │</span><br><span class="line">│  └─────────────────────────────────────────────────────────────────────────┘ │</span><br><span class="line">│                                       │                                      │</span><br><span class="line">│                                       ▼                                      │</span><br><span class="line">│  ┌─────────────────────────────────────────────────────────────────────────┐ │</span><br><span class="line">│  │                              DUT                                        │ │</span><br><span class="line">│  │ ┌───────────────┐  ┌─────────────────┐  ┌─────────────────────────────┐ │ │</span><br><span class="line">│  │ │   Ingress     │  │ Packet Engine   │  │         Egress              │ │ │</span><br><span class="line">│  │ │ • Header解析  │  │ • 类型识别处理  │  │ • 输出缓冲控制              │ │ │</span><br><span class="line">│  │ │ • 数据验证    │  │ • Payload处理   │  │ • 反压信号生成              │ │ │</span><br><span class="line">│  │ │ • 流量控制    │  │ • 错误检测      │  │ • SOP/EOP生成               │ │ │</span><br><span class="line">│  │ └───────────────┘  └─────────────────┘  └─────────────────────────────┘ │ │</span><br><span class="line">│  └─────────────────────────────────────────────────────────────────────────┘ │</span><br><span class="line">└─────────────────────────────────────────────────────────────────────────────────┘</span><br></pre></td></tr></table></figure><hr><h3 id="⚙️-数据包级反压控制机制详图"><a href="#⚙️-数据包级反压控制机制详图" class="headerlink" title="⚙️ 数据包级反压控制机制详图"></a>⚙️ 数据包级反压控制机制详图</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">┌─────────────────────────────────────────────────────────────────────────────────┐</span><br><span class="line">│                         数据包级反压控制时序图                                   │</span><br><span class="line">├─────────────────────────────────────────────────────────────────────────────────┤</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ 时间线: ──────────────────────────────────────────────────────────────────────▶ │</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ Sequence  ┌─────┐     ┌─────┐     ┌─────┐     ┌─────┐     ┌─────┐               │</span><br><span class="line">│ 激励控制  │Pkt-A│     │Pkt-B│     │Pkt-C│     │Pkt-D│     │Pkt-E│               │</span><br><span class="line">│          └─────┘     └─────┘     └─────┘     └─────┘     └─────┘               │</span><br><span class="line">│              │           │           │           │           │                 │</span><br><span class="line">│              ▼           ▼           ▼           ▼           ▼                 │</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ Sequencer ┌─────────────────────────────────────────────────────────────────┐   │</span><br><span class="line">│ 状态管理  │ BP Status: [0,1,0] → [1,1,0] → [1,1,0] → [0,1,0] → [0,0,0]  │   │</span><br><span class="line">│          │ Queue Len: [2,5,3] → [1,6,3] → [0,7,3] → [0,6,2] → [1,5,2]  │   │</span><br><span class="line">│          │ Decision:  Send-A   Block-B    Block-C   Send-D    Send-E     │   │</span><br><span class="line">│          └─────────────────────────────────────────────────────────────────┘   │</span><br><span class="line">│              │           │           │           │           │                 │</span><br><span class="line">│              ▼           ▼           ▼           ▼           ▼                 │</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ Driver    ┌─SOP─┐     ┌─Wait─┐     ┌─Wait─┐   ┌─SOP─┐     ┌─SOP─┐             │</span><br><span class="line">│ 响应执行  │beat1│     │ ing  │     │ ing  │   │beat1│     │beat1│             │</span><br><span class="line">│          ┌┴beat2┴┐    │      │     │      │  ┌┴beat2┴┐   ┌┴beat2┴┐            │</span><br><span class="line">│          │ beat3 │    │      │     │      │  │ beat3 │   │ EOP  │            │</span><br><span class="line">│          └──EOP──┘    └──────┘     └──────┘  └──EOP──┘   └──────┘            │</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ 反压信号  type0_bp:  ────────┬─────────────────────────┬─────────────          │</span><br><span class="line">│ (来自DUT)                   │  ████████████████████  │                       │</span><br><span class="line">│                             └─────────────────────────┘                       │</span><br><span class="line">│          type1_bp:  ─────────────┬─────────────────────────────────────        │</span><br><span class="line">│                                  │  ████████████████████████████████            │</span><br><span class="line">│                                  └─────────────────────────────────────        │</span><br><span class="line">│          type2_bp:  ─────────────────────────────────────────────────────      │</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ 关键机制说明:                                                                   │</span><br><span class="line">│ 🔹 SOP检查: 只在数据包开始时检查反压状态                                        │</span><br><span class="line">│ 🔹 传输保护: 数据包传输过程中绝不中断                                           │</span><br><span class="line">│ 🔹 Pending应用: 反压在当前数据包EOP后才生效                                     │</span><br><span class="line">│ 🔹 智能重试: 被阻塞的数据包自动重新调度                                         │</span><br><span class="line">│                                                                                 │</span><br><span class="line">│ 数据包完整性保证:                                                               │</span><br><span class="line">│ ✅ Pkt-A: Type0, 正常传输 (SOP→...→EOP)                                        │</span><br><span class="line">│ ❌ Pkt-B: Type1, 被反压阻塞，等待重试                                           │</span><br><span class="line">│ ❌ Pkt-C: Type1, 仍被阻塞，继续等待                                             │</span><br><span class="line">│ ✅ Pkt-D: Type0, 反压解除后正常传输                                             │</span><br><span class="line">│ ✅ Pkt-E: Type2, 所有反压解除，正常传输                                         │</span><br><span class="line">└─────────────────────────────────────────────────────────────────────────────────┘</span><br></pre></td></tr></table></figure><hr><h3 id="🎯-Sequence决策算法流程图"><a href="#🎯-Sequence决策算法流程图" class="headerlink" title="🎯 Sequence决策算法流程图"></a>🎯 Sequence决策算法流程图</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">┌─────────────────────────────────────────────────────────────────────────────────┐</span><br><span class="line">│                        Sequence智能决策算法                                     │</span><br><span class="line">├─────────────────────────────────────────────────────────────────────────────────┤</span><br><span class="line">│                                                                                 │</span><br><span class="line">│                              ┌─────────────┐                                   │</span><br><span class="line">│                              │ 激励请求到达 │                                   │</span><br><span class="line">│                              └──────┬──────┘                                   │</span><br><span class="line">│                                     │                                          │</span><br><span class="line">│                                     ▼                                          │</span><br><span class="line">│  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  │</span><br><span class="line">│  ┃                   SEQUENCE CONTROL CENTER                                 ┃  │</span><br><span class="line">│  ┃                     (激励控制中心)                                        ┃  │</span><br><span class="line">│  ┃                                                                           ┃  │</span><br><span class="line">│  ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────┐ ┃  │</span><br><span class="line">│  ┃ │   系统状态分析  │ │   智能决策引擎  │ │   激励策略执行  │ │ 性能优化 │ ┃  │</span><br><span class="line">│  ┃ │                 │ │                 │ │                 │ │          │ ┃  │</span><br><span class="line">│  ┃ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌──────┐ │ ┃  │</span><br><span class="line">│  ┃ │ │反压状态[<span class="number">3</span>:<span class="number">0</span>]│ │ │ │ 保守模式    │ │ │ │数据包生成   │ │ │ │自适应│ │ ┃  │</span><br><span class="line">│  ┃ │ │ type0: ●    │ │ │ │ • 低风险    │ │ │ │• Type0小包  │ │ │ │速率  │ │ ┃  │</span><br><span class="line">│  ┃ │ │ type1: ○    │ │ │ │ • 稳定优先  │ │ │ │• Type1中包  │ │ │ │调整  │ │ ┃  │</span><br><span class="line">│  ┃ │ │ type2: ●    │ │ │ └─────────────┘ │ │ │• Type2大包  │ │ │ └──────┘ │ ┃  │</span><br><span class="line">│  ┃ │ └─────────────┘ │ │ ┌─────────────┐ │ │ └─────────────┘ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ ┌─────────────┐ │ │ │ 平衡模式    │ │ │ ┌─────────────┐ │ │ ┌──────┐ │ ┃  │</span><br><span class="line">│  ┃ │ │吞吐率统计   │ │ │ │ • 负载均衡  │ │ │ │时序控制     │ │ │ │负载  │ │ ┃  │</span><br><span class="line">│  ┃ │ │Type0: <span class="number">45</span>pps │ │ │ │ • 性能优化  │ │ │ │• 发送间隔   │ │ │ │均衡  │ │ ┃  │</span><br><span class="line">│  ┃ │ │Type1: <span class="number">32</span>pps │ │ │ └─────────────┘ │ │ │• 优先级     │ │ │ └──────┘ │ ┃  │</span><br><span class="line">│  ┃ │ │Type2: <span class="number">28</span>pps │ │ │ ┌─────────────┐ │ │ └─────────────┘ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ └─────────────┘ │ │ │ 激进模式    │ │ │ ┌─────────────┐ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ ┌─────────────┐ │ │ │ • 高吞吐量  │ │ │ │错误处理     │ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ │队列状态     │ │ │ │ • 压力测试  │ │ │ │• 重试机制   │ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ │Pending[<span class="number">3</span>]   │ │ │ └─────────────┘ │ │ │• 降级策略   │ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ │[<span class="number">5</span>, <span class="number">3</span>, <span class="number">8</span>]    │ │ │                 │ │ └─────────────┘ │ │          │ ┃  │</span><br><span class="line">│  ┃ │ └─────────────┘ └─────────────────┘ └─────────────────┘ └──────────┘ ┃  │</span><br><span class="line">│  ┃ └─────────────────┘                                                      ┃  │</span><br><span class="line">│  ┃         │                           │                         │          ┃  │</span><br><span class="line">│  ┃         ▼                           ▼                         ▼          ┃  │</span><br><span class="line">│  ┃ ┌─────────────────────────────────────────────────────────────────────┐   ┃  │</span><br><span class="line">│  ┃ │                    决策输出与控制命令                                  │   ┃  │</span><br><span class="line">│  ┃ │ • 选择发送类型: Type1 (负载最轻)                                      │   ┃  │</span><br><span class="line">│  ┃ │ • 数据包大小: <span class="number">1024</span> bytes                                              │   ┃  │</span><br><span class="line">│  ┃ │ • 发送时机: 立即发送                                                   │   ┃  │</span><br><span class="line">│  ┃ │ • 优先级: 中等                                                         │   ┃  │</span><br><span class="line">│  ┃ │ • 控制命令: start_item() → 子<span class="keyword">sequence</span>调用 → finish_item()               │   ┃  │</span><br><span class="line">│  ┃ └─────────────────────────────────────────────────────────────────────┘   ┃  │</span><br><span class="line">│  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛  │</span><br><span class="line">│                                  │                                            │</span><br><span class="line">│                                  ▼                                            │</span><br><span class="line">│  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  │</span><br><span class="line">│  ┃                         SEQUENCER BRIDGE                                 ┃  │</span><br><span class="line">│  ┃                          (状态桥梁)                                       ┃  │</span><br><span class="line">│  ┃                                                                           ┃  │</span><br><span class="line">│  ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────┐ ┃  │</span><br><span class="line">│  ┃ │  反压状态跟踪   │ │  性能统计管理   │ │ Driver状态管理  │ │ 通信接口 │ ┃  │</span><br><span class="line">│  ┃ │                 │ │                 │ │                 │ │          │ ┃  │</span><br><span class="line">│  ┃ │ • BP信号监控    │ │ • 实时吞吐率    │ │ • 传输状态跟踪  │ │ • Mon→Seq │ ┃  │</span><br><span class="line">│  ┃ │ • 状态变化通知  │ │ • 延迟统计      │ │ • 完成/阻塞报告 │ │ • Drv→Seq │ ┃  │</span><br><span class="line">│  ┃ │ • 历史记录维护  │ │ • 负载均衡计算  │ │ • 错误状态反馈  │ │ • Seq→Drv │ ┃  │</span><br><span class="line">│  ┃ │ • 趋势分析      │ │ • 性能告警      │ │ • 资源使用统计  │ │ • 状态同步│ ┃  │</span><br><span class="line">│  ┃ └─────────────────┘ └─────────────────┘ └─────────────────┘ └──────────┘ ┃  │</span><br><span class="line">│  ┃         ▲                   ▲                   ▲               ▲        ┃  │</span><br><span class="line">│  ┃         │                   │                   │               │        ┃  │</span><br><span class="line">│  ┃   ┌─────┴─────┐       ┌─────┴─────┐       ┌─────┴─────┐   ┌─────┴─────┐ ┃  │</span><br><span class="line">│  ┃   │  Monitor  │       │Performance│       │  Driver   │   │  Control  │ ┃  │</span><br><span class="line">│  ┃   │ Feedback  │       │ Metrics   │       │ Feedback  │   │ Interface │ ┃  │</span><br><span class="line">│  ┃   └───────────┘       └───────────┘       └───────────┘   └───────────┘ ┃  │</span><br><span class="line">│  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛  │</span><br><span class="line">│                                  │                                            │</span><br><span class="line">│                                  ▼                                            │</span><br><span class="line">│  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  │</span><br><span class="line">│  ┃                        DRIVER RESPONSE                                   ┃  │</span><br><span class="line">│  ┃                         (响应执行)                                        ┃  │</span><br><span class="line">│  ┃                                                                           ┃  │</span><br><span class="line">│  ┃ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────┐ ┃  │</span><br><span class="line">│  ┃ │  事务接收处理   │ │ 数据包级反压控制│ │  信号驱动执行   │ │ 状态反馈 │ ┃  │</span><br><span class="line">│  ┃ │                 │ │                 │ │                 │ │          │ ┃  │</span><br><span class="line">│  ┃ │ • get_next_item │ │ • SOP反压检查   │ │ • 接口信号驱动  │ │ • 完成通知│ ┃  │</span><br><span class="line">│  ┃ │ • 事务验证      │ │ • 传输中不中断  │ │ • 时序控制      │ │ • 阻塞报告│ ┃  │</span><br><span class="line">│  ┃ │ • 类型解析      │ │ • EOP后应用BP   │ │ • clk <span class="keyword">edge</span>同步  │ │ • 错误上报│ ┃  │</span><br><span class="line">│  ┃ │ • 有效性检查    │ │ • Pending机制   │ │ • valid控制     │ │ • 统计更新│ ┃  │</span><br><span class="line">│  ┃ └─────────────────┘ └─────────────────┘ └─────────────────┘ └──────────┘ ┃  │</span><br><span class="line">│  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛  │</span><br><span class="line">│                                                                               │</span><br><span class="line">│  ┌─────────────────────────────────────────────────────────────────────────┐ │</span><br><span class="line">│  │                             INTERFACE                                   │ │</span><br><span class="line">│  │ ┌─────────────────────────┐      ┌─────────────────────────────────────┐ │ │</span><br><span class="line">│  │ │     Data Signals        │      │        Backpressure Signals        │ │ │</span><br><span class="line">│  │ │ data[<span class="number">2047</span>:<span class="number">0</span>] sop eop    │◄────▶│  type0_backpressure type1_backpressure type2_backpressure        │ │ │</span><br><span class="line">│  │ │ vld err ready           │      │  (由DUT产生，影响Sequence决策)      │ │ │</span><br><span class="line">│  │ └─────────────────────────┘      └─────────────────────────────────────┘ │ │</span><br><span class="line">│  └─────────────────────────────────────────────────────────────────────────┘ │</span><br><span class="line">│                                       │                                      │</span><br><span class="line">│                                       ▼                                      │</span><br><span class="line">│  ┌─────────────────────────────────────────────────────────────────────────┐ │</span><br><span class="line">│  │                              DUT                                        │ │</span><br><span class="line">│  │ ┌───────────────┐  ┌─────────────────┐  ┌─────────────────────────────┐ │ │</span><br><span class="line">│  │ │   Ingress     │  │ Packet Engine   │  │         Egress              │ │ │</span><br><span class="line">│  │ │ • Header解析  │  │ • 类型识别处理  │  │ • 输出缓冲控制              │ │ │</span><br><span class="line">│  │ │ • 数据验证    │  │ • Payload处理   │  │ • 反压信号生成              │ │ │</span><br><span class="line">│  │ │ • 流量控制    │  │ • 错误检测      │  │ • SOP/EOP生成               │ │ │</span><br><span class="line">│  │ └───────────────┘  └─────────────────┘  └─────────────────────────────┘ │ │</span><br><span class="line">│  └─────────────────────────────────────────────────────────────────────────┘ │</span><br><span class="line">└─────────────────────────────────────────────────────────────────────────────────┘</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h2&gt;&lt;p&gt;本文档介绍如何在UVM验证环境中正确实现monitor采集DUT输出，以及如何通过分类型backpressure机制控制数据包流。核心特性是</summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>UVM Phase 机制详解</title>
    <link href="https://sqlmaps.com/2026/08/01/UVM-Phase%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3/"/>
    <id>https://sqlmaps.com/2026/08/01/UVM-Phase%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>UVM Phase机制是验证环境执行流程的核心控制机制，通过预定义的执行阶段确保验证组件的有序初始化和运行。</p><h2 id="2-主要Phase及其作用"><a href="#2-主要Phase及其作用" class="headerlink" title="2. 主要Phase及其作用"></a>2. 主要Phase及其作用</h2><h3 id="2-1-构建阶段-Build-Phases"><a href="#2-1-构建阶段-Build-Phases" class="headerlink" title="2.1 构建阶段 (Build Phases)"></a>2.1 构建阶段 (Build Phases)</h3><pre><code class="highlight mermaid">flowchart TD    S([开始]) --&gt; A[build_phase]    A --&gt; B[connect_phase]    B --&gt; C[end_of_elaboration_phase]    C --&gt; D[start_of_simulation_phase]    D --&gt; E([结束])</code></pre><table><thead><tr><th>Phase名称</th><th>执行顺序</th><th>主要作用</th><th>典型操作</th></tr></thead><tbody><tr><td><code>build_phase</code></td><td>1</td><td>组件层次结构构建</td><td>创建子组件实例，配置对象分配</td></tr><tr><td><code>connect_phase</code></td><td>2</td><td>组件间连接建立</td><td>TLM端口连接，analysis端口绑定</td></tr><tr><td><code>end_of_elaboration_phase</code></td><td>3</td><td>环境最终调整</td><td>拓扑结构检查，最终配置参数设置</td></tr><tr><td><code>start_of_simulation_phase</code></td><td>4</td><td>仿真前准备</td><td>初始激励生成，参考模型初始化</td></tr></tbody></table><h3 id="2-2-运行阶段-Run-Phases"><a href="#2-2-运行阶段-Run-Phases" class="headerlink" title="2.2 运行阶段 (Run Phases)"></a>2.2 运行阶段 (Run Phases)</h3><pre><code class="highlight mermaid">flowchart TD    S([开始]) --&gt; A[pre_reset]    A --&gt; B[reset]    B --&gt; C[post_reset]    C --&gt; D[pre_configure]    D --&gt; E[configure]    E --&gt; F[post_configure]    F --&gt; G[main]    G --&gt; H[pre_shutdown]    H --&gt; I[shutdown]    I --&gt; J([结束])</code></pre><table><thead><tr><th>子Phase名称</th><th>执行顺序</th><th>场景说明</th><th>典型操作</th></tr></thead><tbody><tr><td><code>pre_reset</code></td><td>1</td><td>复位信号生效前准备</td><td>时钟信号启动，电源稳定模拟</td></tr><tr><td><code>reset</code></td><td>2</td><td>复位操作执行</td><td>复位信号驱动，寄存器复位值设置</td></tr><tr><td><code>post_reset</code></td><td>3</td><td>复位后稳定阶段</td><td>复位解除时序控制，状态机初始化</td></tr><tr><td><code>pre_configure</code></td><td>4</td><td>配置寄存器前准备</td><td>配置空间初始化，DUT模式设置</td></tr><tr><td><code>configure</code></td><td>5</td><td>寄存器配置阶段</td><td>写配置寄存器，模式寄存器设置</td></tr><tr><td><code>post_configure</code></td><td>6</td><td>配置后验证准备</td><td>配置回读校验，功能模式使能</td></tr><tr><td><code>main</code></td><td>7</td><td>主要测试场景执行</td><td>测试用例执行，功能覆盖率收集</td></tr><tr><td><code>pre_shutdown</code></td><td>8</td><td>结束测试前处理</td><td>最后事务完成检测，超时保护机制</td></tr><tr><td><code>shutdown</code></td><td>9</td><td>测试结束操作</td><td>关闭时钟信号，电源下电模拟</td></tr></tbody></table><h2 id="3-后处理阶段-Post-Run-Phases"><a href="#3-后处理阶段-Post-Run-Phases" class="headerlink" title="3. 后处理阶段 (Post-Run Phases)"></a>3. 后处理阶段 (Post-Run Phases)</h2><pre><code class="highlight mermaid">flowchart TD    S([开始]) --&gt; A[extract_phase]    A --&gt; B[check_phase]    B --&gt; C[report_phase]    C --&gt; D[final_phase]    D --&gt; E([结束])</code></pre><table><thead><tr><th>Phase名称</th><th>执行顺序</th><th>关键作用</th><th>典型应用场景</th></tr></thead><tbody><tr><td><code>extract_phase</code></td><td>1</td><td>数据收集与统计</td><td>覆盖率数据收集，错误计数统计</td></tr><tr><td><code>check_phase</code></td><td>2</td><td>结果验证与断言</td><td>最终状态检查，断言总结报告</td></tr><tr><td><code>report_phase</code></td><td>3</td><td>结果报告生成</td><td>生成验证报告，输出日志文件</td></tr><tr><td><code>final_phase</code></td><td>4</td><td>环境清理</td><td>内存释放，文件句柄关闭</td></tr></tbody></table><h2 id="4-执行特性说明"><a href="#4-执行特性说明" class="headerlink" title="4. 执行特性说明"></a>4. 执行特性说明</h2><ol><li><strong>自动拓扑执行</strong>：Phase按层次结构自顶向下(build)和自底向上(run)执行</li><li><strong>同步控制机制</strong>：使用<code>phase.raise_objection()/drop_objection()</code>控制执行时间</li><li><strong>超时保护</strong>：内置超时机制防止phase无限期挂起</li><li><strong>并行执行支持</strong>：run_phase及其子phase支持并行执行模式</li></ol><h2 id="5-最佳实践建议"><a href="#5-最佳实践建议" class="headerlink" title="5. 最佳实践建议"></a>5. 最佳实践建议</h2><ol><li>在build_phase使用<code>create_component</code>创建子组件</li><li>避免在connect_phase进行耗时操作</li><li>在main phase使用fork-join控制并发激励</li><li>使用phase跳转机制实现异常处理：<figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">phase<span class="variable">.jump</span>(uvm_reset_phase::get()); </span><br></pre></td></tr></table></figure></li><li>在report_phase使用<code>uvm_report_server</code>进行总结报告</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-概述&quot;&gt;&lt;a href=&quot;#1-概述&quot; class=&quot;headerlink&quot; title=&quot;1. 概述&quot;&gt;&lt;/a&gt;1. 概述&lt;/h2&gt;&lt;p&gt;UVM Phase机制是验证环境执行流程的核心控制机制，通过预定义的执行阶段确保验证组件的有序初始化和运行。&lt;/p&gt;
&lt;</summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>UVM 实用技巧</title>
    <link href="https://sqlmaps.com/2026/08/01/UVM%E5%AE%9E%E7%94%A8%E6%8A%80%E5%B7%A7/"/>
    <id>https://sqlmaps.com/2026/08/01/UVM%E5%AE%9E%E7%94%A8%E6%8A%80%E5%B7%A7/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>通用验证方法（UVM）是一种功能强大的验证方法，其设计目的是能够验证各种设计规模和设计类型。UVM 名称中的“Universal”之一层含义，是该方法能够验证宇宙中的任何事物，至少是集成电路领域的所有事物。该通用能力有价值，但也意味着 UVM 中的许多能力对特定项目可能并非必要。事实上，作者认为 UVM 中的许多功能对多数项目来说并不需要。此外，UVM 起源于其他验证方法的融合，如 OVM 和 VMM。这些渊源意味着 UVM 中有些部分是从其他方法继承而来，但在纯 UVM 测试平台中并非真正需要。本文重点定义 UVM 基类、方法和宏的一个子集，使工程师更快学习 UVM，并在使用 UVM 验证以 VHDL、Verilog 或 SystemVerilog 建模的各种类型和规模的数字设计时提高效率。您可能会惊讶地发现，要有效验证复杂设计，真正需要的 UVM 子集其实很小。</p><h1 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h1><p>通用验证方法（通常称为 UVM）的设计目的是具备验证所有类型数字逻辑设计的能力，无论设计规模大小，是 FPGA 或 ASIC 或全定制设计，还是面向控制、面向数据或面向处理器的设计。UVM 的这种通用性意味着，该方法中的一些构造和功能虽然可能对某些验证项目有用，但对大多数项目来说并非必要。UVM 的传统进一步增加了方法论的复杂性。UVM 并不是从零开始创建的。相反，UVM 的基础类库和通用测试平台架构是从其他已被证明对数字设计验证有效的方法中提取出来的。  UVM 的通用性和传统性导致了类库、方法和宏的臃肿。通常情况下，有多个类、方法或宏做着几乎相同的事情，只有细微的差别，而且往往是不明显的差别。例如，UVM 同时提供资源数据库和配置数据库。在互联网上快速搜索一下，就会发现对于哪个数据库最好，或者在这种情况下应该使用哪个数据库，或者在那种情况下应该使用哪个数据库，有很多相互矛盾的意见。冗余的另一个例子是 UVM 如何提供多种 “报告 “信息的方法。有几乎相同的报告方法，如 uvm_report_error()，也有报告宏，如 &#96;uvm_error。  面向对象编程的本质增加了 UVM 类库的复杂性。只有《UVM 类参考手册》中列出的部分类是供编写基于 UVM 的测试平台的人员使用的。这些类遵循良好的 OOP 实践，扩展并继承自其他基类。遗憾的是，《UVM 类参考手册》记录了所有这些类（这是应该的），但手册并没有明确说明哪些类是供 UVM 的最终用户在 UVM 测试平台中使用的，哪些类是供 UVM 方法内部使用的。  本文的目的是通过在存在冗余的情况下提出优先选择，并明确哪些类是供 UVM 最终用户使用的，从而简化学习和采用 UVM 的过程。我们将说明，几乎所有验证项目都可以通过 UVM 类、方法和宏的简单子集来实现。这种 “UVM-light “子集将有助于使 UVM 更容易学习、更容易维护、更容易重复使用，并且不易出现编码错误或非理想的编码风格。</p><h1 id="历史与发展"><a href="#历史与发展" class="headerlink" title="历史与发展"></a>历史与发展</h1><p>UVM 在数字逻辑验证方面拥有悠久而丰富的历史，其中包括超过 15 年的组织有序的文档化方法，以及更多年的公司特定临时方法。vAdvisor, eRm, RVM, VMM, AVM, URM 和 OVM 等成熟的验证方法都对 UVM 所使用的验证方法做出了贡献。虽然这些方法学都有一个共同的目标，即验证数字逻辑设计，但这些方法学往往采用截然不同的方法来实现这一目标。本文无意提供这些遗产的细节，而是要强调这些遗产影响了 UVM 中存在的臃肿和冗余。  作为起点，UVM 开发委员会在很大程度上借鉴了开放验证方法（OVM）的方法来构建验证测试平台。事实上，UVM 的第一个初步版本 UVM 1.0EA （”EA “代表 “早期采用者”）于 2010 年发布，主要是对 OVM 的直接移植，只有少量改动或添加。UVM 从这个早期采用者版本迅速发展，增加了来自 VMM 的功能（如寄存器层），以及来自其他文档和临时方法的成熟验证概念。UVM 1.0 版本在 1.0EA 版本发布 9 个月后发布，仅 6 个月后，UVM 1.1 版本于 2011 年 6 月发布。在这短短约 15 个月的时间里，UVM 已经发展成与 OVM 截然不同的版本，尽管两者的传承非常明显。  在接下来的三年中，UVM 1.1 有了一些小的更新，但总体而言，并没有重大的进化变化。UVM 的下一次重大变化发生在 2014 年 6 月，UVM 1.2 发布。UVM 1.2 为 UVM 增加了几项实质性的新功能，本文稍后将讨论其中的一些功能。演变尚未完成。UVM 目前正处于成为 IEEE 标准（指定为 IEEE P1800.2）的早期阶段，在这一过程中很可能会有更多的发展。  从 OVM 的起点到 UVM 1.1，再到现在的 UVM 1.2，这种快速发展是 UVM 变得臃肿的主要原因。随着 UVM 的发展，新的测试平台架构和测试编写方法已被添加到 UVM 中，但旧的方法仍然可用。一些旧的方法论特性已被正式弃用，另一些已被修改，但旧特性的包袱仍然存在于 UVM 类库和宏的实现中，仍然在现有的 UVM 测试平台和验证知识产权（VIP）中使用，并且仍然出现在书籍、论文和培训课程中。UVM 的演进过程导致编写 UVM 测试平台的方法既有旧的，也有新的。  如前所述，本文的目的是将这些多余的包袱搬到柜子里，并展示一个简单的 UVM 类、方法和宏子集，它几乎可以处理所有的验证项目。这个推荐子集基于 UVM 1.2，但只使用向后兼容 UVM 1.1 的构造。</p><h1 id="我们撰写本文的方法"><a href="#我们撰写本文的方法" class="headerlink" title="我们撰写本文的方法"></a>我们撰写本文的方法</h1><p>本文从测试编写人员、环境编写人员和序列编写人员这三个角度来研究 UVM。注意：这是一篇“如何使用”的论文，而不是“如何编写”的论文！我们不会在本文中教授如何编写 UVM 测试、驱动程序、监视器和记分板，也不讨论 UVM 结构的定义、语法和语义。我们将重点放在为大多数验证项目编写有效的 UVM 测试、环境和激励所真正需要的 UVM 结构上。  UVM 测试平台可分为三个主要部分：测试、环境和序列（刺激）。UVM 的结构使不同的工程师可以专注于编写测试平台的不同部分，而对其他部分知之甚少。在本文中，我们将通过首先考虑一个简单但完整的 UVM 测试、环境和序列来研究 “用什么”。我们将展示在这个简单的 UVM 验证项目中，测试编写器、环境编写器和序列编写器需要确切了解哪些 UVM 结构。然后，我们将探讨几种高级验证情况，并讨论处理这些更困难的测试平台所需的其他 UVM 结构。  虽然本文的重点是简单和更高级的 UVM 验证需要哪些 UVM 结构，但我们也将讨论一些不需要的结构。不过，对不必要构造的讨论并不全面。也许我们可以用另一种简单的方式来看待这份 UVM 实用子集指南：如果某个构造没有列在推荐子集中，那么您可能并不需要它。  不需要的 UVM 结构体一般分为以下四类中的一类或几类：<br>1）该结构体是 UVM 的 OVM 传统遗留下来的，但已被更受欢迎的 UVM 结构体所取代；<br>2）该结构体与我们推荐的 UVM 子集中的结构体冗余（在这种情况下，我们选择我们认为最简单或最通用的结构体）；<br>3）该结构体仅对少数罕见的验证需求有用，并非绝大多数项目需要；<br>4）该结构体并非面向 UVM 最终用户，而是用于 UVM 方法的内部实现。</p><h1 id="测试编写指南"><a href="#测试编写指南" class="headerlink" title="测试编写指南"></a>测试编写指南</h1><p>测试编写负责使用可用的环境和序列来指定刺激和结果检查，以验证被测设备（DUT）的特定功能。UVM 的设置使测试编写者无需了解太多环境或 UVM 本身的底层细节，就能指定有用的测试。从测试编写者的角度来看，UVM 环境主要是一个黑盒子。在本节中，我们将讨论交给测试编写者的具体任务，并说明测试编写者需要哪些 UVM 结构。</p><h2 id="连接到-DUT"><a href="#连接到-DUT" class="headerlink" title="连接到 DUT"></a>连接到 DUT</h2><ul><li><p>目标</p><ul><li>将基于类的 UVM 测试平台与顶层模块中的 DUT 连接起来</li><li>使用 SystemVerilog 接口传递“虚拟接口”到 UVM 层次</li></ul></li><li><p>顶层模块操作步骤</p><ol><li>实例化接口与 DUT，并完成端口连接</li><li>通过 uvm_config_db::set() 将虚拟接口句柄写入配置数据库</li><li>调用 run_test() 启动 UVM</li></ol></li><li><p>set() 参数说明</p><ul><li>第1参：null（作用域对象）</li><li>第2参：”uvm_test_top”（顶层测试实例路径）</li><li>第3参：”DUT_IF”（字段名，唯一标识某接口）</li><li>第4参：虚拟接口句柄（接口实例）</li></ul></li><li><p>多接口场景</p><ul><li>为每个接口选择唯一“字段名”，按需多次 set()</li><li>建议统一命名规范：如 “AXI_IF”、”GPIO_IF”、”DBG_IF”</li></ul></li><li><p>在 test&#x2F;env 中获取</p><ul><li>使用 uvm_config_db::get(this, “”, “DUT_IF”, m_env_cfg.dut_if)</li><li>失败时报告 <code>uvm_error/</code>uvm_fatal，避免空句柄</li></ul></li><li><p>运行流程</p><ul><li>run_test() 根据 +UVM_TESTNAME 创建测试实例并驱动各阶段</li><li>接口 set() 与 run_test() 顺序如上保持不变</li></ul></li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">*&gt; <span class="keyword">module</span> test_top（修正端口连接与缩进）</span><br><span class="line"><span class="keyword">module</span> test_top;</span><br><span class="line">  <span class="keyword">import</span> uvm_pkg::*;</span><br><span class="line">  <span class="keyword">import</span> my_test_pkg::*;</span><br><span class="line"></span><br><span class="line">  my_dut_interface my_dut_if();</span><br><span class="line">  my_dut_rtl      my_dut(<span class="variable">.if</span>(my_dut_if));</span><br><span class="line"></span><br><span class="line">  <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    uvm_config_db <span class="variable">#(virtual my_dut_interface)::set(null, &quot;uvm_test_top&quot;, &quot;DUT_IF&quot;, my_dut_if)</span>;</span><br><span class="line">    run_test();</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endmodule</span></span><br></pre></td></tr></table></figure><p>导入 uvm_pkg 包是所有 UVM 测试平台的标准配置。UVM 环境的代码通常包含在一个或多个用户定义包中（本例中为 my_test_pkg）。导入该用户定义包以及测试平台接口（my_dut_interface）的实例化和连接都是标准的 SystemVerilog 编程。当我们使用 uvm_config_db 数据库将虚拟接口句柄传递给 UVM 测试（并最终传递到环境中）时，UVM 本身在这个顶层模块中的使用就开始发挥作用了。</p><p>uvm_config_db 数据库是一个参数化类，其中一个参数用于表示传入数据库的对象类型–在本例中是 my_dut_interface 类型的虚拟接口。uvm_config_db 类包含一个名为 set 的静态方法。测试编写者只需要知道调用该方法的语法，而不需要知道数据库的实现。在顶层，set() 方法的前两个参数始终分别为 null 和 “uvm_test_top”。在 UVM 中，”uvm_test_top” 始终代表顶层测试的实例名称。第三个参数是数据库中的 “字段名”，是一个字符串，用于识别 UVM 测试中的特定接口（本例中为 “DUT_IF”）。大型验证项目通常会使用多个接口将 UVM 测试平台与设计连接起来。每个接口在数据库中都有一个唯一的字段名。最后一个参数是接口实例的名称。实例名称被称为该实例的虚拟接口句柄。环境写入程序将使用前三个参数的组合，从配置数据库中获取虚拟接口的信息。</p><p>run_test() 方法用于启动 UVM 运行。它将创建一个顶级测试类实例（在命令行中通过 +UVM_TESTNAME&#x3D;<testname> 指定），并相应运行其方法。为测试平台和 DUT 之间使用的每个接口创建一个实例，并使用 set() 调用通过 uvm_config_db 将它们传递到测试中，然后使用 run_test()启动 UVM，这就是测试编写者在顶层模块中启动 UVM 测试所需要做的全部工作。</p><h2 id="UVM-test"><a href="#UVM-test" class="headerlink" title="UVM test"></a>UVM test</h2><p>UVM test 有几个基本职责：(1)从配置数据库获取虚拟接口句柄 (2)实例化 UVM 环境 (3)使用配置数据库将虚拟接口句柄和其他信息传递给环境 (4)实例化并启动测试用例所需的任何序列 (5)管理阶段异议，确保测试成功完成。<br>测试必须在工厂注册，并且必须实现 build_phase() 和 run_phase() 方法。它还可以选择实现其他阶段方法，但这些方法通常不是实现有效测试所必需的。以下可视为 UVM 测试的模板：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">*&gt; UVM test 模板（排版优化）</span><br><span class="line"><span class="keyword">class</span> my_test <span class="keyword">extends</span> uvm_test;</span><br><span class="line">  `uvm_component_utils(my_test)</span><br><span class="line"></span><br><span class="line">  my_env            m_env;</span><br><span class="line">  my_env_config_obj m_env_cfg;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;my_test&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    ...</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    ...</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p><code>uvm_component_utils</code> 宏用于将测试类注册到工厂中，以便在顶层模块中调用 run_test()，创建并运行该测试实例。UVM 提供的工厂注册宏的优势是您无需关心在 UVM 工厂中注册类的细节。只需在测试中首先调用宏，并将测试类名称作为参数即可。注意，宏调用行尾不加分号。</p><p>所有 UVM 组件的类 new() 构造函数都是一样的。new() 的参数是默认值，当组件被工厂实例化时，这些参数可能（而且很可能）被重写。不过，由于测试是通过调用 run_test()（如例 1 所示）实例化的，因此将使用其默认值。因此，我们将名称指定为类的名称（以便于识别），并将 null 指定为父类（因为 uvm_test 位于 UVM 层次结构的顶层）。</p><h2 id="实例化和设置环境"><a href="#实例化和设置环境" class="headerlink" title="实例化和设置环境"></a>实例化和设置环境</h2><p>test使用 build_phase 来实例化和配置环境。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">*&gt; build_phase 片段（排版与对齐）</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">  m_env_cfg = my_env_config_obj::type_id::create(<span class="string">&quot;m_env_cfg&quot;</span>);</span><br><span class="line">  m_env     = my_env::type_id::create(<span class="string">&quot;my_env&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!uvm_config_db<span class="variable">#(virtual my_dut_interface)::get(this, &quot;&quot;, &quot;DUT_IF&quot;, m_env_cfg.dut_if))</span></span><br><span class="line">    `uvm_error(<span class="string">&quot;TEST&quot;</span>, <span class="string">&quot;Failed to get virtual interface in test&quot;</span>)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 设置 m_env_cfg 的其他方面</span></span><br><span class="line">  uvm_config_db<span class="variable">#(my_env_config_obj)::set(this, &quot;my_env&quot;, &quot;m_env_cfg&quot;, m_env_cfg)</span>;</span><br><span class="line"><span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><p>UVM 对象和组件是使用工厂 create() 方法构造的，而不是使用传统的类 new() 构造函数。测试编写者只需知道 create() 方法的使用语法。它是一个静态方法调用，静态路径由被构造类的类型名和静态 type_id 句柄组成。从 uvm_object 基类扩展而来的类的 create() 方法需要一个参数，即名称字符串。从 uvm_component 基类扩展而来的类的 create() 方法需要两个参数，一个是名称字符串，另一个是组件句柄，该组件将包含正在创建的组件实例。第二个参数始终是这个–被创建的组件存在于调用 create() 方法的组件中。<br>使用配置对象 my_env_config_obj 只是一种方便的机制，它允许将环境的所有信息封装在一个对象中，从而只需调用一次 uvm_config_db 就能将信息传递给环境。配置对象本身只是 uvm_object 的一个扩展，因此它和其他 uvm_object 一样，通过 &#96;uvm_object_utils 宏创建并在工厂注册。<br>为了最大限度地提高重用性，我们建议 UVM 层次结构中的每一层都应从其父层获取配置信息，并将信息下传给下一层。<br>env本身只是一个 UVM 组件，因此它是由工厂创建的，就像其他组件一样。实例化和配置环境等基本操作通常在 “base test “中完成，然后对其进行扩展，以便针对特定测试目标进行额外定制。在这种情况下，我们可以扩展基础测试，并使用工厂实例化不同的环境。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 扩展测试</span><br><span class="line"><span class="keyword">class</span> my_extended_test <span class="keyword">extends</span> my_test;</span><br><span class="line">  `uvm_component_utils(my_extended_test)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    my_env::type_id::set_type_override(my_env2::get_type()); <span class="comment">// optionally override type of my_env_cfg object</span></span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);  <span class="comment">// optionally make additional changes to my_env_cfg object</span></span><br><span class="line">  <span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><p>关于扩展测试，有几点需要注意：在调用 super.build_phase() 之前，先在 build_phase() 中完成工厂重载，这样在创建环境之前就生效（如重载配置对象，也同理）。虽然类型重写更常见，但 UVM 工厂也可对特定实例进行重写。其次，我们在扩展测试中调用了 super.build_phase()，但在基础测试中不要这样做。UVM 一般规则如下：<br><strong>切勿在从 UVM 库基类扩展的组件中调用 super.build_phase()。</strong></p><h2 id="启动序列"><a href="#启动序列" class="headerlink" title="启动序列"></a>启动序列</h2><p>除了设置env外，test还主要负责在 UVM 中启动特定的测试sequences，以定义实际执行的行为。序列本身将由序列编写器编写，但由测试编写器来启动它们。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 在 test 中启动序列（修正 <span class="number">32</span>&#x27;h 字面量与缩进）</span><br><span class="line"><span class="keyword">class</span> my_extended_test <span class="keyword">extends</span> my_test;</span><br><span class="line">  `uvm_component_utils(my_extended_test)</span><br><span class="line">  ...</span><br><span class="line">  <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    ...</span><br><span class="line">    my_seq seq = my_seq::type_id::create(<span class="string">&quot;seq&quot;</span>);</span><br><span class="line">    <span class="comment">// optionally randomize sequence</span></span><br><span class="line">    <span class="keyword">assert</span>(seq<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123; src_addr == <span class="number">32&#x27;h0100_0800</span>; xfer_size == <span class="number">128</span>; &#125;);</span><br><span class="line">    seq<span class="variable">.start</span>(m_env<span class="variable">.m_agent</span><span class="variable">.m_sequencer</span>);</span><br><span class="line">    ...</span><br><span class="line">  <span class="keyword">endtask</span></span><br></pre></td></tr></table></figure><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 启动虚拟序列（修正引号样式）</span><br><span class="line"><span class="keyword">class</span> my_virtual_test <span class="keyword">extends</span> my_test;</span><br><span class="line">  `uvm_component_utils(my_extended_test)</span><br><span class="line">  ...</span><br><span class="line">  <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    ...</span><br><span class="line">    my_vseq virt_seq = my_seq::type_id::create(<span class="string">&quot;virt_seq&quot;</span>);</span><br><span class="line">    virt_seq<span class="variable">.init</span>(<span class="variable">.bus_seqr</span>(m_env<span class="variable">.m_agent1</span><span class="variable">.m_sequencer</span>),</span><br><span class="line">                  <span class="variable">.gpio_seqr</span>(m_env<span class="variable">.m_agent2</span><span class="variable">.m_sequencer</span>));</span><br><span class="line">    virt_seq<span class="variable">.start</span>(<span class="literal">null</span>);</span><br><span class="line">    ...</span><br><span class="line">  <span class="keyword">endtask</span></span><br></pre></td></tr></table></figure><p><strong>不建议</strong>采用 “default sequence” 机制；建议通过配置对象传入后台序列。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 通过配置对象传入背景序列</span><br><span class="line"><span class="keyword">class</span> my_extended_test <span class="keyword">extends</span> my_test;</span><br><span class="line">`uvm_component_utils(my_extended_test)</span><br><span class="line">...  </span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);  </span><br><span class="line">my_env::type_id::set_type_override(my_env2::get_type()); </span><br><span class="line"><span class="comment">// optionally override type of my_env_cfg object  </span></span><br><span class="line"><span class="keyword">super</span><span class="variable">.build_phase</span>(phase);  </span><br><span class="line">my_bkgrnd_seq bkgrnd_seq = my_bkgrnd_seq::type_id::create(<span class="string">&quot;bkgrnd_seq&quot;</span>); </span><br><span class="line"><span class="keyword">assert</span>(bkgrnd_seq<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;burst_len == <span class="number">16</span>;&#125;); </span><br><span class="line">my_env_cfg<span class="variable">.background_seq</span> = bkgrnd_seq; </span><br><span class="line"><span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 启动虚拟序列（无需 <span class="keyword">virtual</span> sequencer 组件）</span><br><span class="line"><span class="keyword">class</span> my_virtual_test <span class="keyword">extends</span> my_test;  </span><br><span class="line">`uvm_component_utils(my_extended_test) </span><br><span class="line">...  </span><br><span class="line"><span class="keyword">task</span> run_phase(uvm_phase phase); </span><br><span class="line">...  </span><br><span class="line">my_vseq virt_seq = my_seq::type_id::create(<span class="string">&quot;virt_seq&quot;</span>); </span><br><span class="line">virt_seq<span class="variable">.init</span>(<span class="variable">.bus_seqr</span>(m_env<span class="variable">.m_agent1</span><span class="variable">.m_sequencer</span>),  </span><br><span class="line"><span class="variable">.gpio_seqr</span>(m_env<span class="variable">.m_agent2</span><span class="variable">.m_sequencer</span>));  </span><br><span class="line">virt_seq<span class="variable">.start</span>(<span class="literal">null</span>);</span><br><span class="line">... </span><br><span class="line"><span class="keyword">endtask</span></span><br></pre></td></tr></table></figure><p><strong>虚拟时序器只会增加组件间的连接和环境的复杂性</strong>，不推荐引入。</p><h2 id="Phasing-and-Objections"><a href="#Phasing-and-Objections" class="headerlink" title="Phasing and Objections"></a>Phasing and Objections</h2><p><strong>run_phase 是唯一耗时的执行阶段。</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 异议管理</span><br><span class="line"><span class="keyword">class</span> my_extended_test <span class="keyword">extends</span> my_test;</span><br><span class="line">  `uvm_component_utils(my_extended_test)</span><br><span class="line">  ...</span><br><span class="line">  <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    phase<span class="variable">.raise_objection</span>(<span class="string">&quot;Starting test&quot;</span>);</span><br><span class="line"></span><br><span class="line">    my_seq seq = my_seq::type_id::create(<span class="string">&quot;seq&quot;</span>);</span><br><span class="line">    <span class="keyword">assert</span>(seq<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123; src_addr == <span class="number">32&#x27;h0100_0800</span>; xfer_size == <span class="number">128</span>; &#125;);</span><br><span class="line">    seq<span class="variable">.start</span>(m_env<span class="variable">.m_agent</span><span class="variable">.m_sequencer</span>);</span><br><span class="line"></span><br><span class="line">    phase<span class="variable">.drop_objection</span>(<span class="string">&quot;Ending test&quot;</span>);</span><br><span class="line">  <span class="keyword">endtask</span></span><br></pre></td></tr></table></figure><p>在该阶段开始前调用 **raise_objection()**，序列完成后调用 **drop_objection()**。</p><h1 id="环境编写人员"><a href="#环境编写人员" class="headerlink" title="环境编写人员"></a>环境编写人员</h1><p>环境编写人员负责将测试生成的刺激输入被测设备（DUT），并验证被测设备对刺激的正确响应。为此，环境编写人员定义 UVM 环境（env）、代理（agent）和记分板（SCB）。</p><h2 id="UVM-Environment"><a href="#UVM-Environment" class="headerlink" title="UVM Environment"></a>UVM Environment</h2><p>如前所述，UVM env是由 UVM test 创建和配置的 UVM 组件。env将刺激驱动到 DUT 中，monitor DUT 的输入和输出，并验证 DUT 是否按预期运行。<br> UVM env封装了 UVM 测试平台的结构方面。UVM 环境包含：<br> 一个或多个agent，每个agent负责驱动 DUT 输入并monitor特定 DUT interface上的 DUT 输入和输出<br> 记分板SCB，用于验证 DUT 对刺激的响应<br> 覆盖范围收集器（可选），用于记录交易信息以进行覆盖范围分析<br> 配置组件，使测试能够设置环境和代理，以满足特定的测试要求。</p><p> 更复杂的 UVM 环境（如图 1 所示）可能包含更多组件，如多个agent和寄存器模型。本文后面的第 5.0 节 “高级示例 “将对此进行讨论。剧透警报！我们将看到，在这些更复杂的环境中，与基本 UVM 环境中使用的简单结构集相比，env编辑人员只需知道很少的 UVM 结构集即可。</p><p>例 9 展示了一个简单 UVM 环境的代码，该环境只有一个代理和记分牌。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 简单环境（缩进与对齐）</span><br><span class="line"><span class="keyword">class</span> my_env <span class="keyword">extends</span> uvm_env;</span><br><span class="line">  `uvm_component_utils(my_env)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line">  my_agent      agent;</span><br><span class="line">  my_scoreboard scoreboard;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    agent      = my_agent::type_id::create(<span class="string">&quot;agent&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    scoreboard = my_scoreboard::type_id::create(<span class="string">&quot;scoreboard&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">endfunction</span>: build_phase</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> connect_phase(uvm_phase phase);</span><br><span class="line">    agent<span class="variable">.dut_inputs_port</span><span class="variable">.connect</span>(scoreboard<span class="variable">.dut_in_imp_export</span>);</span><br><span class="line">    agent<span class="variable">.dut_outputs_port</span><span class="variable">.connect</span>(scoreboard<span class="variable">.dut_out_imp_export</span>);</span><br><span class="line">  <span class="keyword">endfunction</span>: connect_phase</span><br><span class="line"><span class="keyword">endclass</span>: my_env</span><br></pre></td></tr></table></figure><h3 id="The-Environment-Declaration-声明"><a href="#The-Environment-Declaration-声明" class="headerlink" title="The Environment Declaration 声明"></a>The Environment Declaration 声明</h3><p> 环境是一个用户定义的类，在本例中称为 my_env。环境类是从 uvm_env 基类扩展而来的，而 uvm_env 基类又是从 uvm_component 基类派生而来。UVM 组件是构成测试平台层次结构的对象，通常在仿真开始时创建，并在整个仿真过程中保持不变。</p><p> 类的顶部是所有从 uvm_component 扩展而来的类都需要的模板代码。这些代码与本文第 2.3 节讨论的一般代码相同，包括使用宏 <code>uvm_component_utils() 向工厂注册类名，以及定义类的 new() 构造函数。如上所述，使用 UVM 的自动配置和字段自动化功能没有任何好处，因此没有理由使用 </code>uvm_component_utils_begin&#x2F;end 宏来设置字段自动化。</p><h3 id="The-Environment-Build-Phase"><a href="#The-Environment-Build-Phase" class="headerlink" title="The Environment Build Phase"></a>The Environment Build Phase</h3><p>UVM build_phase 用于构建环境中包含的组件。在这个简单的例子中，这些组件是一个代理和一个记分牌。这些组件是通过前面第 2.3 节中讨论的 create() 方法构建的。关于代理和记分牌的细节将在本文后面讨论。</p><h3 id="The-Environment-Connect-Phase"><a href="#The-Environment-Connect-Phase" class="headerlink" title="The Environment Connect Phase"></a>The Environment Connect Phase</h3><p>UVM connect_phase 用于建立代理与记分板之间的连接。UVM 使用 TLM 1.0 通信协议在类对象间传递信息，其源自 SystemC 标准。主要通信协议：</p><ul><li>port&#x2F;export 对：1 对 1，用于推送 uvm_sequence_item 句柄（序列器与驱动常用）</li><li>analysis port &#x2F; analysis imp 导出：1 对多，用于广播 uvm_sequence_item 句柄（监视器常用，可同时连记分板和覆盖率收集器）</li></ul><p>TLM port和export是 UVM 基类库中定义的类。每个port和每个export都是其中一个类的对象（实例）。port或export的名称实际上就是该端口或导出对象的句柄.<br>每个port或analysis port都有一个 connect() 方法。该 connect 方法的参数是与该port 配对的相应export或 imp export。<br>在env类级别，connect() 方法是完成环境所需的唯一 UVM 结构。在例 9 中，agent包含两个analysis port，它们与SCB上的两个 imp export相连。(env编辑人员还需要了解其他 TLM 方法，以便编写驱动程序和监视器，这将在下文有关这些主题的讨论中介绍）。</p><h2 id="UVM-Agents"><a href="#UVM-Agents" class="headerlink" title="UVM Agents"></a>UVM Agents</h2><p>UVM agent是一个低级构件，与一组特定的 DUT I&#x2F;O 引脚和这些引脚的通信协议相关联。例如，DUT 的 USB 总线将有一组端口 agent。同样，AXI 总线也有一个专门针对该总线的agent。代理包含三个必要组件：sequencer、driver和monitor。此外，代理还可包含一个可选的覆盖范围收集器组件。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">*&gt; agent 声明与旋钮（修正 &#x27; 方向与排版）</span><br><span class="line"><span class="keyword">class</span> my_agent <span class="keyword">extends</span> uvm_agent;</span><br><span class="line">`uvm_component_utils(my_agent)</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line"><span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// handles for agent’s components</span></span><br><span class="line">my_sequencer          sqr;</span><br><span class="line">my_driver             drv;</span><br><span class="line">my_monitor            mon;</span><br><span class="line">my_coverage_collector cov;</span><br><span class="line">my_config             m_config;</span><br><span class="line"></span><br><span class="line"><span class="comment">// configuration knobs</span></span><br><span class="line"><span class="keyword">localparam</span> OFF = <span class="number">1&#x27;b0</span>, ON = <span class="number">1&#x27;b1</span>;</span><br><span class="line"><span class="keyword">bit</span>                      enable_coverage = OFF;         <span class="comment">// default disabled</span></span><br><span class="line">uvm_active_passive_enum  is_active       = UVM_ACTIVE;  <span class="comment">// default active</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// handles to the monitor&#x27;s analysis ports</span></span><br><span class="line">uvm_analysis_port <span class="variable">#(my_tx)</span> dut_inputs_port;</span><br><span class="line">uvm_analysis_port <span class="variable">#(my_tx)</span> dut_outputs_port;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">...</span><br><span class="line"><span class="keyword">endfunction</span>: build_phase</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> connect_phase(uvm_phase phase);</span><br><span class="line">...</span><br><span class="line"><span class="keyword">endfunction</span>: connect_phase</span><br><span class="line"><span class="keyword">endclass</span>: my_agent</span><br></pre></td></tr></table></figure><ul><li>is_active 取值：<strong>UVM_ACTIVE &#x2F; UVM_PASSIVE</strong>。</li></ul><h3 id="The-Agent-声明"><a href="#The-Agent-声明" class="headerlink" title="The Agent 声明"></a>The Agent 声明</h3><p>代理是一个用户定义的类，本例中称为 my_agent，它是从 uvm_agent 基类扩展而来的。我们使用宏 &#96;uvm_component_utils() 在工厂注册了类名，并定义了类的 new() 构造函数，输入了它的名称和父类</p><h3 id="agent-配置按钮"><a href="#agent-配置按钮" class="headerlink" title="agent 配置按钮"></a>agent 配置按钮</h3><p>代理需要进行配置，以满足特定测试的要求。配置 UVM 组件的控件通常称为 “旋钮”。这些旋钮可能具有简单的开&#x2F;关值（通常用 1 位 0 表示关，1 位 1 表示开），或者旋钮可能被设置为一个值，如序列应生成的事务数。<br>启用覆盖范围旋钮用于配置代理收集或不收集功能覆盖范围数据。该旋钮的默认值为 OFF（禁用）。<br>is_active 旋钮用于将代理配置为主动或被动。主动代理可以监控和驱动 DUT 端口。被动代理只能监控 DUT 端口。is_active 的数据类型是 UVM 基类库中定义的枚举类型，称为 uvm_active_passive_enum，它有两个可能的枚举值：UVM_ACTIVE 和 UVM_PASSIVE。该旋钮的默认值是代理处于活动状态。<br>uvm_agent 基类中已经定义了一个 is_active 节点，但《UVM 类参考手册》中并没有将该属性作为该基类的变量之一进行记录。相反，《类参考手册》记录了一个 get_is_active() 方法，该方法可返回基类 is_active 属性的值。然而，《类参考手册》并未提供设置该旋钮的方法。由于基类 is_active 旋钮没有正式文档记录，也没有设置该变量的方法，因此作者建议明确定义一个本地 is_active 旋钮，而不是使用未记录的 is_active 基类属性。有了本地 is_active 属性，还可以明确定义默认值。从 uvm_agent 基类扩展代理没有任何功能上的理由。代理也可以从 uvm_component 基类扩展而来。</p><h3 id="The-Agent-Port-Handles"><a href="#The-Agent-Port-Handles" class="headerlink" title="The Agent Port Handles"></a>The Agent Port Handles</h3><p>环境需要将代理连接到记分板，以便记分板接收监视器捕获的 DUT 输入和输出值信息。要做到这一点，需要在代理层声明与监视器上相同端口相对应的 UVM 分析端口。其中一个端口将传递 sequence_item 对象的句柄，该对象包含该代理使用的 DUT 输入端口的值。另一个端口将传递到 sequence_item 对象的句柄，其中包含该代理使用的 DUT 输出端口的值。UVM 分析端口是基类 uvm_analysis_port 的实例。uvm_agent 基类包含一个类型参数，该参数定义了将通过端口通信的 sequence_item 类类型。在本例中，两个端口都传递 my_tx sequence_item 类型的句柄。代理端口名称 dut_inputs_port 和 dut_outputs_port 是对象句柄，将在代理的 connect_phase 中赋值。</p><h3 id="The-Agent-Build-Phase"><a href="#The-Agent-Build-Phase" class="headerlink" title="The Agent Build Phase"></a>The Agent Build Phase</h3><p>class my_agent extends uvm_agent;<br>  …<br>  function void build_phase(uvm_phase phase);<br>    if (uvm_config_db #(my_config)::get(this, “”, “test_config”, m_config)) begin  *&gt; get() succeeded<br>      this.is_active       &#x3D; this.m_config.is_active;<br>      this.enable_coverage &#x3D; this.m_config.enable_coverage;<br>    end<br>    else<br>      &#96;uvm_warning(“LAB”, “Failed to access config_db – using defaults instead.\n”)</p><pre><code>mon = my_monitor::type_id::create(&quot;mon&quot;, this);if (is_active == UVM_ACTIVE) begin  sqr = my_sequencer::type_id::create(&quot;sqr&quot;, this);  drv = my_driver::type_id::create(&quot;drv&quot;, this);endif (enable_coverage)  cov = my_coverage_collector::type_id::create(&quot;cov&quot;, this);</code></pre><p>  endfunction: build_phase</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br></pre></td><td class="code"><pre><span class="line">UVM build_phase 用于构建代理中包含的组件。在这个简单的示例中，这些组件包括：my_monitor、driver、my_sequencer、my_coverage_collector 和 my_config。这些组件是使用前面讨论过的工厂 create() 方法构建的。本文稍后将讨论这些组件的细节。</span><br><span class="line">在构建代理组件之前，构建阶段首先会尝试使用 uvm_config_db:get() 静态方法从配置数据库中获取配置对象。配置对象为测试编写程序提供了一种配置环境和代理的方法，以满足特定测试的要求，本文前面的第 2.3 节对此进行了讨论。</span><br><span class="line">在上面的例 11 中，配置对象句柄从数据库中获取并存储到 m_config 属性中。代理使用的配置 &quot;旋钮 &quot;是 is_active 和 enable_coverage 配置变量，它们作为测试类的一部分由测试编写程序设置。这些旋钮用于确定是否构建代理中的驱动程序、序列器和覆盖范围收集器组件。如果测试将代理配置为 &quot;被动&quot;，则没有驱动程序/定序器对。如果测试将代理配置为不收集覆盖率，则没有覆盖率收集器组件。</span><br><span class="line">## UVM Drivers</span><br><span class="line">UVM driver从其关联的sequencer中请求一个sequence_item对象的句柄，并将sequence_item属性中的值分配给SystemVerilog接口中的相应信号，从而驱动DUT输入。</span><br><span class="line"></span><br><span class="line">```verilog</span><br><span class="line">*&gt; UVM driver示例</span><br><span class="line">class my_driver extends uvm_driver #(my_tx);</span><br><span class="line">  `uvm_component_utils(my_driver)</span><br><span class="line"></span><br><span class="line">  function new(string name, uvm_component parent);</span><br><span class="line">    super.new(name, parent);</span><br><span class="line">  endfunction</span><br><span class="line"></span><br><span class="line">  virtual tb_if tb_vif; // virtual interface pointer</span><br><span class="line"></span><br><span class="line">  function void build_phase(uvm_phase phase);</span><br><span class="line">    if (!uvm_config_db #(virtual my_dut_interface)::get(this, &quot;&quot;, &quot;DUT_IF&quot;, tb_vif))</span><br><span class="line">      `uvm_fatal(&quot;NOVIF&quot;, &quot;Failed to get virtual interface from uvm_config_db.\n&quot;)</span><br><span class="line">  endfunction: build_phase</span><br><span class="line"></span><br><span class="line">  task run_phase(uvm_phase phase);</span><br><span class="line">    my_tx tx;</span><br><span class="line">    forever begin</span><br><span class="line">      @tb_vif.clk  // drive values synchronized to interface clock</span><br><span class="line">      seq_item_port.get_next_item(tx);  // get a transaction</span><br><span class="line">      tb_vif.operand_a &lt;= tx.operand_a;</span><br><span class="line">      tb_vif.operand_b &lt;= tx.operand_b;</span><br><span class="line">      tb_vif.opcode    &lt;= tx.opcode;</span><br><span class="line">      seq_item_port.item_done();</span><br><span class="line">    end</span><br><span class="line">  endtask: run_phase</span><br><span class="line">endclass: my_driver</span><br><span class="line">```verilog</span><br><span class="line"></span><br><span class="line">驱动程序的主要任务是在其 run_phase() 方法中执行。驱动程序通过从其关联的序列器请求 sequence_item 对象的句柄来启动对 DUT 的刺激。然后，驱动程序将这些值分配给 SystemVerilog 接口中的信号，从而驱动 DUT 输入。</span><br><span class="line"></span><br><span class="line">驱动程序通过为 SystemVerilog 接口中的变量赋值，将数值发送到 DUT。该接口针对代理，封装了 DUT 使用的特定总线协议所需的 DUT 信号。例如，如果 DUT 有一条 USB 总线和一条 AXI 总线，那么每条总线都会有一个单独的接口和相应的代理（及其驱动程序）。  为了让类定义为接口变量赋值，类需要有一个指向接口实例的指针。这个指针被称为虚拟接口。本文前面讨论的顶层模块（见第 2.1 节）将接口实例化，并将虚拟接口复制到 UVM 的配置数据库中。驱动程序使用静态 uvm_config_db::get()方法检索虚拟接口。该方法在前面的第 2.3 节中讨论过。</span><br><span class="line">### The Driver’s Run Phase</span><br><span class="line">驱动程序的真正工作发生在 UVM run_phase 阶段。通常，UVM 驱动程序被写成一个无限循环，可以使用 SystemVerilog 的 forever 循环或 while(1) 循环来实现。虽然驱动程序被编码为一个无限循环，但 run_phase 本身并不会一直运行到无穷大。测试编写程序使用 UVM 的反对标志来控制 run_phase 的实际运行时间，这在本文前面已经讨论过。</span><br><span class="line">在驱动程序的运行阶段（run_phase）内，驱动程序将与 DUT 时钟和生成刺激值的 UVM 序列同步。下文将讨论这种双重同步。</span><br><span class="line"></span><br><span class="line">### driver/DUT和避免竞争</span><br><span class="line">为了协调从驱动程序到接口变量的数值传输，驱动程序使用接口中的时钟信号与 DUT 同步。这与 DUT 使用的时钟相同，用于 UVM 代理处理的特定总线协议。  在所有数字验证中，无论采用何种验证方法，测试平台都必须避免与 DUT 发生竞赛。简单地说，测试平台必须在 DUT 的时钟边沿之前足够早地驱动刺激，以便在 DUT 寄存器触发和存储输入值（设置时间）时刺激保持稳定。SystemVerilog 方法希望（但不强制）由 UVM 驱动程序和 DUT 之间的接口处理测试平台和 DUT 之间的同步。将这种同步转移到接口具有重要优势：   驱动程序代码大大简化--所有驱动程序需要做的就是为接口信号赋值，并由接口来避免与 DUT 之间的竞赛条件。   驱动程序的变体可以从用户定义的驱动程序类中扩展，而无需重复复杂的同步时序。  监控器也需要避免与 DUT 发生竞赛，仅在 DUT 输出稳定时观察 DUT 输出。  请注意，驱动程序和监控器可以直接访问虚拟接口中的信号，也可以调用接口中的任务，以进一步简化测试平台，并将细节留给接口编写者[1]。可以使用 SystemVerilog 时钟块来帮助避免竞赛，但这种结构通常与仿真不兼容，在设计驱动程序和监视器时应考虑到这一点。让这些组件调用接口任务，可以将同步机制的选择权也交给接口。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">### driver/sequence同步</span><br><span class="line">UVM 驱动程序将驱动 DUT 的值存储在 UVM sequence_item 对象中。该对象由 UVM 序列创建，其值由 UVM 序列生成。当驱动程序获取 sequence_item 句柄时，需要与序列同步。这种同步是通过一对方法（get_next_item() 和 item_done()）完成的。这些方法被定义为驱动程序 TLM 端口的一部分，该端口与相应的序列器相连。环境写入器只需知道调用 get_next_item()将阻塞驱动程序的执行，并等待序列创建 sequence_item 对象。与一个或多个序列激励发生器实际握手的复杂代码，完全由驱动程序和序列使用的 UVM 基类方法处理。图 3 展示了驱动程序与序列之间的基本握手过程。</span><br><span class="line"></span><br><span class="line">使 driver 和 sequence 同步的握手步骤是：</span><br><span class="line">1. 测试编写人员引发反对标志，并调用序列的 start()，该方法会进入序列的 body() 并在其退出前阻塞。</span><br><span class="line">2. 序列在 body() 中调用 start_item()，阻塞等待驱动请求事务。</span><br><span class="line">3. 驱动调用 seq_item_port.get_next_item() 请求事务，并在获得事务前阻塞。</span><br><span class="line">4. 序列生成值并调用 finish_item() 发送给驱动，随后阻塞等待驱动完成该事务。</span><br><span class="line">5. 驱动将事务值驱动到接口后，调用 seq_item_port.item_done() 解除序列阻塞。随后可继续步骤 2–5。</span><br><span class="line">6. 序列完成后 body() 退出，解除测试中 start() 的阻塞；测试继续，包含放弃反对标志以结束阶段。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">## UVM Monitors</span><br><span class="line">UVM 监视器观察特定接口的 DUT 输入和输出，将观察到的值捕获到一个或多个 sequence_items 中，并将这些 sequence_items 的句柄广播给其他 UVM 组件（如记分板和覆盖范围收集器）。UVM 严格规定了监视器应做的事情，但在如何实现该功能方面允许充分的灵活性--也许是灵灵活性过大，导致监视器的实现风格和如何最好地实现监视器的意见五花八门。UVM 对监控器的唯一规定是1) 监视器是代理的一部分，因此与该代理处理的特定总线协议密切相关。2）监控器是严格意义上的被动组件--监控器只能观察活动，而不能改变值。3) 监控程序同时观察 DUT 的输入和输出。尽管驱动程序知道 DUT 的驱动值，但 UVM 要求只有监控器将这些输入值传达给记分板或其他组件。之所以有这样的要求，是因为可以将代理配置为被动代理，而被动代理有一个监视器，但没有驱动程序或定序器。例 15 显示了基本 UVM 监视器的代码。</span><br><span class="line"></span><br><span class="line">class my_monitor extends uvm_monitor;  `uvm_component_utils(my_monitor)  function new(string name, uvm_component parent); super.new(name, parent); endfunction  virtual my_dut_interface tb_vif; // virtual interface  uvm_analysis_port #(my_tx) dut_inputs_port; // analysis port for DUT inputs uvm_analysis_port #(my_tx) dut_outputs_port; // analysis port for DUT outputs  function void build_phase(uvm_phase phase); dut_inputs_port = new(&quot;dut_inputs_port&quot;, this); // construct the analysis port dut_outputs_port = new(&quot;dut_outputs_port&quot;, this); // construct the analysis port if (!uvm_config_db #(virtual my_dut_interface)::get(this, &quot;&quot;, &quot;DUT_IF&quot;, tb_vif)) `uvm_fatal(&quot;NOVIF&quot;, Failed to get virtual interface from uvm_config_db.\n&quot;) endfunction: build_phase  task run_phase(uvm_phase phase);  my_tx tx_in, my_tx tx_out, tx_copy; fork // monitor DUT inputs synchronous to the interface clock forever @(tb_vif.clk) begin // create a new tx_write object for this cycle  tx_in = my_tx::type_id::create(&quot;tx_in&quot;); tx_in.operand_a = tb_vif.operand_a;</span><br><span class="line">tx_in.operand_b = tb_vif.operand_b; tx_in.opcode = tb_vif.opcode;  dut_inputs_port.write(tx_in); end  // monitor DUT outputs synchronous to the cb2 clocking block // create a tx_tmp object to reuse each pass of the loop  tx_out = my_tx::type_id::create(&quot;tx_out&quot;); // tx_out is reused each loop pass forever @(tb_vif.clk2) begin tx_out.result = tb_vif.result; tx_out.exception = tb_vif.exception; // create a copy of tx_out to send to the scoreboard  $cast(tx_copy, tx_out.clone()); dut_outputs_port.write(tx_copy); end join endtask: run_phase endclass: my_monitor</span><br><span class="line"></span><br><span class="line">### The Monitor 声明</span><br><span class="line">UVM 监视器是从 uvm_monitor 基类扩展而来的。该基类没有参数化，因此不需要重新定义参数。与所有 UVM 测试台组件一样，类名使用 `uvm_component_utils()宏向工厂注册，并且定义了类 new() 构造函数，其中包含所需的名称和父输入。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">### monitor 通信</span><br><span class="line">UVM 监视器使用 TLM 端口与记分板和覆盖率收集器通信。TLM 端口将句柄传递给 sequence_items。UVM 方法允许环境写入器决定通过 TLM 端口通信的 sequence_items 类型。最常见的类型有   同一 sequence_item 类型用于捕获 DUT 输入值和 DUT 输出值。虽然使用了相同的 sequence_item 类型，但输入和输出被捕获到不同的对象中，因为这些值是在不同的仿真时间捕获的。这就是例 15 中显示的样式。   不同的 sequence_item 类型用于捕获 DUT 输入和 DUT 输出。例如，可能会有一个 my_tx_in sequence_item 类，该类只有用于存储 DUT 输入的变量，而 my_tx_out sequence_item 类只有用于存储特定接口 DUT 输出的变量。  UVM 还允许 Environment Writer 确定监控器需要多少个通信端口，以便将信息传递给记分板和覆盖率收集器。常见的编码方式是使用两个端口，一个用于包含 DUT 输入的 sequence_item 对象句柄，另一个用于包含 DUT 输出的 sequence_item 对象句柄。例 15 中的监视器使用了两个端口。这两个端口都与 my_tx 序列项类型的句柄通信，该类型的变量可捕获 DUT 输入值和 DUT 输出值。根据协议的不同，也可以使用请求和响应项目类型，或任何合适的项目集。  这些端口是 TLM 分析端口，允许一对多连接。这样，包含 DUT 输入值的 sequence_item 对象的句柄就可以同时传递给记分板和覆盖范围收集器。uvm_analysis_port 是一个参数化的类，必须与特定的 sequence_item 类类型（本例中为 my_tx）配合使用。 端口是在监视器的 build_phase 阶段构建的。请注意，端口是使用类的 new() 构造函数而不是工厂构造的。uvm_analysis_port 基类名称没有在工厂注册，因此不能由工厂构造。也没有理由这样做。工厂的目的是允许测试编写者用一种类类型替换另一种类类型（例如，用 USB 3.0 sequence_items 替换所有 USB 2.0 sequence_items）。对于一个测试来说，改变监视器使用的端口类型是没有意义的，因此不需要工厂来构造端口。</span><br><span class="line"></span><br><span class="line">### Monitor/Interface 通信</span><br><span class="line">监控器通过读取顶层模块实例化并连接到 DUT 的接口中的变量来观察 DUT 的输入和输出值。监控器使用静态 uvm_config_db::get()方法检索指向接口的虚拟接口，与驱动程序检索虚拟接口的方式完全相同。</span><br><span class="line"></span><br><span class="line">### The Monitor’s Run Phase</span><br><span class="line">DUT 输入和输出值的实际监控在 UVM 运行阶段进行。通常情况下，输入和输出会在不同的仿真时间捕获，也可能在不同的时钟上捕获。为了与不同的时间和时钟同步，run_phase 会分叉出两个无限循环，这两个循环并行运行。与驱动程序一样，监控器也采用无限循环编码，因此只要 run_phase 在运行，监控就会一直持续。测试编写程序通过使用 UVM 的反对标志来控制 run_phase 的实际执行时间。  在这些循环的每个周期中，监控器都会创建一个 sequence_item 对象，将 DUT 值捕获到该对象中，然后使用 write() 方法将该对象的句柄广播到分析端口。写（）方法的实际功能将在分析端口所连接的每个分析 imp 导出中实现。我们将在覆盖率收集器（第 3.6 节）和记分板（第 3.7 节）组件的代码中看到写入（）方法的实现。  重要的是，监控器要为监控器循环的每次传递创建一个新的 sequence_item 对象。记分板将收到 sequence_item 对象的句柄。如果记分板保存了该句柄以便在未来某个时间进行评估，而监测仪没有为循环的每次传递创建一个新对象，则会出现问题。每次循环都会捕获新的 DUT 值。如果这些新值保存在上一循环中使用的同一对象中，记分板最终将保存多个对象句柄，这些句柄都引用同一对象，而该对象仅存储最后一次捕获的一组值。有两种编码方式可用于在每次循环中创建新的 sequence_item 对象：在每次循环开始时使用 factory create() 方法，或在每次循环结束时使用 sequence_item clone() 方法。为便于说明，例 15 中的代码展示了这两种方式，不过大多数环境编写者可能会使用其中一种方式。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">## UVM 覆盖范围收集器</span><br><span class="line">功能覆盖是验证复杂设计的一个重要方面，尤其是在使用约束随机验证时。功能覆盖是 SystemVerilog 语言不可分割的一部分，包括 covergroup、coverpoint 和 bins 定义以及 sample() 方法。UVM 并未规定在何处使用覆盖构造。它们只是 SystemVerilog 结构，可以在任何 SystemVerilog 代码中使用。尽管方法论没有强制要求，但 UVM 代理是在 UVM 测试平台中收集功能覆盖信息的理想位置。代理的监控器会观察 DUT 针对特定总线协议的输入和输出，因此可以收集针对该总线观察到的值的覆盖率。</span><br><span class="line">UVM 也没有规定应在代理的哪个位置收集覆盖。有些工程师喜欢将覆盖率作为监控器的一个组成部分。这是一种简单的方法，不需要使用 TLM 端口将值传递给覆盖率收集代码。不过，作者建议定义一个可在代理中实例化的独立覆盖率收集器组件。使用单独的组件需要更多的编码（虽然不多），但也有一些优点。覆盖率收集器组件将代理的覆盖率定义和功能封装在一个地方，而不是将覆盖率代码分散在监控器中。此外，单独的组件可以由工厂构建，这使得使用工厂定制覆盖范围以满足特定测试要求变得更加容易。</span><br><span class="line">```verilog</span><br><span class="line">*&gt; 覆盖率收集器</span><br><span class="line">class my_coverage_collector extends uvm_subscriber #(my_tx);</span><br><span class="line">  my_tx tx;  *&gt; the transaction object on which value changes will be covered</span><br><span class="line"></span><br><span class="line">  covergroup dut_inputs;</span><br><span class="line">    option.per_instance = 1;  *&gt; track coverage for each instance</span><br><span class="line">    Opc: coverpoint tx.opcode;</span><br><span class="line">    Opa: coverpoint tx.operand_a;</span><br><span class="line">    Opb: coverpoint tx.operand_b;</span><br><span class="line">  endgroup</span><br><span class="line"></span><br><span class="line">  `uvm_component_utils(my_coverage_collector)</span><br><span class="line"></span><br><span class="line">  function new(string name, uvm_component parent);</span><br><span class="line">    super.new(name, parent);</span><br><span class="line">    dut_inputs = new();  *&gt; construct the covergroup</span><br><span class="line">  endfunction: new</span><br><span class="line"></span><br><span class="line">  function void write(my_tx t);</span><br><span class="line">    tx = t;              *&gt; copy transaction handle received from the monitor</span><br><span class="line">    dut_inputs.sample(); *&gt; collect coverage</span><br><span class="line">  endfunction: write</span><br><span class="line"></span><br><span class="line">  function void report_phase(uvm_phase phase);</span><br><span class="line">    `uvm_info(&quot;DEBUG&quot;,</span><br><span class="line">              $sformatf(&quot;\n\n Coverage for instance %s = %2.2f%%\n\n&quot;,</span><br><span class="line">                        this.get_full_name(), this.dut_inputs.get_inst_coverage()),</span><br><span class="line">              UVM_HIGH)</span><br><span class="line">  endfunction: report_phase</span><br><span class="line">endclass: my_coverage_collector</span><br></pre></td></tr></table></figure><h2 id="UVM-Scoreboards"><a href="#UVM-Scoreboards" class="headerlink" title="UVM Scoreboards"></a>UVM Scoreboards</h2><p>UVM 中记分板的主要作用是验证实际 DUT 输出是否与预测输出值相匹配。UVM 规定这种验证功能是 UVM 环境的一部分，但这也是方法论的终点。如何预测预期结果和验证 DUT 输出是 SystemVerilog 编程的一部分，完全取决于环境编写者的创造力。这种灵活性使 UVM 能够真正通用于处理任何规模和类型的设计，但也导致 UVM “专家 “的建议存在很大差异。本文提出了一些 UVM 记分牌的指导原则，这些原则遵循著名的 KISS 原则–”保持简单，愚蠢”。<br>KISS 准则规定，记分板功能应封装到在环境级实例化的 UVM 组件中。环境提供与一个或多个代理的连接，使记分板组件能够访问这些代理观察到的 DUT 输入和输出值。测试编写者可配置环境，包括配置记分板组件，以满足特定测试的需要。当记分板功能被封装到 UVM 组件中时，记分板可以更容易地重复使用，并可扩展以添加特定测试功能。UVM 工厂可以将标准记分板组件与扩展版本互换。这种 KISS 准则还可以验证更复杂的设计，利用多个环境来验证设计的不同部分。<br>相对简单的记分牌功能可直接在记分板组件（扁平层次结构）中编码。扁平化的计分板组件通常包含一个预测预期结果的方法和一个将预测结果与实际 DUT 输出进行比较的方法。记分板组件内部也可以有层次结构。预测算法和验证算法可在与记分板实例化的类中定义。这些子块也可配置，并可在工厂注册，以实现工厂创建和覆盖功能。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">*&gt; 记分板声明与基本结构</span><br><span class="line">`uvm_analysis_imp_decl(_verify_outputs)</span><br><span class="line"><span class="keyword">class</span> my_scoreboard <span class="keyword">extends</span> uvm_subscriber <span class="variable">#(my_tx)</span>;</span><br><span class="line">  `uvm_component_utils(my_scoreboard)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line">  uvm_analysis_imp_verify_outputs <span class="variable">#(my_tx, my_scoreboard)</span> dut_out_imp_export;</span><br><span class="line">  mailbox <span class="variable">#(my_tx)</span> expected_fifo = <span class="keyword">new</span>; <span class="comment">// SystemVerilog mailbox for my_tx handles</span></span><br><span class="line">  <span class="keyword">int</span> num_passed, num_failed; <span class="comment">// score cards</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    dut_out_imp_export = <span class="keyword">new</span>(<span class="string">&quot;dut_out_imp_export&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// implement the write() method called by the monitor for observed DUT inputs;</span></span><br><span class="line">  <span class="comment">// predict what the DUT results should be for a set of input values</span></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> write(my_tx t);</span><br><span class="line">    my_tx expected_tx;</span><br><span class="line">    <span class="built_in">$cast</span>(expected_tx, t<span class="variable">.clone</span>());</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">case</span> (t<span class="variable">.opcode</span>)</span><br><span class="line">      ADD: expected_tx<span class="variable">.result</span> = t<span class="variable">.operand_a</span> + t<span class="variable">.operand_b</span>;</span><br><span class="line">      SUB: expected_tx<span class="variable">.result</span> = t<span class="variable">.operand_a</span> - t<span class="variable">.operand_b</span>;</span><br><span class="line">      <span class="comment">// ... 其他操作码</span></span><br><span class="line">    <span class="keyword">endcase</span></span><br><span class="line">    </span><br><span class="line">    expected_tx<span class="variable">.exception</span> = ...;  <span class="comment">// 设置异常标志</span></span><br><span class="line">    expected_fifo<span class="variable">.put</span>(expected_tx);</span><br><span class="line">  <span class="keyword">endfunction</span>: write</span><br><span class="line"></span><br><span class="line">  <span class="comment">// implement the write() method called by the monitor for actual DUT outputs;</span></span><br><span class="line">  <span class="comment">// compare the DUT outputs to the predicted results</span></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> write_verify_outputs(my_tx t);</span><br><span class="line">    ...</span><br><span class="line">  <span class="keyword">endfunction</span>: write_verify_outputs</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> report_phase(uvm_phase phase);</span><br><span class="line">    ...</span><br><span class="line">  <span class="keyword">endfunction</span>: report_phase</span><br><span class="line"><span class="keyword">endclass</span>: my_scoreboard</span><br></pre></td></tr></table></figure><p>这个小例子使用了扁平化层次结构——预测与验证算法均直接编码在记分板类中。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;摘要&quot;&gt;&lt;a href=&quot;#摘要&quot; class=&quot;headerlink&quot; title=&quot;摘要&quot;&gt;&lt;/a&gt;摘要&lt;/h1&gt;&lt;p&gt;通用验证方法（UVM）是一种功能强大的验证方法，其设计目的是能够验证各种设计规模和设计类型。UVM 名称中的“Universal”之一层含义</summary>
      
    
    
    
    <category term="UVM" scheme="https://sqlmaps.com/categories/UVM/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="UVM" scheme="https://sqlmaps.com/tags/UVM/"/>
    
  </entry>
  
  <entry>
    <title>杂项学习</title>
    <link href="https://sqlmaps.com/2026/08/01/%E6%9D%82%E9%A1%B9%E5%AD%A6%E4%B9%A0/"/>
    <id>https://sqlmaps.com/2026/08/01/%E6%9D%82%E9%A1%B9%E5%AD%A6%E4%B9%A0/</id>
    <published>2026-08-01T14:12:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<hr><h2 id="mermaid-true"><a href="#mermaid-true" class="headerlink" title="mermaid: true"></a>mermaid: true</h2><h1 id="网络速率与交换容量说明"><a href="#网络速率与交换容量说明" class="headerlink" title="网络速率与交换容量说明"></a>网络速率与交换容量说明</h1><h2 id="1-112G-以太网"><a href="#1-112G-以太网" class="headerlink" title="1. 112G 以太网"></a>1. 112G 以太网</h2><ul><li>112G（Gigabit）以太网指的是网络接口或链路的物理传输速率为 112 Gbps（千兆位每秒）。</li><li>适用于高性能数据中心、主干网互联或存储网络，能满足大规模数据传输需求。</li></ul><h2 id="2-1-6T-交换容量"><a href="#2-1-6T-交换容量" class="headerlink" title="2. 1.6T 交换容量"></a>2. 1.6T 交换容量</h2><ul><li>1.6T（Terabit）通常指交换设备的总交换容量或总吞吐量为 1.6 Tbps（太比特每秒）。</li><li>表示该交换机在全线速转发情况下，理论上能够处理的最大数据流量上限。</li><li>该指标越高，设备能够支持的并发数据流越多，网络性能越强。</li></ul><h2 id="3-400G-以太网"><a href="#3-400G-以太网" class="headerlink" title="3. 400G 以太网"></a>3. 400G 以太网</h2><ul><li>聚合方式：8 × 50Gbps（PAM4）或 4 × 100Gbps（NRZ）  </li><li>计算示例：  <ul><li>8 × 50Gbps &#x3D; 400Gbps  </li><li>4 × 100Gbps &#x3D; 400Gbps</li></ul></li><li>实现方式：  <ul><li>使用 QSFP-DD &#x2F; OSFP 模块  </li><li>基于 PAM4 调制，每通道约 53.125GBd</li></ul></li></ul><h2 id="4-800G-以太网"><a href="#4-800G-以太网" class="headerlink" title="4. 800G 以太网"></a>4. 800G 以太网</h2><ul><li>聚合方式：8 × 100Gbps（PAM4）  </li><li>计算示例：  <ul><li>8 × 100Gbps &#x3D; 800Gbps</li></ul></li><li>实现方式：  <ul><li>使用 QSFP-DD800 &#x2F; OSFP800 模块  </li><li>PAM4 调制，每通道 100Gbps</li></ul></li></ul><h2 id="5-Gbps-计算方法"><a href="#5-Gbps-计算方法" class="headerlink" title="5. Gbps 计算方法"></a>5. Gbps 计算方法</h2><ul><li>总 Gbps &#x3D; 通道数 × 单通道速率 (Gbps)</li><li>示例：<ul><li>4 × 100Gbps &#x3D; 400 Gbps</li><li>8 × 50Gbps  &#x3D; 400 Gbps</li></ul></li></ul><h2 id="6-PAM4-调制简介"><a href="#6-PAM4-调制简介" class="headerlink" title="6. PAM4 调制简介"></a>6. PAM4 调制简介</h2><ul><li>PAM4 全称 4-level Pulse Amplitude Modulation  </li><li>每个符号可承载 2 bit（4 个电平）  </li><li>比特率 &#x3D; 符号率 × log₂4 &#x3D; 符号率 × 2  </li><li>示例：53.125 GBd 符号率 → 53.125 × 2 &#x3D; 106.25 Gbps  </li><li>优势：同等带宽下速率提升  </li><li>挑战：对信噪比和线性度要求更高</li></ul><h2 id="7-符号率-Symbol-Rate"><a href="#7-符号率-Symbol-Rate" class="headerlink" title="7. 符号率 (Symbol Rate)"></a>7. 符号率 (Symbol Rate)</h2><ul><li>定义：每秒钟传输的符号数，单位为波特（Baud）</li><li>计算：符号率 &#x3D; 比特率 (bit&#x2F;s) ÷ 每符号承载的比特数</li><li>示例：<ul><li>NRZ（二电平）：1 bit&#x2F;符号，100 Gbps → 100 GBd  </li><li>PAM4（四电平）：2 bit&#x2F;符号，100 Gbps → 50 GBd</li></ul></li></ul><h2 id="8-NRZ-调制简介"><a href="#8-NRZ-调制简介" class="headerlink" title="8. NRZ 调制简介"></a>8. NRZ 调制简介</h2><ul><li>NRZ 全称 Non‑Return‑to‑Zero  </li><li>每个符号承载 1 bit  </li><li>符号率 &#x3D; 比特率（bit&#x2F;s）  </li><li>示例：100 Gbps → 100 GBd  </li><li>优势：实现简单，信号处理复杂度低  </li><li>挑战：带宽利用率低，对直流分量敏感</li></ul><h2 id="9-网络片上互连-NoC-路由与交换芯片"><a href="#9-网络片上互连-NoC-路由与交换芯片" class="headerlink" title="9. 网络片上互连 (NoC) 路由与交换芯片"></a>9. 网络片上互连 (NoC) 路由与交换芯片</h2><ul><li>定义：芯片内部的高性能互连网络，用于多核处理器或 SoC 中核间数据通信  </li><li>拓扑结构：Mesh、Torus、Ring、Fat‑Tree 等常用布局  </li><li>路由算法：<ul><li>XY 算法、Turn 模型、自适应路由等</li></ul></li><li>交换架构：<ul><li>分布式路由器节点  </li><li>虚拟通道 (VC) 支持无阻塞交换</li></ul></li><li>关键指标：<ul><li>吞吐量：多通道并行传输带宽  </li><li>延迟：单跳延迟及端到端时延  </li><li>能耗：pJ&#x2F;bit 级功耗</li></ul></li><li>典型实例：ARM AMBA CHI NoC、Intel Mesh NoC、Tilera Tile 系列芯片</li></ul><h2 id="10-NoC-常用拓扑结构"><a href="#10-NoC-常用拓扑结构" class="headerlink" title="10. NoC 常用拓扑结构"></a>10. NoC 常用拓扑结构</h2><ul><li>Mesh（网格）  </li><li>Torus（环面）  </li><li>Ring（环）  </li><li>Fat‑Tree（胖树）</li></ul><h3 id="10-1-Mesh-拓扑（2×2-示例）"><a href="#10-1-Mesh-拓扑（2×2-示例）" class="headerlink" title="10.1 Mesh 拓扑（2×2 示例）"></a>10.1 Mesh 拓扑（2×2 示例）</h3><?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a xlink:href="https://github.com/plantuml/plantuml/issues/2495"><text x="10" y="30" font-family="sans-serif" font-size="14" fill="blue" text-decoration="underline">This feature has been suppressed</text></a></svg><h3 id="10-2-Torus-拓扑（2×2-示例）"><a href="#10-2-Torus-拓扑（2×2-示例）" class="headerlink" title="10.2 Torus 拓扑（2×2 示例）"></a>10.2 Torus 拓扑（2×2 示例）</h3><?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a xlink:href="https://github.com/plantuml/plantuml/issues/2495"><text x="10" y="30" font-family="sans-serif" font-size="14" fill="blue" text-decoration="underline">This feature has been suppressed</text></a></svg><h3 id="10-3-Ring-拓扑（4-节点示例）"><a href="#10-3-Ring-拓扑（4-节点示例）" class="headerlink" title="10.3 Ring 拓扑（4 节点示例）"></a>10.3 Ring 拓扑（4 节点示例）</h3><?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a xlink:href="https://github.com/plantuml/plantuml/issues/2495"><text x="10" y="30" font-family="sans-serif" font-size="14" fill="blue" text-decoration="underline">This feature has been suppressed</text></a></svg><h3 id="10-4-Fat‑Tree-拓扑（2-核心、2-聚合、2-接入）"><a href="#10-4-Fat‑Tree-拓扑（2-核心、2-聚合、2-接入）" class="headerlink" title="10.4 Fat‑Tree 拓扑（2 核心、2 聚合、2 接入）"></a>10.4 Fat‑Tree 拓扑（2 核心、2 聚合、2 接入）</h3><?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a xlink:href="https://github.com/plantuml/plantuml/issues/2495"><text x="10" y="30" font-family="sans-serif" font-size="14" fill="blue" text-decoration="underline">This feature has been suppressed</text></a></svg>]]></content>
    
    
      
      
    <summary type="html">&lt;hr&gt;
&lt;h2 id=&quot;mermaid-true&quot;&gt;&lt;a href=&quot;#mermaid-true&quot; class=&quot;headerlink&quot; title=&quot;mermaid: true&quot;&gt;&lt;/a&gt;mermaid: true&lt;/h2&gt;&lt;h1 id=&quot;网络速率与交换容量说明&quot;&gt;&lt;a hr</summary>
      
    
    
    
    <category term="笔记" scheme="https://sqlmaps.com/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="笔记" scheme="https://sqlmaps.com/tags/%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>VCS 模式配置与使用指南</title>
    <link href="https://sqlmaps.com/2026/08/01/VCS%E6%A8%A1%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%8E%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/"/>
    <id>https://sqlmaps.com/2026/08/01/VCS%E6%A8%A1%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%8E%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</id>
    <published>2026-08-01T14:11:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><ul><li><a href="#%E7%AE%80%E4%BB%8B">简介</a></li><li><a href="#%E6%A8%A1%E5%BC%8F%E6%96%87%E4%BB%B6%E8%AF%AD%E6%B3%95">模式文件语法</a><ul><li><a href="#%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84">基本结构</a></li><li><a href="#%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9%E8%AF%A6%E8%A7%A3">配置选项详解</a></li><li><a href="#%E9%94%99%E8%AF%AF%E5%92%8C%E8%AD%A6%E5%91%8A%E5%A4%84%E7%90%86">错误和警告处理</a></li></ul></li><li><a href="#%E5%B8%B8%E7%94%A8%E6%A8%A1%E5%BC%8F%E7%A4%BA%E4%BE%8B">常用模式示例</a><ul><li><a href="#%E9%80%9A%E7%94%A8%E4%BB%A3%E7%A0%81%E6%A8%A1%E5%BC%8F">通用代码模式</a></li><li><a href="#ic%E8%AE%BE%E8%AE%A1%E9%AA%8C%E8%AF%81%E4%B8%93%E7%94%A8%E6%A8%A1%E5%BC%8F">IC设计验证专用模式</a></li></ul></li><li><a href="#%E5%B7%A5%E5%85%B7%E4%B8%8E%E8%84%9A%E6%9C%AC">工具与脚本</a><ul><li><a href="#%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8pat%E6%A8%A1%E5%BC%8F%E6%96%87%E4%BB%B6">如何调用PAT模式文件</a></li><li><a href="#%E6%B3%A8%E9%87%8A%E6%A3%80%E6%9F%A5%E8%84%9A%E6%9C%AC">注释检查脚本</a></li></ul></li><li><a href="#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5">最佳实践</a></li><li><a href="#%E5%AE%8C%E6%95%B4%E7%A4%BA%E4%BE%8B">完整示例</a></li></ul><hr><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>VCS（版本控制系统）模式文件是一种定义如何识别和处理代码中特定模式的配置文件。这些模式可用于代码审查、文档生成、质量检查和IC设计验证等自动化任务。本指南详细介绍VCS配置模式的语法和使用方法。</p><hr><h2 id="模式文件语法"><a href="#模式文件语法" class="headerlink" title="模式文件语法"></a>模式文件语法</h2><h3 id="基本结构"><a href="#基本结构" class="headerlink" title="基本结构"></a>基本结构</h3><p>VCS模式文件使用类似Perl的语法结构，主要由一个<code>%PATTERNS_DEF</code>哈希&#x2F;字典结构组成：</p><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">%PATTERNS_DEF</span> = (</span><br><span class="line">    <span class="string">Modes =&gt;</span> &#123;</span><br><span class="line">        <span class="string">ModeName1 =&gt;</span> &#123; 配置选项 &#125;,</span><br><span class="line">        <span class="string">ModeName2 =&gt;</span> &#123; 配置选项 &#125;,</span><br><span class="line">        <span class="regexp">//</span> ...</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="string">Errors =&gt;</span> &#123; 错误模式定义 &#125;,</span><br><span class="line">    <span class="string">Warnings =&gt;</span> &#123; 警告模式定义 &#125;,</span><br><span class="line">    <span class="regexp">//</span> ...</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="配置选项详解"><a href="#配置选项详解" class="headerlink" title="配置选项详解"></a>配置选项详解</h3><p>每个模式可以包含以下配置选项：</p><ul><li><strong>Ignore</strong>: 是否忽略此模式（0为不忽略，1为忽略）。</li><li><strong>Required</strong>: 是否必须匹配此模式（0为非必须，1为必须）。</li><li><strong>StartString</strong>: 开始匹配的正则表达式。</li><li><strong>EndString</strong>: 结束匹配的正则表达式。</li><li><strong>RequiredText</strong>: 必须包含的文本模式数组。</li><li><strong>OptionalText</strong>: 可选包含的文本模式数组。</li><li><strong>ExcludedText</strong>: 不应包含的文本模式数组。</li><li><strong>Actions</strong>: 匹配后要执行的操作。</li></ul><hr><h2 id="常用模式示例"><a href="#常用模式示例" class="headerlink" title="常用模式示例"></a>常用模式示例</h2><h3 id="通用代码模式"><a href="#通用代码模式" class="headerlink" title="通用代码模式"></a>通用代码模式</h3><h4 id="CommentBlock-注释块匹配"><a href="#CommentBlock-注释块匹配" class="headerlink" title="CommentBlock - 注释块匹配"></a>CommentBlock - 注释块匹配</h4><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">CommentBlock =&gt;</span> &#123;</span><br><span class="line">    <span class="string">Ignore =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">Required =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">StartString =&gt;</span> <span class="string">&#x27;/\/\*/&#x27;</span>,</span><br><span class="line">    <span class="string">EndString =&gt;</span> <span class="string">&#x27;/\*\//&#x27;</span>,</span><br><span class="line">    <span class="string">OptionalText =&gt;</span> [<span class="string">&#x27;/\@brief/&#x27;</span>, <span class="string">&#x27;/\@param/&#x27;</span>, <span class="string">&#x27;/\@return/&#x27;</span>],</span><br><span class="line">    <span class="string">Actions =&gt;</span> &#123;</span><br><span class="line">        <span class="string">Highlight =&gt;</span> <span class="string">&#x27;green&#x27;</span>,</span><br><span class="line">        <span class="string">Extract =&gt;</span> <span class="string">&#x27;documentation&#x27;</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><h4 id="其他通用模式"><a href="#其他通用模式" class="headerlink" title="其他通用模式"></a>其他通用模式</h4><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">CodeBlock =&gt;</span> &#123;</span><br><span class="line">    <span class="string">Ignore =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">Required =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">StartString =&gt;</span> <span class="string">&#x27;/\&#123;/&#x27;</span>,</span><br><span class="line">    <span class="string">EndString =&gt;</span> <span class="string">&#x27;/\&#125;/&#x27;</span>,</span><br><span class="line">    <span class="string">ExcludedText =&gt;</span> [<span class="string">&#x27;/TODO:/&#x27;</span>, <span class="string">&#x27;/FIXME:/&#x27;</span>],</span><br><span class="line">    <span class="string">Actions =&gt;</span> &#123;</span><br><span class="line">        <span class="string">Analyze =&gt;</span> <span class="string">&#x27;complexity&#x27;</span>,</span><br><span class="line">        <span class="string">Log =&gt;</span> <span class="number">1</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line"><span class="string">TodoItem =&gt;</span> &#123;</span><br><span class="line">    <span class="string">Ignore =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">Required =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">StartString =&gt;</span> <span class="string">&#x27;/TODO:|FIXME:/i&#x27;</span>,</span><br><span class="line">    <span class="string">EndString =&gt;</span> <span class="string">&#x27;/$/&#x27;</span>,</span><br><span class="line">    <span class="string">RequiredText =&gt;</span> [<span class="string">&#x27;/[\w\s]+/&#x27;</span>],</span><br><span class="line">    <span class="string">Actions =&gt;</span> &#123;</span><br><span class="line">        <span class="string">Highlight =&gt;</span> <span class="string">&#x27;yellow&#x27;</span>,</span><br><span class="line">        <span class="string">Extract =&gt;</span> <span class="string">&#x27;tasks&#x27;</span>,</span><br><span class="line">        <span class="string">Priority =&gt;</span> <span class="string">&#x27;high&#x27;</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><hr><h3 id="IC设计验证专用模式"><a href="#IC设计验证专用模式" class="headerlink" title="IC设计验证专用模式"></a>IC设计验证专用模式</h3><h4 id="时钟域识别-ClockDomain"><a href="#时钟域识别-ClockDomain" class="headerlink" title="时钟域识别 (ClockDomain)"></a>时钟域识别 (ClockDomain)</h4><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">ClockDomain =&gt;</span> &#123;</span><br><span class="line">    <span class="string">Ignore =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">Required =&gt;</span> <span class="number">1</span>,</span><br><span class="line">    <span class="string">StartString =&gt;</span> <span class="string">&#x27;/\bclock\s+domain\b|\bclk_domain\b/i&#x27;</span>,</span><br><span class="line">    <span class="string">EndString =&gt;</span> <span class="string">&#x27;/;/&#x27;</span>,</span><br><span class="line">    <span class="string">RequiredText =&gt;</span> [<span class="string">&#x27;/\b(posedge|negedge)\b/&#x27;</span>, <span class="string">&#x27;/\bclk\b/&#x27;</span>],</span><br><span class="line">    <span class="string">Actions =&gt;</span> &#123;</span><br><span class="line">        <span class="string">Highlight =&gt;</span> <span class="string">&#x27;purple&#x27;</span>,</span><br><span class="line">        <span class="string">Extract =&gt;</span> <span class="string">&#x27;timing_info&#x27;</span>,</span><br><span class="line">        <span class="string">Log =&gt;</span> <span class="number">1</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><h4 id="属性断言-AssertProperty"><a href="#属性断言-AssertProperty" class="headerlink" title="属性断言 (AssertProperty)"></a>属性断言 (AssertProperty)</h4><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">AssertProperty =&gt;</span> &#123;</span><br><span class="line">    <span class="string">Ignore =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">Required =&gt;</span> <span class="number">0</span>,</span><br><span class="line">    <span class="string">StartString =&gt;</span> <span class="string">&#x27;/\b(assert\s+property|property\s+[a-zA-Z_][a-zA-Z0-9_]*)/i&#x27;</span>,</span><br><span class="line">    <span class="string">EndString =&gt;</span> <span class="string">&#x27;/\bendproperty\b|\);/i&#x27;</span>,</span><br><span class="line">    <span class="string">RequiredText =&gt;</span> [<span class="string">&#x27;/\b(always|never|eventually)\b/i&#x27;</span>],</span><br><span class="line">    <span class="string">OptionalText =&gt;</span> [<span class="string">&#x27;/\b(sequence|strong|weak)\b/i&#x27;</span>],</span><br><span class="line">    <span class="string">Actions =&gt;</span> &#123;</span><br><span class="line">        <span class="string">Highlight =&gt;</span> <span class="string">&#x27;blue&#x27;</span>,</span><br><span class="line">        <span class="string">Extract =&gt;</span> <span class="string">&#x27;assertions&#x27;</span>,</span><br><span class="line">        <span class="string">Verify =&gt;</span> <span class="string">&#x27;safety_property&#x27;</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><hr><h2 id="工具与脚本"><a href="#工具与脚本" class="headerlink" title="工具与脚本"></a>工具与脚本</h2><h3 id="如何调用PAT模式文件"><a href="#如何调用PAT模式文件" class="headerlink" title="如何调用PAT模式文件"></a>如何调用PAT模式文件</h3><p>PAT模式文件可以通过多种方式被调用和使用，下面介绍几种常见的调用方法：</p><h4 id="1-命令行直接调用"><a href="#1-命令行直接调用" class="headerlink" title="1. 命令行直接调用"></a>1. 命令行直接调用</h4><p>使用VCS命令行工具直接引用PAT文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vcs -full64 -sverilog +pat+c:/prj/example.pat -f filelist.f -l compile.log</span><br></pre></td></tr></table></figure><p>关键参数说明：</p><ul><li><code>+pat+&lt;filepath&gt;</code> - 指定PAT模式文件的路径</li><li><code>-f filelist.f</code> - 包含要处理的源文件列表</li><li><code>-l compile.log</code> - 指定日志输出文件</li></ul><h4 id="2-通过配置文件引用"><a href="#2-通过配置文件引用" class="headerlink" title="2. 通过配置文件引用"></a>2. 通过配置文件引用</h4><p>在VCS配置文件中引用PAT文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// vcs.config</span><br><span class="line">PATTERNS_FILE = &quot;c:/prj/example.pat&quot;;</span><br><span class="line">PATTERN_MODE = &quot;ClockDomain,AssertProperty&quot;;  // 可以指定要使用的模式</span><br></pre></td></tr></table></figure><p>然后在命令行中引用此配置文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vcs -full64 -sverilog -config vcs.config -f filelist.f</span><br></pre></td></tr></table></figure><h4 id="3-通过脚本间接调用"><a href="#3-通过脚本间接调用" class="headerlink" title="3. 通过脚本间接调用"></a>3. 通过脚本间接调用</h4><p>使用自定义Perl脚本调用处理：</p><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/perl</span></span><br><span class="line"><span class="comment"># 示例：通过脚本调用PAT模式验证</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> strict;</span><br><span class="line"><span class="keyword">use</span> warnings;</span><br><span class="line"><span class="keyword">use</span> VCS::PatternChecker;  <span class="comment"># VCS Pattern API模块</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">my</span> <span class="variable">$checker</span> = VCS::PatternChecker-&gt;new(</span><br><span class="line">    <span class="string">pattern_file =&gt;</span> <span class="string">&#x27;c:/prj/example.pat&#x27;</span>,</span><br><span class="line">    <span class="string">active_modes =&gt;</span> [<span class="string">&#x27;CommentBlock&#x27;</span>, <span class="string">&#x27;ClockDomain&#x27;</span>],</span><br><span class="line">    <span class="string">report_file =&gt;</span> <span class="string">&#x27;pattern_report.txt&#x27;</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="variable">$checker</span>-&gt;check_files(<span class="string">&#x27;src/*.sv&#x27;</span>);</span><br><span class="line"><span class="variable">$checker</span>-&gt;print_summary();</span><br></pre></td></tr></table></figure><h4 id="4-与VCS-GUI工具集成"><a href="#4-与VCS-GUI工具集成" class="headerlink" title="4. 与VCS GUI工具集成"></a>4. 与VCS GUI工具集成</h4><p>在VCS的GUI环境中：</p><ol><li>打开VCS图形界面：<code>vcs -gui</code></li><li>选择菜单：<code>Tools</code> &gt; <code>Code Quality</code> &gt; <code>Pattern Checker</code></li><li>在弹出窗口中，浏览并选择PAT文件</li><li>选择要检查的源文件目录</li><li>选择要应用的模式（可多选）</li><li>点击”Run”开始验证</li></ol><h4 id="5-与项目Makefile集成"><a href="#5-与项目Makefile集成" class="headerlink" title="5. 与项目Makefile集成"></a>5. 与项目Makefile集成</h4><p>在项目Makefile中定义PAT验证规则：</p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Pattern verification target</span></span><br><span class="line"><span class="section">pattern_check:</span></span><br><span class="line">@echo <span class="string">&quot;Running pattern verification...&quot;</span></span><br><span class="line">@vcs -full64 -sverilog +pat+<span class="variable">$(PATTERN_FILE)</span> -f <span class="variable">$(SRC_LIST)</span> -l pattern.log</span><br><span class="line">@grep -E <span class="string">&quot;Error|Warning&quot;</span> pattern.log || echo <span class="string">&quot;Pattern check passed.&quot;</span></span><br></pre></td></tr></table></figure><p>然后使用<code>make pattern_check</code>执行验证。</p><h3 id="注释检查脚本"><a href="#注释检查脚本" class="headerlink" title="注释检查脚本"></a>注释检查脚本</h3><p>以下是<code>check_comments.pl</code>脚本的完整代码，用于检查代码库中的注释：</p><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/perl</span></span><br><span class="line"><span class="comment"># filepath: c:\prj\check_comments.pl</span></span><br><span class="line"><span class="keyword">use</span> strict;</span><br><span class="line"><span class="keyword">use</span> warnings;</span><br><span class="line"><span class="keyword">use</span> Getopt::Long;</span><br><span class="line"><span class="keyword">use</span> File::Find;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 命令行参数</span></span><br><span class="line"><span class="keyword">my</span> <span class="variable">$pattern_name</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">my</span> <span class="variable">$src_pattern</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">my</span> <span class="variable">$verbose</span> = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">my</span> <span class="variable">$help</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">GetOptions(</span><br><span class="line">    <span class="string">&quot;pattern=s&quot;</span> =&gt; \<span class="variable">$pattern_name</span>,</span><br><span class="line">    <span class="string">&quot;src=s&quot;</span>     =&gt; \<span class="variable">$src_pattern</span>,</span><br><span class="line">    <span class="string">&quot;verbose&quot;</span>   =&gt; \<span class="variable">$verbose</span>,</span><br><span class="line">    <span class="string">&quot;help&quot;</span>      =&gt; \<span class="variable">$help</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$help</span> || !<span class="variable">$pattern_name</span> || !<span class="variable">$src_pattern</span>) &#123;</span><br><span class="line">    print_help();</span><br><span class="line">    <span class="keyword">exit</span>(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加载模式定义</span></span><br><span class="line"><span class="keyword">my</span> <span class="variable">%PATTERNS_DEF</span> = load_patterns();</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查模式是否存在</span></span><br><span class="line"><span class="keyword">die</span> <span class="string">&quot;Error: Pattern &#x27;<span class="variable">$pattern_name</span>&#x27; not found.\n&quot;</span></span><br><span class="line">    <span class="keyword">unless</span> <span class="keyword">exists</span> <span class="variable">$PATTERNS_DEF</span><span class="string">&#123;Modes&#125;</span>&#123;<span class="variable">$pattern_name</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">my</span> <span class="variable">$pattern</span> = <span class="variable">$PATTERNS_DEF</span><span class="string">&#123;Modes&#125;</span>&#123;<span class="variable">$pattern_name</span>&#125;;</span><br><span class="line"><span class="keyword">print</span> <span class="string">&quot;Using pattern: <span class="variable">$pattern_name</span>\n&quot;</span> <span class="keyword">if</span> <span class="variable">$verbose</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扫描文件</span></span><br><span class="line"><span class="keyword">my</span> <span class="variable">@files</span> = <span class="keyword">glob</span>(<span class="variable">$src_pattern</span>);</span><br><span class="line"><span class="keyword">foreach</span> <span class="keyword">my</span> <span class="variable">$file</span> (<span class="variable">@files</span>) &#123;</span><br><span class="line">    <span class="keyword">open</span> <span class="keyword">my</span> <span class="variable">$fh</span>, <span class="string">&#x27;&lt;&#x27;</span>, <span class="variable">$file</span> <span class="keyword">or</span> <span class="keyword">die</span> <span class="string">&quot;Cannot open <span class="variable">$file</span>: <span class="variable">$!</span>&quot;</span>;</span><br><span class="line">    <span class="keyword">my</span> <span class="variable">$content</span> = <span class="keyword">do</span> &#123; <span class="keyword">local</span> <span class="variable">$/</span>; &lt;<span class="variable">$fh</span>&gt; &#125;;</span><br><span class="line">    <span class="keyword">close</span> <span class="variable">$fh</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable">$content</span> =~ <span class="regexp">/$pattern-&gt;&#123;StartString&#125;/</span>) &#123;</span><br><span class="line">        <span class="keyword">print</span> <span class="string">&quot;Found pattern in <span class="variable">$file</span>\n&quot;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">print</span> <span class="string">&quot;No pattern found in <span class="variable">$file</span>\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">sub</span> <span class="title">load_patterns</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        <span class="string">Modes =&gt;</span> &#123;</span><br><span class="line">            <span class="string">CommentBlock =&gt;</span> &#123;</span><br><span class="line">                <span class="string">StartString =&gt;</span> <span class="string">&#x27;/\/\*/&#x27;</span>,</span><br><span class="line">                <span class="string">EndString =&gt;</span> <span class="string">&#x27;/\*\//&#x27;</span>,</span><br><span class="line">                <span class="string">RequiredText =&gt;</span> [<span class="string">&#x27;/\@brief/&#x27;</span>, <span class="string">&#x27;/\@param/&#x27;</span>, <span class="string">&#x27;/\@return/&#x27;</span>],</span><br><span class="line">            &#125;,</span><br><span class="line">        &#125;</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">sub</span> <span class="title">print_help</span> </span>&#123;</span><br><span class="line">    <span class="keyword">print</span> &lt;&lt;HELP;</span><br><span class="line">Usage: perl check_comments.pl --pattern=PATTERN --src=SOURCE_FILES [options]</span><br><span class="line"></span><br><span class="line">Options:</span><br><span class="line">  --pattern=PATTERN     指定要使用的模式名称</span><br><span class="line">  --src=SOURCE_FILES    源文件路径，支持通配符</span><br><span class="line">  --verbose             显示详细输出</span><br><span class="line">  --help                显示帮助信息</span><br><span class="line">HELP</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><ol><li><strong>针对特定语言调整正则表达式</strong>：根据语言特性优化StartString和EndString。</li><li><strong>从宽松规则开始</strong>：逐步收紧规则以减少误报。</li><li><strong>结合工具使用</strong>：将模式文件与脚本结合使用，自动化代码审查和验证。</li></ol><hr><h2 id="完整示例"><a href="#完整示例" class="headerlink" title="完整示例"></a>完整示例</h2><p>以下是一个完整的模式文件示例：</p><figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">%PATTERNS_DEF</span> = (</span><br><span class="line">    <span class="string">Modes =&gt;</span> &#123;</span><br><span class="line">        <span class="string">CommentBlock =&gt;</span> &#123;</span><br><span class="line">            <span class="string">Ignore =&gt;</span> <span class="number">0</span>,</span><br><span class="line">            <span class="string">Required =&gt;</span> <span class="number">0</span>,</span><br><span class="line">            <span class="string">StartString =&gt;</span> <span class="string">&#x27;/\/\*/&#x27;</span>,</span><br><span class="line">            <span class="string">EndString =&gt;</span> <span class="string">&#x27;/\*\//&#x27;</span>,</span><br><span class="line">            <span class="string">OptionalText =&gt;</span> [<span class="string">&#x27;/\@brief/&#x27;</span>, <span class="string">&#x27;/\@param/&#x27;</span>, <span class="string">&#x27;/\@return/&#x27;</span>],</span><br><span class="line">            <span class="string">Actions =&gt;</span> &#123;</span><br><span class="line">                <span class="string">Highlight =&gt;</span> <span class="string">&#x27;green&#x27;</span>,</span><br><span class="line">                <span class="string">Extract =&gt;</span> <span class="string">&#x27;documentation&#x27;</span></span><br><span class="line">            &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="regexp">//</span> ...</span><br><span class="line">    &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>通过结合模式文件和脚本，您可以实现自动化的代码审查、文档生成和IC设计验证。</p><h1 id="This-is-a-sample-Python-script"><a href="#This-is-a-sample-Python-script" class="headerlink" title="This is a sample Python script."></a>This is a sample Python script.</h1><h1 id="Press-Shift-F10-to-execute-it-or-replace-it-with-your-code"><a href="#Press-Shift-F10-to-execute-it-or-replace-it-with-your-code" class="headerlink" title="Press Shift+F10 to execute it or replace it with your code."></a>Press Shift+F10 to execute it or replace it with your code.</h1><h1 id="Press-Double-Shift-to-search-everywhere-for-classes-files-tool-windows-actions-and-settings"><a href="#Press-Double-Shift-to-search-everywhere-for-classes-files-tool-windows-actions-and-settings" class="headerlink" title="Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings."></a>Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.</h1><h1 id="coding-UTF-8"><a href="#coding-UTF-8" class="headerlink" title="-- coding: UTF-8 --"></a>-<em>- coding: UTF-8 -</em>-</h1><p>import os</p><p>import sys<br>import re</p><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>target_dir &#x3D;”xxx”  # 替换为你要扫描的目录<br>output_file &#x3D; “verilog_comparison_results.txt”</p><h1 id="定义比较操作符"><a href="#定义比较操作符" class="headerlink" title="定义比较操作符"></a>定义比较操作符</h1><p>#comparison_ops &#x3D; [‘&gt;’, ‘&gt;&#x3D;’, ‘&#x3D;&#x3D;’, ‘&lt;&#x3D;’, ‘&lt;’]<br>#pattern &#x3D; r’if\s<em>(\s*([a-zA-Z_][a-zA-Z0-9_]<em>)\s</em>(&gt;&#x3D;|&lt;&#x3D;|&gt;|&lt;|&#x3D;&#x3D;)\s*(\d+)\s*)‘<br>pattern &#x3D; r’([a-zA-Z_][a-zA-Z0-9_]*)\s*(&gt;&#x3D;|&lt;&#x3D;|&gt;|&lt;)\s</em>(\d+)’</p><h1 id="正则表达式：匹配只包含-“var"><a href="#正则表达式：匹配只包含-“var" class="headerlink" title="正则表达式：匹配只包含 “var &lt;&#x3D; 10” 的行（如 assign var &lt;&#x3D; 10;）"></a>正则表达式：匹配只包含 “var &lt;&#x3D; 10” 的行（如 assign var &lt;&#x3D; 10;）</h1><p>#single_compare_pattern &#x3D; r’^\s*([a-zA-Z_][a-zA-Z0-9_]<em>)\s</em>(&gt;&#x3D;|&lt;&#x3D;|&gt;|&lt;|&#x3D;&#x3D;)\s*(\d+|1&#39;b0|2&#39;b0|3&#39;b0|4&#39;b0|5&#39;b0|6&#39;b0|7&#39;b0|8&#39;b0|9&#39;b0|10&#39;b0|11&#39;b0|12&#39;b0|13&#39;b0|14&#39;b0|5&#39;b0|6&#39;b0|7&#39;b0|8&#39;b0|9&#39;b0|10&#39;b0|16&#39;b0|32&#39;b0|9&#39;d20|64&#39;h0|1&#39;b1|2&#39;b1|3&#39;b1|16&#39;b1|8&#39;b1|9&#39;d20|64&#39;h1|1&#39;d0|2&#39;d0|3&#39;d0|4&#39;d0|8&#39;d0|16&#39;d0|32&#39;d0|1&#39;h0|2&#39;h0|3&#39;h0|4&#39;h0|8&#39;h0|16&#39;h0|32&#39;h0|9&#39;d20)\s*;$’<br>single_compare_pattern &#x3D;r’^\s*([a-zA-Z_][a-zA-Z0-9_]<em>)\s*(&gt;&#x3D;|&lt;&#x3D;|&gt;|&lt;|&#x3D;&#x3D;)\s</em>(\d+|(\d+)&#39;[a-zA-Z]+[0-9&#39;]<em>)\s</em>;$’</p><h1 id="打开输出文件"><a href="#打开输出文件" class="headerlink" title="打开输出文件"></a>打开输出文件</h1><p>with open(output_file, ‘w’, encoding&#x3D;’utf-8’) as f_out:<br>    # 遍历目录中的所有文件<br>    for root, dirs, files in os.walk(target_dir):<br>        for file in files:<br>            # 如果文件名包含 “ecc”，跳过<br>            if “ecc” in file:<br>                continue<br>            if “host” in file:<br>                continue<br>            if “ssu” in file:<br>                continue<br>            if file.endswith(“.v”) or file.endswith(“.sv”):  # 只处理 Verilog 和 SystemVerilog 文件<br>                file_path &#x3D; os.path.join(root, file)<br>                try:<br>                    with open(file_path, ‘r’, encoding&#x3D;’utf-8’) as f_in:  # 尝试用 utf-8 读取<br>                        lines &#x3D; f_in.readlines()<br>                except UnicodeDecodeError:<br>                    # 如果 utf-8 失败，尝试用 gbk 或其他编码<br>                    with open(file_path, ‘r’, encoding&#x3D;’gbk’) as f_in:<br>                        lines &#x3D; f_in.readlines()<br>                for line_num, line in enumerate(lines, start&#x3D;1):<br>                    # 使用正则表达式匹配条件判断语句中的变量与常值比较<br>                    if line.strip().startswith(“for”):<br>                        continue<br>                    if line.strip().startswith(“&#x2F;&#x2F;“):<br>                        continue<br>                    if line.strip().startswith(“assign”):<br>                        continue<br>                    if line.strip().startswith(“wire”):<br>                        continue<br>                    if line.strip().startswith(“4’b”):<br>                        continue<br>                    if line.strip().startswith(“3’b”):<br>                        continue<br>                    if line.strip().startswith(“default”):<br>                        continue<br>                    if line.strip().startswith(“input”):<br>                        continue<br>                    if line.strip().startswith(“generate”):<br>                        continue<br>                    if line.strip().startswith(“lan”):<br>                        continue<br>                    if line.strip().startswith(“4’h”):<br>                        continue<br>                    if line.strip().startswith(“oxu_ibe_inq_chn”):<br>                        continue<br>                    matches &#x3D; re.finditer(pattern, line)<br>                    for match in matches:<br>                        var_name &#x3D; match.group(1)<br>                        op &#x3D; match.group(2)<br>                        value &#x3D; match.group(3)<br>                        # 构造匹配的完整语句<br>                        matched_line &#x3D; line.strip()<br>                        # 检查该行是否只包含 “var &lt;&#x3D; 10”<br>                        if re.fullmatch(single_compare_pattern, line.strip()):<br>                            # 如果只包含变量与常值比较，不输出<br>                            continue<br>                        # 否则，输出<br>                        f_out.write(f”文件: {file_path}\n”)<br>                        f_out.write(f”行号: {line_num}\n”)<br>                        f_out.write(f”代码: {matched_line}\n”)<br>                        f_out.write(f”变量: {var_name} {op} {value}\n”)<br>                        f_out.write(“-“ * 40 + “\n”)<br>    print(f”结果已保存到 {output_file}”)</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;目录&quot;&gt;&lt;a href=&quot;#目录&quot; class=&quot;headerlink&quot; title=&quot;目录&quot;&gt;&lt;/a&gt;目录&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%AE%80%E4%BB%8B&quot;&gt;简介&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%A8%A</summary>
      
    
    
    
    <category term="工具" scheme="https://sqlmaps.com/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://sqlmaps.com/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="开发环境" scheme="https://sqlmaps.com/tags/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/"/>
    
  </entry>
  
  <entry>
    <title>IC 验证学习笔记</title>
    <link href="https://sqlmaps.com/2026/08/01/IC%E9%AA%8C%E8%AF%81%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    <id>https://sqlmaps.com/2026/08/01/IC%E9%AA%8C%E8%AF%81%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</id>
    <published>2026-08-01T14:10:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h1 id="一、UVM验证"><a href="#一、UVM验证" class="headerlink" title="一、UVM验证"></a>一、UVM验证</h1><h2 id="1-常见组件"><a href="#1-常见组件" class="headerlink" title="1 常见组件"></a>1 常见组件</h2><h3 id="1-1-sequencer"><a href="#1-1-sequencer" class="headerlink" title="1.1 sequencer"></a>1.1 sequencer</h3><ul><li>uvm_sequencer 是一个参数化类，其参数是 my_transaction。</li><li>在 sequencer 的帮助下，sequence 产生的 transaction 才能最终送给 driver。</li><li>sqr 和 drv 相连接：<code>drv.seq_item_port.connect(sqr.seq_item_export)</code> 将 sqr 的 trans 传递给 drv。</li></ul><h3 id="1-2-driver"><a href="#1-2-driver" class="headerlink" title="1.2 driver"></a>1.2 driver</h3><ul><li>uvm_driver 是一个参数化类，定义 driver 时需指明参数 transaction。</li><li>uvm_driver 具有两个参数：request &#x2F; response。默认情况下二者类型一致，一般指定为用户定义的 transaction 类型；它们也是 uvm_driver 自带 seq_item_port 的参数类型。</li><li>环境中 driver 组件的变量值会保持至仿真结束（与 phase 执行相关）。</li></ul><div class="note info flat"><blockquote><p><strong>注意</strong></p></blockquote></div><blockquote><ul><li><code>get_next_item()</code> 是阻塞的：一直等待 trans 到来（get_next_item → item_done）。</li><li><code>try_next_item()</code> 是非阻塞的：若无新 trans 直接返回，<code>req == null</code>；否则 <code>req = trans</code>。</li></ul></blockquote><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> (<span class="number">1</span>) <span class="keyword">begin</span></span><br><span class="line">  seq_item_port<span class="variable">.try_next_item</span>(req);</span><br><span class="line">  <span class="keyword">if</span> (req == <span class="literal">null</span>)</span><br><span class="line">    @(<span class="keyword">posedge</span> vif<span class="variable">.clk</span>);</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">    drive_one_pkt(req);</span><br><span class="line">    seq_item_port<span class="variable">.item_done</span>();</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h3 id="1-3-transaction"><a href="#1-3-transaction" class="headerlink" title="1.3 transaction"></a>1.3 transaction</h3><ul><li>sequence 相当于一个弹夹，里面的子弹相当于 transaction，而 sequencer 相当于手枪。</li><li>transaction 使用 uvm_object_utils 宏注册到 factory 中（有生命周期）。</li></ul><div class="note info flat"><blockquote><p><strong>注意</strong> transaction 的句柄每次发送给其它组件时，需要 <code>new()</code> 或 <code>type_id::create</code> 开辟新空间，避免所有句柄指向同一空间。</p></blockquote></div><h3 id="1-4-测试用例"><a href="#1-4-测试用例" class="headerlink" title="1.4 测试用例"></a>1.4 测试用例</h3><p>测试 DUT 是否按照预期工作，需要施加不同的激励，这些激励称为测试向量或 pattern。</p><h3 id="1-5-uvm-pkg"><a href="#1-5-uvm-pkg" class="headerlink" title="1.5 uvm_pkg"></a>1.5 uvm_pkg</h3><p>uvm_pkg 中包含 uvm 内建的变量、方法、机制，需在 UVM 验证环境中导入使用：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> uvm_pkg::*;</span><br></pre></td></tr></table></figure><h3 id="1-6-scoreboard"><a href="#1-6-scoreboard" class="headerlink" title="1.6 scoreboard"></a>1.6 scoreboard</h3><p>scoreboard 可以订阅来自被测设计（DUT）和预期输出的事务，主要依赖 UVM 提供的消息传递与事件通知机制来处理和比较事务。由于事件驱动模型不依赖时钟信号，因此 scoreboard 不需要时钟，即 scoreboard 的 main_phase 不需要时钟信号。</p><h2 id="2-sequence"><a href="#2-sequence" class="headerlink" title="2 sequence"></a>2 sequence</h2><ul><li>sequence 相当于一个参数化类，用于产生激励。</li><li>sequence 使用 uvm_object_utils 宏注册到 factory 中；当 trans 都发送完后，sequence 生命周期结束（有生命周期）。</li><li>每一个 sequence 都应该派生自 uvm_sequence，定义时需指定要产生的 transaction。sequence 启动后会执行 body 任务；除 body 外，还会自动调用 pre_body 与 post_body。</li><li>sequence 启动后，再次启动不需要重新声明与例化（原表述有误，同一 sequence 可以多次启动）。</li><li>sequence 例化多份时，各实例内部变量值互不干扰（不同 class 实例）。</li><li>sequence 中可以使用 rand 类型定义变量，变量名尽量不与 trans 一样。</li></ul><p>sequence 随机 transaction 的方法：</p><ul><li>通过 start_item &#x2F; finish_item（常用，最透明）：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">my_trans = <span class="keyword">new</span>(<span class="string">&quot;my_trans&quot;</span>);</span><br><span class="line">start_item(my_trans);</span><br><span class="line">finish_item(my_trans);</span><br></pre></td></tr></table></figure><div class="note info flat"><blockquote><p><strong>注意</strong> start_item 和 finish_item 之间避免添加延时：start_item 返回后，该 sequence 赢得仲裁并可访问 sequencer&#x2F;driver；若在 finish_item 之前加入延时，会延长占用时间，导致其它 sequence 延迟执行。</p></blockquote></div><ul><li>在 start_item &#x2F; finish_item 之间做随机与赋值（常用写法）：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">my_trans req;</span><br><span class="line">req = my_trans::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">start_item(req);</span><br><span class="line"><span class="keyword">void</span>&#x27;(req<span class="variable">.randomize</span>());</span><br><span class="line">finish_item(req);</span><br></pre></td></tr></table></figure><ul><li><p>在 start_item &#x2F; finish_item 之间增加内嵌约束（<code>randomize() with &#123; ... &#125;</code> 控制某一次发包）：详见 <a href="#22-%E7%BA%A6%E6%9D%9F%E4%B8%8E%E9%9A%8F%E6%9C%BA%E5%8C%96constraint-random">2.2</a></p></li><li><p>将“创建&#x2F;随机&#x2F;发送”拆成宏（写起来更短，但可见性更差）：</p><ul><li><code>uvm_create(req)</code>：用 factory 在当前 sequencer 上创建 item（等价于 <code>type_id::create</code>&#x2F;<code>create_item</code>）</li><li><code>uvm_send(req)</code>：只负责 <code>start_item(req)</code> + <code>finish_item(req)</code>，不做 randomize</li><li><code>uvm_rand_send(req)</code>：<code>start_item</code> + <code>randomize</code> + <code>finish_item</code></li><li><code>uvm_do(req)</code>：<code>uvm_create(req)</code> + <code>uvm_rand_send(req)</code>（最常见的一行发包宏）</li><li><code>uvm_do_with(req, &#123; ... &#125;)</code>：<code>uvm_do(req)</code> 但 randomize 时带 with 约束</li><li><code>uvm_do_on(req, sqr)</code> &#x2F; <code>uvm_do_on_with(req, sqr, &#123; ... &#125;)</code>：指定在哪个 sequencer 上跑</li><li><code>uvm_do_pri(req, pri)</code> &#x2F; <code>uvm_do_pri_with(req, pri, &#123; ... &#125;)</code>：指定 sequencer 仲裁优先级</li></ul></li></ul><p>uvm_do 系列宏“内部做了哪些操作”（等价展开思路）：</p><ul><li>1）创建 item（factory create，便于 override）</li><li>2）start_item：向 sequencer 申请仲裁并等待 driver 拉取</li><li>3）randomize：对 item 随机（可带 with 内嵌约束）</li><li>4）finish_item：将 item 交给 sequencer，driver 侧 get_next_item 能拿到并驱动</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">my_trans req;</span><br><span class="line">req = my_trans::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">start_item(req);</span><br><span class="line"><span class="keyword">if</span> (!req<span class="variable">.randomize</span>()) `uvm_fatal(<span class="string">&quot;RANDFAIL&quot;</span>, <span class="string">&quot;randomize failed&quot;</span>)</span><br><span class="line">finish_item(req);</span><br></pre></td></tr></table></figure><p>补充：调用 start_item&#x2F;finish_item 前需要先例化 transaction；随机化只要发生在 finish_item 之前即可。</p><p>sequence 的启动方法：</p><ol><li>手动启动（常用）：创建一个 my_sequence 实例 seq，再调用 start 任务。start 的参数是一个 sequencer 指针；不指明则 sequence 不知道将产生的 transaction 交给哪个 sequencer。</li><li>自动启动：sequence 和 sequencer 关联，例如：</li></ol><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(uvm_object_wrapper)</span>::set(</span><br><span class="line">  xx, xx, <span class="string">&quot;default_sequence&quot;</span>, <span class="keyword">sequence</span>::type_id::get()</span><br><span class="line">);</span><br></pre></td></tr></table></figure><ol start="3"><li>其它启动方式：可参考后续内容。</li></ol><h3 id="2-2-约束与随机化（constraint-random）"><a href="#2-2-约束与随机化（constraint-random）" class="headerlink" title="2.2 约束与随机化（constraint random）"></a>2.2 约束与随机化（constraint random）</h3><p>约束随机验证的核心是：用约束把随机空间“剪”成你关心的子空间，再通过大量随机种子覆盖状态空间；当覆盖出现空洞时，再通过调整约束引导命中。</p><h4 id="2-2-1-rand-randc-与-constraint-块"><a href="#2-2-1-rand-randc-与-constraint-块" class="headerlink" title="2.2.1 rand &#x2F; randc 与 constraint 块"></a>2.2.1 rand &#x2F; randc 与 constraint 块</h4><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> pkt <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">  `uvm_object_utils(pkt)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">rand</span>  <span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>]  cmd;</span><br><span class="line">  <span class="keyword">rand</span>  <span class="keyword">bit</span> [<span class="number">31</span>:<span class="number">0</span>] addr;</span><br><span class="line">  <span class="keyword">randc</span> <span class="keyword">bit</span> [<span class="number">7</span>:<span class="number">0</span>]  tag;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">constraint</span> c_basic &#123;</span><br><span class="line">    cmd <span class="keyword">inside</span> &#123;[<span class="number">0</span>:<span class="number">3</span>]&#125;;</span><br><span class="line">    addr[<span class="number">1</span>:<span class="number">0</span>] == <span class="number">0</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;pkt&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>要点：</p><ul><li><code>rand</code>：每次随机相互独立</li><li><code>randc</code>：循环随机，遍历完取值空间后再重新洗牌（空间过大时不现实）</li><li>约束块可拆成多个，便于按场景开关（见 <code>constraint_mode()</code>）</li></ul><h4 id="2-2-2-内嵌约束（randomize-with）"><a href="#2-2-2-内嵌约束（randomize-with）" class="headerlink" title="2.2.2 内嵌约束（randomize with）"></a>2.2.2 内嵌约束（randomize with）</h4><p>适用：只想在“某一次发包”施加额外约束，不改类本身的默认约束。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">pkt req;</span><br><span class="line">req = pkt::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">start_item(req);</span><br><span class="line"><span class="keyword">if</span> (!req<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123; cmd == <span class="number">2</span>; addr[<span class="number">15</span>:<span class="number">12</span>] <span class="keyword">inside</span> &#123;[<span class="number">4</span>:<span class="number">8</span>]&#125;; &#125;) `uvm_fatal(<span class="string">&quot;RANDFAIL&quot;</span>, <span class="string">&quot;randomize failed&quot;</span>)</span><br><span class="line">finish_item(req);</span><br></pre></td></tr></table></figure><p>对应的宏写法：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pkt req;</span><br><span class="line">`uvm_do_with(req, &#123; cmd == <span class="number">2</span>; addr[<span class="number">15</span>:<span class="number">12</span>] <span class="keyword">inside</span> &#123;[<span class="number">4</span>:<span class="number">8</span>]&#125;; &#125;)</span><br></pre></td></tr></table></figure><h4 id="2-2-3-常用约束语法速查"><a href="#2-2-3-常用约束语法速查" class="headerlink" title="2.2.3 常用约束语法速查"></a>2.2.3 常用约束语法速查</h4><p><code>inside</code> &#x2F; 集合：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constraint</span> c0 &#123; cmd <span class="keyword">inside</span> &#123;<span class="number">0</span>, <span class="number">2</span>, <span class="number">3</span>&#125;; &#125;</span><br><span class="line"><span class="keyword">constraint</span> c1 &#123; addr <span class="keyword">inside</span> &#123;[<span class="number">32&#x27;h1000</span>:<span class="number">32&#x27;h1fff</span>]&#125;; &#125;</span><br></pre></td></tr></table></figure><p><code>dist</code> &#x2F; 分布：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constraint</span> c_dist &#123;</span><br><span class="line">  cmd <span class="keyword">dist</span> &#123; <span class="number">0</span> := <span class="number">50</span>, <span class="number">1</span> := <span class="number">10</span>, [<span class="number">2</span>:<span class="number">3</span>] := <span class="number">40</span> &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>dist</code> 里 <code>:=</code> 与 <code>:/</code> 的区别：</p><ul><li><code>:=</code>：权重按“每个取值”分配（per-value weight）。区间写法会把权重平均摊到区间内每个值上</li><li><code>:/</code>：权重按“整个区间&#x2F;整个集合”分配（per-range weight）。区间整体拿到该权重，再在区间内均匀取值</li></ul><p>例子：下面两条约束的概率不同</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constraint</span> c_dist_per_value &#123;</span><br><span class="line">  cmd <span class="keyword">dist</span> &#123; [<span class="number">0</span>:<span class="number">3</span>] := <span class="number">40</span>, <span class="number">4</span> := <span class="number">60</span> &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">constraint</span> c_dist_per_range &#123;</span><br><span class="line">  cmd <span class="keyword">dist</span> &#123; [<span class="number">0</span>:<span class="number">3</span>] :/ <span class="number">40</span>, <span class="number">4</span> :/ <span class="number">60</span> &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>直觉对比（假设 <code>cmd</code> 只允许 0~4）：</p><ul><li><code>:=</code>：<code>P(cmd==4)=60%</code>，剩下 40% 平均到 0&#x2F;1&#x2F;2&#x2F;3，每个约 10%</li><li><code>:/</code>：<code>P(cmd in 0..3)=40%</code>，区间内再均匀；<code>P(cmd==4)=60%</code></li></ul><p><code>soft</code> &#x2F; 软约束（可被更强约束覆盖）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constraint</span> c_soft &#123; <span class="keyword">soft</span> cmd == <span class="number">0</span>; &#125;</span><br></pre></td></tr></table></figure><p><code>solve ... before ...</code> &#x2F; 解算顺序（常用于数组长度&#x2F;依赖关系）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">rand</span> <span class="keyword">int</span> <span class="keyword">unsigned</span> len;</span><br><span class="line"><span class="keyword">rand</span> <span class="keyword">byte</span> payload[];</span><br><span class="line"><span class="keyword">constraint</span> c_len &#123;</span><br><span class="line">  len <span class="keyword">inside</span> &#123;[<span class="number">1</span>:<span class="number">256</span>]&#125;;</span><br><span class="line">  <span class="keyword">solve</span> len <span class="keyword">before</span> payload;</span><br><span class="line">  payload<span class="variable">.size</span>() == len;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>foreach</code> &#x2F; 数组元素约束：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constraint</span> c_each &#123;</span><br><span class="line">  <span class="keyword">foreach</span> (payload[i]) payload[i] <span class="keyword">inside</span> &#123;[<span class="number">8&#x27;h00</span>:<span class="number">8&#x27;hff</span>]&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>||</code> &#x2F; <code>or</code>（二选一、多选一约束）：</p><p>适用：需要表达“满足 A 或满足 B”，而不是把条件都同时满足（AND）。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constraint</span> c_or &#123;</span><br><span class="line">  (cmd == <span class="number">0</span>) || (cmd == <span class="number">1</span>) || (cmd == <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">constraint</span> c_or2 &#123;</span><br><span class="line">  (cmd == <span class="number">0</span> &amp;&amp; addr[<span class="number">3</span>:<span class="number">0</span>] == <span class="number">0</span>) ||</span><br><span class="line">  (cmd == <span class="number">1</span> &amp;&amp; addr[<span class="number">3</span>:<span class="number">0</span>] == <span class="number">4</span>) ||</span><br><span class="line">  (cmd == <span class="number">2</span> &amp;&amp; addr[<span class="number">3</span>:<span class="number">0</span>] <span class="keyword">inside</span> &#123;<span class="number">8</span>, <span class="number">12</span>&#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>find with</code>（先筛选候选集合，再用 inside 约束随机）：</p><p>适用：手上先有一堆“可选项”，你只想从其中“符合条件的那部分”里随机挑一个。</p><p>数通芯片例子：交换芯片有 64 个 egress port，但你这次只想从“链路 up 且没被屏蔽”的端口里随机挑一个去打流量。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> <span class="keyword">unsigned</span> cand_q[$];</span><br><span class="line"><span class="keyword">int</span> <span class="keyword">unsigned</span> all_q[$];</span><br><span class="line"><span class="keyword">int</span> <span class="keyword">unsigned</span> pick;</span><br><span class="line"></span><br><span class="line">all_q = &#x27;&#123;<span class="number">32&#x27;h1000</span>, <span class="number">32&#x27;h1004</span>, <span class="number">32&#x27;h1008</span>, <span class="number">32&#x27;h1010</span>, <span class="number">32&#x27;h2000</span>&#125;;</span><br><span class="line">cand_q = all_q<span class="variable">.find</span> <span class="keyword">with</span> (item[<span class="number">7</span>:<span class="number">0</span>] <span class="keyword">inside</span> &#123;[<span class="number">8&#x27;h00</span>:<span class="number">8&#x27;h1f</span>]&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span>&#x27;(std::randomize(pick) <span class="keyword">with</span> &#123; pick <span class="keyword">inside</span> &#123;cand_q&#125;; &#125;);</span><br></pre></td></tr></table></figure><p>使用条件：</p><ul><li><code>find with</code> 是“过程代码里筛选集合”的语义，更适合在 sequence&#x2F;test 里先筛出 <code>cand_q</code>，再用 <code>inside &#123;cand_q&#125;</code> 进行约束随机</li><li>如果筛选结果可能为空，需要先检查 <code>cand_q.size() &gt; 0</code>，否则 <code>inside &#123;cand_q&#125;</code> 会导致 randomize 失败</li></ul><h4 id="2-2-4-约束开关：constraint-mode-rand-mode"><a href="#2-2-4-约束开关：constraint-mode-rand-mode" class="headerlink" title="2.2.4 约束开关：constraint_mode &#x2F; rand_mode"></a>2.2.4 约束开关：constraint_mode &#x2F; rand_mode</h4><p>适用：同一个 transaction 类，默认约束用于大多数 case；特殊 case 需要临时关闭某一组约束或某个字段随机。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pkt req;</span><br><span class="line">req = pkt::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">req<span class="variable">.c_basic</span><span class="variable">.constraint_mode</span>(<span class="number">0</span>);</span><br><span class="line">req<span class="variable">.addr</span><span class="variable">.rand_mode</span>(<span class="number">0</span>);</span><br></pre></td></tr></table></figure><h4 id="2-2-5-randomize-失败的排查套路"><a href="#2-2-5-randomize-失败的排查套路" class="headerlink" title="2.2.5 randomize 失败的排查套路"></a>2.2.5 randomize 失败的排查套路</h4><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (!req<span class="variable">.randomize</span>()) `uvm_fatal(<span class="string">&quot;RANDFAIL&quot;</span>, <span class="string">&quot;randomize failed&quot;</span>)</span><br></pre></td></tr></table></figure><p>常见原因（按出现频率）：</p><ul><li>约束互相冲突（默认约束 + 内嵌约束叠加后无解）</li><li>字段不是 <code>rand</code> 却被约束</li><li>动态数组 <code>size()</code> 约束缺少 <code>solve before</code></li><li>写了不可能的位切片范围或写错了 <code>inside</code> 区间</li></ul><h4 id="2-2-6-覆盖驱动约束的思路（填洞）"><a href="#2-2-6-覆盖驱动约束的思路（填洞）" class="headerlink" title="2.2.6 覆盖驱动约束的思路（填洞）"></a>2.2.6 覆盖驱动约束的思路（填洞）</h4><p>做法：先定义 coverpoint&#x2F;cross -&gt; 看 coverage report 的 hole -&gt; 用 <code>dist/inside</code> 或者把洞对应的组合变成“可达且高概率”。</p><h3 id="2-1-摘记：sequence-transaction-pull-握手（LeslieQ）"><a href="#2-1-摘记：sequence-transaction-pull-握手（LeslieQ）" class="headerlink" title="2.1 摘记：sequence &#x2F; transaction &#x2F; pull 握手（LeslieQ）"></a>2.1 摘记：sequence &#x2F; transaction &#x2F; pull 握手（LeslieQ）</h3><p>参考原文：<a href="https://www.cnblogs.com/LeslieQ/p/19115777">笔记 sequence</a></p><ul><li>UVM 为什么好用：核心是约束随机验证（constrained random），用仿真随机向量探索状态空间<ul><li>约束随机更容易“撞出” bug（尤其是 corner case）</li><li>自动生成激励，适合长时间跑回归</li></ul></li><li>验证的 CCC：<ul><li>checker：自动检查结果是否正确</li><li>coverage：量化“跑到了多少场景”，暴露覆盖空洞</li><li>constraint：通过约束控制随机空间；有覆盖空洞时，通常通过调整&#x2F;添加约束来引导命中</li></ul></li></ul><h4 id="2-1-1-agent（可复用单元）结构与事务流"><a href="#2-1-1-agent（可复用单元）结构与事务流" class="headerlink" title="2.1.1 agent（可复用单元）结构与事务流"></a>2.1.1 agent（可复用单元）结构与事务流</h4><ul><li>每个 DUT 主要接口通常配 1 个 agent（总线&#x2F;分组&#x2F;串行等）</li><li>agent 的典型“下游&#x2F;上游”分工：<ul><li>下游：sequencer + driver 生成激励并注入 DUT</li><li>上游：monitor 采样引脚，组装为 transaction，分发到 checker&#x2F;coverage 等分析组件</li></ul></li></ul><pre><code class="highlight mermaid">flowchart TD    AGT[agent]    SEQ[sequencer] --&gt;|item| DRV[driver]    DRV --&gt;|pins| DUT[DUT interface]    DUT --&gt;|pins| MON[monitor]    MON --&gt;|transaction| CHK[checker/scoreboard]    MON --&gt;|transaction| COV[coverage]</code></pre><h4 id="2-1-2-sequence-sequencer-的“动态-vs-准静态”"><a href="#2-1-2-sequence-sequencer-的“动态-vs-准静态”" class="headerlink" title="2.1.2 sequence &#x2F; sequencer 的“动态 vs 准静态”"></a>2.1.2 sequence &#x2F; sequencer 的“动态 vs 准静态”</h4><ul><li>sequence 是 object：运行时动态执行（典型在 run_phase），在 sequencer 上运行并生成 transaction</li><li>sequence 的 body 不止能发 transaction：也常用来 start 子 sequence，或通过寄存器模型读写寄存器</li><li>sequencer 是 component：准静态，在 build_phase 0 时刻创建并驻留在组件树中</li></ul><h4 id="2-1-3-sequencer-driver：TLM-pull-接口（图片重画）"><a href="#2-1-3-sequencer-driver：TLM-pull-接口（图片重画）" class="headerlink" title="2.1.3 sequencer-driver：TLM pull 接口（图片重画）"></a>2.1.3 sequencer-driver：TLM pull 接口（图片重画）</h4><ul><li>driver 与 sequencer 的连接是事务级（TLM），常见形式是 “pull”：driver 主动拉取 item</li><li>连接形态上：<ul><li>driver 侧是 port（提出“我需要 get_next_item&#x2F;item_done 这一套接口”）</li><li>sequencer 侧是 export（声明“我提供这一套接口的实现”）</li></ul></li><li>直觉上会觉得 transaction 从左到右流动，但控制流（函数调用）常是从右到左发起</li></ul><pre><code class="highlight mermaid">flowchart LR    DRV[driver] --&gt;|connect| P[&quot;seq_item_port&lt;br/&gt;uvm_seq_item_pull_port&quot;]    P --&gt; E[&quot;seq_item_export&lt;br/&gt;uvm_seq_item_pull_export&quot;]    E --&gt; SEQ[sequencer]</code></pre><h4 id="2-1-4-transaction（sequence-item）的建议写法"><a href="#2-1-4-transaction（sequence-item）的建议写法" class="headerlink" title="2.1.4 transaction（sequence_item）的建议写法"></a>2.1.4 transaction（sequence_item）的建议写法</h4><ul><li>transaction 通常继承 uvm_sequence_item</li><li>用 <code>uvm_object_utils</code> 注册到工厂（transaction 不是 component，没有 parent）</li><li>字段加 rand，并加合法性约束保证随机结果“至少像样”</li><li>建议实现 <code>convert2string()</code>，便于 log&#x2F;compare&#x2F;调试</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_trans <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">  `uvm_object_utils(my_trans)</span><br><span class="line">  <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">7</span>:<span class="number">0</span>]  cmd;</span><br><span class="line">  <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">31</span>:<span class="number">0</span>] addr;</span><br><span class="line">  <span class="keyword">rand</span> <span class="keyword">bit</span> [<span class="number">31</span>:<span class="number">0</span>] data;</span><br><span class="line">  <span class="keyword">constraint</span> legal_c &#123; cmd <span class="keyword">inside</span> &#123;[<span class="number">0</span>:<span class="number">3</span>]&#125;; &#125;</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;my_trans&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h4 id="2-1-5-典型发包四步：create-→-start-item-→-randomize-→-finish-item"><a href="#2-1-5-典型发包四步：create-→-start-item-→-randomize-→-finish-item" class="headerlink" title="2.1.5 典型发包四步：create → start_item → randomize → finish_item"></a>2.1.5 典型发包四步：create → start_item → randomize → finish_item</h4><ul><li>最小 sequence 往往就是“发 1 笔 transaction”，常见四步如下</li><li><code>uvm_do(req)</code> 是宏封装，初学阶段更建议显式四步，便于理解握手点在哪里</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> one_tx_seq <span class="keyword">extends</span> uvm_sequence<span class="variable">#(my_trans)</span>;</span><br><span class="line">  `uvm_object_utils(one_tx_seq)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;one_tx_seq&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">    my_trans req;</span><br><span class="line">    req = my_trans::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">    start_item(req);</span><br><span class="line">    <span class="keyword">void</span>&#x27;(req<span class="variable">.randomize</span>());</span><br><span class="line">    finish_item(req);</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h4 id="2-1-6-start-item-finish-item-与-get-next-item-item-done-的握手（图片重画）"><a href="#2-1-6-start-item-finish-item-与-get-next-item-item-done-的握手（图片重画）" class="headerlink" title="2.1.6 start_item &#x2F; finish_item 与 get_next_item &#x2F; item_done 的握手（图片重画）"></a>2.1.6 start_item &#x2F; finish_item 与 get_next_item &#x2F; item_done 的握手（图片重画）</h4><ul><li>同步点 1：<code>start_item</code> 与 <code>get_next_item</code></li><li>同步点 2：<code>finish_item</code> 与 <code>item_done</code></li><li>谁先调用决定“阻塞发生在哪一端”，但协议是同一套</li></ul><pre><code class="highlight mermaid">sequenceDiagram    participant S as sequence    participant D as driver    Note over S,D: Case A：sequence 先 start_item    S-&gt;&gt;D: start_item(req) (block)    D-&gt;&gt;S: get_next_item(req)    S-&gt;&gt;S: randomize/赋值    S-&gt;&gt;D: finish_item(req) (block)    D-&gt;&gt;D: drive pins    D-&gt;&gt;S: item_done()    S-&gt;&gt;S: finish_item 返回    Note over S,D: Case B：driver 先 get_next_item    D-&gt;&gt;S: get_next_item(req) (block)    S-&gt;&gt;D: start_item(req) (立刻返回)    S-&gt;&gt;S: randomize/赋值    S-&gt;&gt;D: finish_item(req)    D-&gt;&gt;D: drive pins    D-&gt;&gt;S: item_done()</code></pre><h4 id="2-1-7-启动子-sequence-与随机稳定性"><a href="#2-1-7-启动子-sequence-与随机稳定性" class="headerlink" title="2.1.7 启动子 sequence 与随机稳定性"></a>2.1.7 启动子 sequence 与随机稳定性</h4><ul><li>父 sequence 启动子 sequence：<code>child.start(m_sequencer, this)</code></li><li>更完整（强调随机稳定性&#x2F;phase 语义）的启动步骤：<ul><li>create 子 sequence</li><li><code>set_item_context(this, m_sequencer)</code>（让子 sequence “绑定”到将要运行的 sequencer 上下文）</li><li>randomize 子 sequence（若其自身有 rand 参数）</li><li><code>set_starting_phase(phase)</code>（让该 sequence 可对 phase raise&#x2F;drop objection）</li></ul></li></ul><h4 id="2-1-8-virtual-sequence：跨多个-agent-的编排器（图片重画）"><a href="#2-1-8-virtual-sequence：跨多个-agent-的编排器（图片重画）" class="headerlink" title="2.1.8 virtual sequence：跨多个 agent 的编排器（图片重画）"></a>2.1.8 virtual sequence：跨多个 agent 的编排器（图片重画）</h4><ul><li>virtual sequence 的核心价值：统一编排多个接口上的激励行为</li><li>一般不直接产生 transaction；更多是启动多个子 sequence</li></ul><pre><code class="highlight mermaid">flowchart TD    VSEQ[virtual sequence] --&gt;|start| SEQ1[agent1 sequencer]    VSEQ --&gt;|start| SEQ2[agent2 sequencer]    SEQ1 --&gt; DRV1[agent1 driver]    SEQ2 --&gt; DRV2[agent2 driver]    DRV1 --&gt; DUT1[DUT if1]    DRV2 --&gt; DUT2[DUT if2]</code></pre><h4 id="2-1-9-从-sequence-取配置：以“当前-sequencer”为锚点"><a href="#2-1-9-从-sequence-取配置：以“当前-sequencer”为锚点" class="headerlink" title="2.1.9 从 sequence 取配置：以“当前 sequencer”为锚点"></a>2.1.9 从 sequence 取配置：以“当前 sequencer”为锚点</h4><ul><li>常见思路：环境 build_phase 把配置对象 set 到与某个 agent&#x2F;sequencer 路径绑定的位置</li><li>sequence 运行时通过 <code>get_sequencer()</code> 拿到当前 sequencer，再按该路径 get 配置</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> cfg_seq <span class="keyword">extends</span> uvm_sequence<span class="variable">#(my_trans)</span>;</span><br><span class="line">  `uvm_object_utils(cfg_seq)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;cfg_seq&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">    my_cfg cfg;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(my_cfg)::get(null, get_sequencer().get_full_name(), &quot;cfg&quot;, cfg))</span>;</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>基于配置生成多笔事务（文章示例思路：cfg.count 决定循环次数，并用内联约束绑定字段）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; cfg<span class="variable">.count</span>; i++) <span class="keyword">begin</span></span><br><span class="line">  my_trans req;</span><br><span class="line">  req = my_trans::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">  start_item(req);</span><br><span class="line">  <span class="keyword">void</span>&#x27;(req<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123; data == i; &#125;);</span><br><span class="line">  finish_item(req);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h4 id="2-1-10-TLM-三套常用方法：put-get-write（阻塞与数据-控制流）"><a href="#2-1-10-TLM-三套常用方法：put-get-write（阻塞与数据-控制流）" class="headerlink" title="2.1.10 TLM 三套常用方法：put &#x2F; get &#x2F; write（阻塞与数据&#x2F;控制流）"></a>2.1.10 TLM 三套常用方法：put &#x2F; get &#x2F; write（阻塞与数据&#x2F;控制流）</h4><ul><li>put&#x2F;get：阻塞（task），适合传递“不会丢、不覆盖”的事务流<ul><li>put：生产者 push 给消费者；直到对端准备好接收才返回</li><li>get：消费者从生产者 pull；直到生产者准备好返回事务才返回；返回后“下次 get 得到下一个”</li></ul></li><li>write：非阻塞（function），常用于 analysis 通道广播；接收方必须“立刻处理并返回”</li></ul><p>push vs pull 的“数据流&#x2F;控制流”对比：</p><pre><code class="highlight mermaid">flowchart LR    PUSH[&quot;push (put)&quot;]    P1[producer] --&gt;|control put| C1[consumer]    P1 --&gt;|data tx| C1    PULL[&quot;pull (get)&quot;]    C2[consumer] --&gt;|control get| P2[producer]    P2 --&gt;|data tx| C2</code></pre><h4 id="2-1-11-port-export-imp：方法调用如何穿过层级（图片重画）"><a href="#2-1-11-port-export-imp：方法调用如何穿过层级（图片重画）" class="headerlink" title="2.1.11 port &#x2F; export &#x2F; imp：方法调用如何穿过层级（图片重画）"></a>2.1.11 port &#x2F; export &#x2F; imp：方法调用如何穿过层级（图片重画）</h4><ul><li>port：让组件“向外”发起对外部方法的调用</li><li>export：让组件“向内”接收并转发方法调用（中继点）</li><li>imp：终点，拥有 imp 的组件需要提供该方法的最终实现</li></ul><p>层级穿透的直觉：port 把调用一路“往上抛”，到顶层再对接 export，再沿 export “往下传”，直到落到 imp。</p><pre><code class="highlight mermaid">flowchart TD    UP[&quot;Call up through ports&quot;]    CHILD[child] --&gt; PORT_C[port]    PORT_C --&gt; PORT_P[parent port]    PORT_P --&gt; PORT_T[top port]    PORT_T --&gt; EXP_T[top export]    DOWN[&quot;Call down through exports to imp&quot;]    EXP_T --&gt; EXP_P[parent export]    EXP_P --&gt; IMP[imp]    IMP --&gt; LEAF[leaf implements method]</code></pre><h4 id="2-1-12-analysis-port：广播式-write（monitor→agent→订阅者）（图片重画）"><a href="#2-1-12-analysis-port：广播式-write（monitor→agent→订阅者）（图片重画）" class="headerlink" title="2.1.12 analysis_port：广播式 write（monitor→agent→订阅者）（图片重画）"></a>2.1.12 analysis_port：广播式 write（monitor→agent→订阅者）（图片重画）</h4><ul><li>analysis_port 的特性：0&#x2F;1&#x2F;多 连接；monitor&#x2F;agent 不需要知道 transaction 去向</li><li>只提供 <code>write(tx)</code>：非阻塞、只读语义（不应修改 tx），订阅者被回调顺序不可控</li></ul><pre><code class="highlight mermaid">flowchart LR    MON[monitor] --&gt;|write| AP0[analysis_port]    AP0 --&gt; AP1[agent analysis_port]    AP1 --&gt;|write| SUB1[subscriber1]    AP1 --&gt;|write| SUB2[subscriber2]    AP1 --&gt;|write| SUB3[subscriber3]</code></pre><h4 id="2-1-13-subscriber-多路分析流-analysis-fifo：三种常见落地方式"><a href="#2-1-13-subscriber-多路分析流-analysis-fifo：三种常见落地方式" class="headerlink" title="2.1.13 subscriber &#x2F; 多路分析流 &#x2F; analysis_fifo：三种常见落地方式"></a>2.1.13 subscriber &#x2F; 多路分析流 &#x2F; analysis_fifo：三种常见落地方式</h4><ul><li>单路接收：用 uvm_subscriber（内置 analysis_imp），实现对应的 <code>write(tx)</code> 做 checker&#x2F;coverage</li><li>多路接收：同一组件要处理多路 analysis 流时，用 <code>uvm_analysis_imp_decl(_x)</code> 生成多个 imp 类型与 <code>write_x</code> 方法，绕开 SV 不支持函数重载的问题</li><li>延迟处理：不想在 write 里立即处理时，可用 uvm_tlm_analysis_fifo 缓存，再在 run_phase 用阻塞 get 拉取处理</li><li>analysis_port &#x2F; analysis_fifo 的更细代码示例：可对照本笔记的 <a href="#181-analysis-%E7%AB%AF%E5%8F%A3%E9%80%9A%E4%BF%A1">18.1</a> &#x2F; <a href="#182-fifo-%E9%80%9A%E4%BF%A1">18.2</a></li></ul><pre><code class="highlight mermaid">flowchart TD    MON[monitor] --&gt;|write| AP[analysis_port]    AP --&gt;|write| FIFO[uvm_tlm_analysis_fifo]    FIFO --&gt;|get| WORKER[run_phase loop]</code></pre><h2 id="3-seq-sqr-drv-通信"><a href="#3-seq-sqr-drv-通信" class="headerlink" title="3 seq &#x2F; sqr &#x2F; drv 通信"></a>3 seq &#x2F; sqr &#x2F; drv 通信</h2><p>在UVM（Universal Verification Methodology）中，Driver和Sequencer是两个重要的组件，用于实现测试环境中的数据传输和控制。<br>Sequence的主要作用是生成和控制测试用例的执行流程。它可以定义一系列需要执行的事务，并指定它们的顺序、重复次数、延迟等属性。Sequence可以包含条件语句、循环语句和分支语句，以实现复杂的测试场景。<br>Driver是一个用于驱动输入信号到被测设计（DUT）的组件。它负责将事务（transaction）从Sequencer获取，并将其转换为适当的信号或协议操作来驱动DUT。<br>Sequencer是一个用于生成和管理事务的组件。它负责生成测试用例中的事务，并将其传递给Driver以驱动DUT。Driver和Sequencer之间的通信是通过UVM提供的基于事务的接口进行的。（阻塞）</p><pre><code class="highlight mermaid">flowchart LR    TEST[&quot;test or vseq&quot;]    SEQ[&quot;sequence uvm_sequence&quot;] --&gt;|start| SQR[&quot;sequencer uvm_sequencer&quot;]    DRV[&quot;driver uvm_driver&quot;] --&gt;|connect| SQR    DRV --&gt;|pins| DUT[DUT]</code></pre><h3 id="3-1-driver-和-sequencer-的通信"><a href="#3-1-driver-和-sequencer-的通信" class="headerlink" title="3.1 driver 和 sequencer 的通信"></a>3.1 driver 和 sequencer 的通信</h3><p>在UVM中，Driver和Sequencer之间的通信机制如下：<br>1、Sequencer接收一个事务，并将其放入一个事务队列中。<br>2、Driver通过轮询或其他机制检查事务队列是否有新的事务。<br>3、如果Driver检测到有新的事务，它会从事务队列中取出事务，并将其转换为适当的信号或协议操作来驱动DUT。<br>4、Driver完成对事务的驱动后，可以通过事务接口向Sequencer发送一些响应信息，例如完成状态或错误信息。<br>5、Sequencer可以根据Driver的响应信息来调整发送下一个事务。 </p><pre><code class="highlight mermaid">sequenceDiagram    participant SEQ as sequence    participant SQR as sequencer    participant DRV as driver    participant DUT as DUT    SEQ-&gt;&gt;SQR: start()    DRV-&gt;&gt;SQR: get_next_item(req)    SQR--&gt;&gt;DRV: req    DRV-&gt;&gt;DUT: drive pins    DRV-&gt;&gt;SQR: item_done(rsp_ok)</code></pre><h3 id="3-2-sequence-和-sequencer-的通信"><a href="#3-2-sequence-和-sequencer-的通信" class="headerlink" title="3.2 sequence 和 sequencer 的通信"></a>3.2 sequence 和 sequencer 的通信</h3><p>Sequence通过调用Sequencer的start()方法来启动。</p><p>body 是什么：</p><ul><li>sequence 的核心入口是 <code>virtual task body()</code>，sequence 被 start 之后，就会执行 body（严格来说会按 <code>pre_body -&gt; body -&gt; post_body</code> 顺序执行）</li><li>body 里一般做三类事：发 transaction（start_item&#x2F;finish_item 或 uvm_do 宏）、启动子 sequence、做寄存器模型访问&#x2F;场景编排（分支&#x2F;循环&#x2F;约束随机）</li><li>body 的“通信点”本质就是调用 sequencer 的接口：<code>start_item/finish_item</code> 内部会走 <code>wait_for_grant / send_request / wait_for_item_done</code>，从而和 driver 的 <code>get_next_item/item_done</code> 对齐</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_seq <span class="keyword">extends</span> uvm_sequence<span class="variable">#(my_trans)</span>;</span><br><span class="line">  `uvm_object_utils(my_seq)</span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">    my_trans req;</span><br><span class="line">    req = my_trans::type_id::create(<span class="string">&quot;req&quot;</span>);</span><br><span class="line">    start_item(req);</span><br><span class="line">    <span class="keyword">void</span>&#x27;(req<span class="variable">.randomize</span>());</span><br><span class="line">    finish_item(req);</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>它是什么 phase：</p><ul><li>sequence 是 <code>uvm_object</code>，不是 <code>uvm_component</code>，因此它本身没有 <code>run_phase/main_phase/...</code> 这种 phase 回调</li><li>sequence 的执行发生在“启动它的那个 component 的 task phase”里：最常见是在 test&#x2F;virtual sequence 的 <code>main_phase</code>（也有人放 <code>run_phase</code>）</li><li>如果把 sequence 配成某个 phase 的 <code>default_sequence</code>，则 UVM 会在该 phase 自动启动它，并把 <code>starting_phase</code> 指向那个 phase</li><li>需要用 objection 控制仿真时，建议在 sequence 里用 <code>starting_phase</code> 起落 objection（仅当它非空时）</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">virtual</span> <span class="keyword">task</span> pre_body();</span><br><span class="line">  <span class="keyword">if</span> (starting_phase != <span class="literal">null</span>) starting_phase<span class="variable">.raise_objection</span>(<span class="keyword">this</span>);</span><br><span class="line"><span class="keyword">endtask</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">virtual</span> <span class="keyword">task</span> post_body();</span><br><span class="line">  <span class="keyword">if</span> (starting_phase != <span class="literal">null</span>) starting_phase<span class="variable">.drop_objection</span>(<span class="keyword">this</span>);</span><br><span class="line"><span class="keyword">endtask</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>经验</strong> 常在 case 的 main_phase 里 start 启动 sequence（drive 主要功能在 main_phase），控制 sequence 的 body 任务执行；driver 不断接收 sequence 发送的 trans（fork…join 包含两部分：接收 trans &#x2F; 驱动 DUT）。待 sequence 的 body 执行完后（结束 start_item&#x2F;finish_item），case 的 <code>seq.start(sqr)</code> 语句执行完毕。</p></blockquote><div class="note info flat"><blockquote><p><strong>注意</strong> sequence &#x2F; driver &#x2F; sequencer 之间传递的 trans 需要保持同一类型；若不同 trans 类型，需要转换。</p></blockquote></div><p>扩展：sequence-driver-sequencer communication approaches</p><p>sequence 的执行步骤：</p><ol><li>sequence 启动，使 m_sequencer 指向 sequencer。</li><li>使用 m_sequencer.wait_for_grant 仲裁多个 sequence（优先级）—— start_item。</li><li>使用 m_sequencer.send_request 发送 item（trans）至 REQ_FIFO，并等待 wait_for_item_done 完成 —— finish_item。</li></ol><h2 id="4-set-和-get-寄收信"><a href="#4-set-和-get-寄收信" class="headerlink" title="4 set 和 get 寄收信"></a>4 set 和 get 寄收信</h2><p>UVM普遍采用这种方式存（set）、取（get）信息。对于config_db机制，set()方法把需要的资源放进全局可见的数据库；get()方法从全局可见的数据库输出需要的资源。（不用UVM树形成就可调用set方法）</p><h3 id="4-1-寄信方格式（set）"><a href="#4-1-寄信方格式（set）" class="headerlink" title="4.1 寄信方格式（set）"></a>4.1 寄信方格式（set）</h3><p>原型：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(T)</span>::set(</span><br><span class="line">  uvm_component cntxt,</span><br><span class="line">  <span class="keyword">string</span> inst_name,</span><br><span class="line">  <span class="keyword">string</span> filed_name,</span><br><span class="line">  T value</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>数据类型T可以是：virtual interface，int，string，enum，对象等；<br>第一个参数：参数类型uvm_component需要是一个实例句柄，可以是null；<br>第二个参数：数据类型string需要是字符串，相对此实例的路径；<br>第三个参数：数据类型string需要是字符串，与get的第三个参数一致；<br>第四个参数：传递的数据内容。</p><p>示例：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(邮件类型)::set(A, &quot;B&quot;, &quot;邮件名字&quot;, 邮件内容)</span>;</span><br></pre></td></tr></table></figure><h3 id="4-2-收信方格式（get）"><a href="#4-2-收信方格式（get）" class="headerlink" title="4.2 收信方格式（get）"></a>4.2 收信方格式（get）</h3><p>原型：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(T)</span>::get(</span><br><span class="line">  uvm_component cntxt,</span><br><span class="line">  <span class="keyword">string</span> inst_name,</span><br><span class="line">  <span class="keyword">string</span> filed_name,</span><br><span class="line">  <span class="keyword">inout</span> T value</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>参数的意义与set方法一致。</p><p>示例：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(邮件类型)::get(A, &quot;B&quot;, &quot;邮件名字&quot;, 邮件内容)</span>;</span><br></pre></td></tr></table></figure><div class="note info flat"><blockquote><p><strong>注意</strong> set() 和 get() 中前三个参数所指向的目标变量路径必须保持一致，才能保证 set&#x2F;get 作用于同一变量。（若 A+B 组合后的路径不存在，只要 get 的第 1、2 个参数组合后与 set 的第 1、2 个参数一致，仍可传递数据内容）</p></blockquote></div><h3 id="4-3-直线-非直线-获取"><a href="#4-3-直线-非直线-获取" class="headerlink" title="4.3 直线 &#x2F; 非直线 获取"></a>4.3 直线 &#x2F; 非直线 获取</h3><ul><li>直线：通常 tb_top 往 drv 寄信，在 drv 收信。</li><li>非直线：tb_top 往 drv 寄信，agt 也能得到寄往 drv 的信。收信时只要前两参数合并指向同一地址，且类型与信件名字一致，通讯就建立起来。</li></ul><div class="note info flat"><blockquote><p><strong>注意</strong></p></blockquote></div><blockquote><ul><li>set&#x2F;get 通常只用于 component 间通信。</li><li>调用 set 时第一个参数尽量使用 this；在无法得到 this 指针的情况下（如 top_tb），使用 null 或 uvm_root::get()（二者等价）。</li><li>寄&#x2F;收 virtual interface 时传递的是句柄：interface 内容变化，get 到该 interface 的组件也能感知；寄&#x2F;收非句柄（变量值等）传递的是变量值，后续变化不会自动同步到其它组件。</li></ul></blockquote><h2 id="5-1-UVM-基础结构"><a href="#5-1-UVM-基础结构" class="headerlink" title="5.1 UVM 基础结构"></a>5.1 UVM 基础结构</h2><p>常用的派生自uvm_object的类：<br>uvm_sequence_item：所有的transaction都要从uvm_sequence_item派生。</p><p>uvm_sequence：所有sequence要从uvm_sequence派生。sequence就是sequence_item的组合。sequence直接与sequencer打交道，当driver向sequencer索要数据时，sequencer会检查是否有sequence要发送数据。当发现有sequence_item待发送时，会把此sequence_item交给driver。</p><p>uvm_reg_map、uvm_mem、uvm_reg_field、uvm_reg、uvm_reg_fild、uvm_reg_block等与寄存器相关的众多的类都是派生自uvm_object，它们都是用于register model。</p><p>常用的派生自uvm_component的类：<br>构成环境的组件都从uvm_component类继承而来，这是因为它们都从uvm_component类继承了phase机制，都会经历各个phase阶段。常见组件如下：</p><p>uvm_sequencer：所有的sequencer都要派生自uvm_sequencer。<br>sequencer功能：组织管理sequence，driver申请数据时，它就把sequence生成的sequence_item发给driver。</p><p>uvm_driver：所有的driver都要派生自uvm_driver。<br>driver功能：向sequencer申请sequence_item(数据包)，并将包里的信息按照总线协议规定驱动到DUT的端口上。</p><p>uvm_monitor：所有的的monitor都要派生自uvm_monitor。<br>monitor功能：从DUT接收数据，并将其转成transaction级别的sequence_item，发送给scoreboard，供其比较。</p><p>uvm_agent：所有的agent要派生自uvm_agent。<br>agent功能：将sequencer、driver和monitor封装在一起，agent模块的使用提高了代码的可重用性。（UVM_ACTIVE&#x2F;UVM_PASSIVE、两种模式）</p><p>uvm_scoreboard：一般的scoreboard都要派生自uvm_scoreboard。<br>scoreboard功能：比较reference model和monitor分别发送来的数据，根据比较结果判断DUT是否正确工作。</p><p>uvm_env：所有的env要派生自uvm_env。<br>env功能：将平台上的component组件封装在一起，实现一个环境多个用例。运行不同用例时，在其中实例化env即可。</p><p>uvm_test：所有的测试用例要派生自uvm_test或其派生类。<br>任何一个派生的测试用例中，都要实例化env。这样当用例运行时，才能把数据发给DUT，并接收DUT的数据。</p><p>reference model：UVM中并没有针对reference model定义一个类。通常，reference model直接派生自uvm_component。<br>作用就是“模仿DUT，完成与DUT相同的功能”。DUT是用Verilog写成的时序电路，而reference model则可以直接使用verilog高级语言的特性，同时还可以通过DPI等接口调用其他语言来完成与DUT相同的功能。</p><h2 id="5-2-UVM-树的构建"><a href="#5-2-UVM-树的构建" class="headerlink" title="5.2 UVM 树的构建"></a>5.2 UVM 树的构建</h2><p>uvm_object是UVM中最基本的类，几乎全部的类都是由uvm_object类派生出来，其中包含uvm_component。</p><p>uvm_component有两大特性是uvm_object所不具备的。一是通过在new的时候指定parent参数来产生一种树形的组织结构，二是有phase的自动执行特点。UVM树的结点都是由uvm_component构成的，只有基于uvm_component派生出的类才有可能是UVM树的结点。<br>典型的UVM树如下图：（uvm_root是唯一“树根“）</p><h2 id="6-UVM-的打印"><a href="#6-UVM-的打印" class="headerlink" title="6 UVM 的打印"></a>6 UVM 的打印</h2><p><code>uvm_fatal、</code>uvm_error和<code>uvm_warning等宏只有两个参数，而</code>uvm_info就是三个参数。</p><h3 id="6-1-uvm-info-的打印等级"><a href="#6-1-uvm-info-的打印等级" class="headerlink" title="6.1 uvm_info 的打印等级"></a>6.1 uvm_info 的打印等级</h3><p>UVM_NONE的冗余度最低，即无论平台将UVM_VERBOSITY设置为什么级别，都会打印UVM_NONE。（uvm_warning、uvm_error和uvm_fatal默认等级为uvm_none，一定打印）<br>（1）UVM中，默认的冗余度阈值是UVM_MEDIUM，所有低于等于UVM_MEDIUM（如UVM_LOW和UVM_MEDIUM）的信息都会被打印出来。<br>（2）UVM提供set_report_verbosity_level函数来设置某个特定component的默认冗余度阈值，如env.i_agt.drv.set_report_verbosity_level(UVM_HIGH)表示为DRV组件中，低于等于UVM_HIGH冗余度阈值的都会打印。<br>（3）UVM提供set_report_verbosity_level_hier函数来指定某个component下所有的component的冗余度阈值阈值。如env.i_agt.set_report_verbostiry_level_hier(UVM_HIGH)表示i_agt及其下所有的component的冗余度阈值将配置为UVM_HIGH。</p><div class="note info flat"><blockquote><p><strong>注意</strong> 一般在 case 里配置（需要在 connect_phase 后），也可以在组件内配置（任意位置）。另外，打印与函数位置有关：函数位置后按设置的打印等级生效；函数位置前仍按原先等级打印。</p></blockquote></div><h3 id="6-2-uvm-位置打印函数"><a href="#6-2-uvm-位置打印函数" class="headerlink" title="6.2 uvm 位置打印函数"></a>6.2 uvm 位置打印函数</h3><p>uvm打印中常使用下述函数表示打印所在的位置：</p><ul><li>get_type_name()：返回对象 class 的名字。</li><li>get_name()：返回创建对象时传入的字符串。</li><li>get_full_name()：返回当前 component 的完整 UVM 树路径；object 类的返回值与 get_name() 一样（object 不是 UVM 树节点，所以路径没有层次）。</li></ul><p>总结：上述被调用时，get_name()返回创建对象时的字符串。get_type_name()返回对象class名字。get_full_name()返回组件UVM树的完整路径。</p><h3 id="6-3-sprintf-与-sformatf"><a href="#6-3-sprintf-与-sformatf" class="headerlink" title="6.3 $sprintf 与 $sformatf"></a>6.3 $sprintf 与 $sformatf</h3><p>$sprintf 和 $sformatf 都是 verilog 中用于格式化字符串的系统函数。它们可以使用格式说明符指定输出字符串的格式（如宽度、精度、基数等）。区别在于：</p><ul><li>$sprintf：返回一个 string</li><li>$sformatf：不返回值（直接得到格式化结果）</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$sprintf(<span class="string">&quot;info... value=%0d&quot;</span>, value);</span><br></pre></td></tr></table></figure><h3 id="6-4-重载打印严重性"><a href="#6-4-重载打印严重性" class="headerlink" title="6.4 重载打印严重性"></a>6.4 重载打印严重性</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aaa<span class="variable">.bbb</span><span class="variable">.ccc</span><span class="variable">.set_report_severity_override</span>(UVM_WARNING, UVM_ERROR);</span><br></pre></td></tr></table></figure><p>该方法可以将组件 ccc 的 UVM_WARNING 打印信息重载为 UVM_ERROR。</p><h2 id="7-phase-执行顺序"><a href="#7-phase-执行顺序" class="headerlink" title="7 phase 执行顺序"></a>7 phase 执行顺序</h2><p>UVM树的执行顺序有三种：自上而下、自下而上和随机序。<br>UVM内所有的phase如下图所示，不同phase间的执行顺序从时间上讲是从上往下执行的（所有的phase，包括function phase和task phase）</p><h3 id="7-1-function-phase-执行顺序"><a href="#7-1-function-phase-执行顺序" class="headerlink" title="7.1 function phase 执行顺序"></a>7.1 function phase 执行顺序</h3><p>对于function phase来说，即不耗费仿真时间的phase（function phase），同一类phase，除了build phase自上而下执行之外，其它的function phase都是自下而上执行的。<br>例如：对于connect_phase即先执行driver和monitor的connect_phase，再执行agent的connect_phase。<br>（build_phase一般用于实例化组件，如果自下而上，那么组件还没有实例化，若调用其方法，则会报错，如in_agent）<br>对于同一层次的、具有兄弟关系的component，它们的phase的执行顺序是按照字典序执行的，这里字典的排序依据new时指定的名字。</p><h3 id="7-2-task-phase-执行顺序"><a href="#7-2-task-phase-执行顺序" class="headerlink" title="7.2 task phase 执行顺序"></a>7.2 task phase 执行顺序</h3><p>对于同一类 run phase，其执行顺序是自下而上执行，同时在运行（并行执行）。对于同一组件的 run phase（不同 task phase），其执行顺序是自上而下执行的。</p><p>由上可知，run phase是同时执行的，待同一层的task phase执行完后，再同时执行下一层的task phase，中间可能会存在空白等待时间。如上，同时执行A和B的main_phase，待A的main_phase和B的main_phase都执行完后，再同时执行A和B的post_main_phase，待A的post_main_phase和B的post_main_phase都执行完后，在接着往下执行。</p><p>对于run_phase，是通过fork….join_none包裹起来了，虽然都是“并行”执行，但其实存在先后顺序的。也就是说，类似run_phase、main_phase等task_phase也都是按照自下而上的顺序执行的，虽然同一层此task phase是同时启动的。</p><h2 id="9-UVM-类的继承"><a href="#9-UVM-类的继承" class="headerlink" title="9 UVM 类的继承"></a>9 UVM 类的继承</h2><h2 id="10-前门-后门访问"><a href="#10-前门-后门访问" class="headerlink" title="10 前门 &#x2F; 后门访问"></a>10 前门 &#x2F; 后门访问</h2><h3 id="10-1-寄存器模型前-后门访问"><a href="#10-1-寄存器模型前-后门访问" class="headerlink" title="10.1 寄存器模型前&#x2F;后门访问"></a>10.1 寄存器模型前&#x2F;后门访问</h3><p>寄存器模型针对模块里的寄存器，UVM提供了基于寄存器模型的两种访问方式，分为前门访问和后门访问：</p><ul><li>前门访问：通过模拟 CPU 在总线上发出读&#x2F;写指令，进行真实物理总线操作。常用于验证寄存器读写是否正常。</li><li>后门访问：不通过物理总线，直接层次化引用方式访问寄存器。常用于测试与调试。</li></ul><table><thead><tr><th>特性</th><th>前门访问</th><th>后门访问</th></tr></thead><tbody><tr><td>访问方式</td><td>通过总线物理信号时序实现寄存器读写</td><td>通过 UVM DPI 直接操作 DUT 内部寄存器变量</td></tr><tr><td>仿真时间</td><td>消耗仿真时间，等待总线返回应答后结束</td><td>瞬时生效，不消耗仿真时间</td></tr><tr><td>域字段操作</td><td>只能对整个位宽读写，不能单独操作域字段</td><td>可以单独对域字段读写</td></tr><tr><td>时序</td><td>正确反映寄存器操作的时序关系</td><td>不受硬件时序控制，可能与硬件行为产生时序冲突</td></tr><tr><td>预测方式</td><td>依靠监测总线对寄存器模型做预测</td><td>依靠自动预测方式做预测</td></tr></tbody></table><p>另外，对于寄存器的后门访问，UVM提供了两类后门访问的函数：一是UVM_BACKDOOR形式的read和write，二是peek和poke方式。前者会在操作时模仿DUT的行为，后者完全不管DUT的行为。如对一个只读寄存器进行写操作，前者模拟DUT的只读行为，所以写不进去，后者可以写进去（poke）。</p><p>注：force属于后门访问的一种方法，不仅可以访问reg类型，也可以访问wire类型。</p><h3 id="10-2-后门访问-DUT-内部信号（常用）"><a href="#10-2-后门访问-DUT-内部信号（常用）" class="headerlink" title="10.2 后门访问 DUT 内部信号（常用）"></a>10.2 后门访问 DUT 内部信号（常用）</h3><p>针对寄存器使用的 DPI&#x2F;PLI 后门访问提供接口。</p><p><strong>变量</strong></p><ul><li>UVM_HDL_MAX_WIDTH：设置后门访问数据位宽，可在编译选项中调整宏定义最大位宽。</li></ul><p><strong>方法</strong></p><ul><li>uvm_hdl_check_path：检查给定 HDL 路径是否存在</li><li>uvm_hdl_deposit：将给定 HDL 路径设置为指定值</li><li>uvm_hdl_force：强制给定路径上的值（常用）</li><li>uvm_hdl_force_time：强制给定路径上的值为指定数量的 force_time</li><li>uvm_hdl_release_and_read：释放先前 force 的值并读取</li><li>uvm_hdl_release：释放先前 force 的值（常用）</li><li>uvm_hdl_read：读取给定路径的值（常用）</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">uvm_hdl_force(<span class="built_in">$sformatf</span>(<span class="string">&quot;&quot;</span>), value);</span><br><span class="line">uvm_hdl_release(<span class="built_in">$sformatf</span>(<span class="string">&quot;&quot;</span>));</span><br><span class="line">uvm_hdl_read(<span class="built_in">$sformatf</span>(<span class="string">&quot;&quot;</span>), value);</span><br></pre></td></tr></table></figure><div class="note info flat"><blockquote><p><strong>注意</strong> 使用 DPI 后门访问时，string 字符串为 DUT 内信号路径，需要保持一致；调用 DPI 函数时可加入返回值判断，确认是否调用成功。</p></blockquote></div><div class="note info flat"><blockquote><p><strong>注意</strong> uvm_hdl_force 一个信号后再 uvm_hdl_release：若信号未被驱动，值保持释放前的值；若被驱动，则变为驱动后的值。一般通过“路径”方式（而非总线方式）处理 DUT 信号的，都可广义视为后门访问。</p></blockquote></div><h3 id="10-3-读取数组信号（示例）"><a href="#10-3-读取数组信号（示例）" class="headerlink" title="10.3 读取数组信号（示例）"></a>10.3 读取数组信号（示例）</h3><p>使用 uvm_hdl_read 读取 DUT 信号（如 <code>reg[1:0] counter[3:0]</code>，一维&#x2F;多维数组）时，可用以下方式（uvm_hdl_force 类似）：</p><p><strong>方法 1：逐个读取</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] read_cnt[<span class="number">3</span>:<span class="number">0</span>];</span><br><span class="line">uvm_hdl_read(<span class="string">&quot;xxx.xxx.xxx.counter[0]&quot;</span>, read_cnt[<span class="number">0</span>]);</span><br><span class="line">uvm_hdl_read(<span class="string">&quot;xxx.xxx.xxx.counter[1]&quot;</span>, read_cnt[<span class="number">1</span>]);</span><br><span class="line">uvm_hdl_read(<span class="string">&quot;xxx.xxx.xxx.counter[2]&quot;</span>, read_cnt[<span class="number">2</span>]);</span><br><span class="line">uvm_hdl_read(<span class="string">&quot;xxx.xxx.xxx.counter[3]&quot;</span>, read_cnt[<span class="number">3</span>]);</span><br></pre></td></tr></table></figure><p><strong>方法 2：读取整个数组</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> [<span class="number">1</span>:<span class="number">0</span>] read_cnt[<span class="number">3</span>:<span class="number">0</span>];</span><br><span class="line">uvm_hdl_read(<span class="string">&quot;xxx.xxx.xxx.counter&quot;</span>, read_cnt);</span><br></pre></td></tr></table></figure><h2 id="11-覆盖率合并"><a href="#11-覆盖率合并" class="headerlink" title="11 覆盖率合并"></a>11 覆盖率合并</h2><ul><li>使用 <code>urg -dir aaa.vdb -dir bbb.vdb -dbname ccc.vdb</code>：合并 aaa&#x2F;bbb 的 vdb，输出 ccc.vdb。ccc.vdb 覆盖率为 aaa+bbb 的集合（不同公司可能需要 <code>bsub -Is</code> 提交任务，如 ）。</li><li>使用 <code>urg -full64 -f aaa.list -dbname bbb.vdb</code>：合并 aaa.list 中列出的所有 .vdb，输出 bbb.vdb（不同公司可能需要 <code>bsub -Is</code> 提交任务，如 ）。</li><li>查看 Makefile，使用 <code>bsub -Is make cov_merge</code> 生成 vdb（特有）。</li></ul><h2 id="12-命令行传参"><a href="#12-命令行传参" class="headerlink" title="12 命令行传参"></a>12 命令行传参</h2><p>当需要构造一些固定参数的case时（常见为定向case），且其它参数不需要较大变动即可使用外部传参。</p><p><strong>命令行执行</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-run_opt +uvm_set_config_int=&quot;uvm_test_top,xxx,value&quot;</span><br></pre></td></tr></table></figure><ul><li>uvm_test_top：传入 case 的目标实例</li><li>xxx：参数名</li><li>value：参数值</li><li>多参数：继续追加 <code>+uvm_set_config_int=&quot;uvm_test_top,xxx,value&quot;</code>，不需要空格</li></ul><p><strong>回归执行</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">;+uvm_set_config_int=&quot;uvm_test_top,xxx,value&quot;;</span><br></pre></td></tr></table></figure><p><strong>指定运行次数</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">;+uvm_set_config_int=&quot;uvm_test_top,xxx,value&quot;;n</span><br></pre></td></tr></table></figure><p>case 中获取命令行参数：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uvm_config_db<span class="variable">#(uvm_bitstream_t)::get(this, &quot;&quot;, &quot;xxx&quot;, value)</span>;</span><br></pre></td></tr></table></figure><h2 id="13-uvm-重载"><a href="#13-uvm-重载" class="headerlink" title="13 uvm 重载"></a>13 uvm 重载</h2><h3 id="13-1-virtual-关键字"><a href="#13-1-virtual-关键字" class="headerlink" title="13.1 virtual 关键字"></a>13.1 virtual 关键字</h3><ul><li>在基类中用 virtual 声明成员（函数&#x2F;任务）后，派生类可重写该成员；运行时会按对象实际类型调用对应实现（多态）。</li><li>若基类成员未声明为 virtual，则派生类无法重写，只能继承基类实现。</li><li>super 关键字：派生类可在复用父类方法的同时追加逻辑。</li></ul><h3 id="13-2-重载方法"><a href="#13-2-重载方法" class="headerlink" title="13.2 重载方法"></a>13.2 重载方法</h3><p>常用思路：用 factory 的 override，把“创建 father_class 时实际创建成 son_class”。</p><p><strong>set_type_override_by_type（全局类型重载）</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">uvm_factory::get()<span class="variable">.set_type_override_by_type</span>(</span><br><span class="line">  father_class_name::get_type(),</span><br><span class="line">  son_class_name::get_type(),</span><br><span class="line">  <span class="number">1</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>对 father_class 的全部实例进行重载。</p><p><strong>set_inst_override_by_type（实例路径重载）</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">uvm_factory::get()<span class="variable">.set_inst_override_by_type</span>(</span><br><span class="line">  relative_inst_path,</span><br><span class="line">  father_class_name::get_type(),</span><br><span class="line">  son_class_name::get_type()</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">uvm_factory::get()<span class="variable">.set_inst_override_by_type</span>(</span><br><span class="line">  <span class="string">&quot;env.fw1_req_env.credit_data_in_agt.drv&quot;</span>,</span><br><span class="line">  credit_data_in_drv::get_type(),</span><br><span class="line">  fw1_srst_in_drv::get_type()</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>对指定实例路径进行重载。</p><p><strong>set_type_override &#x2F; set_inst_override</strong></p><ul><li>与上面两种方法等价，只是用字符串代替 <code>xxx::get_type()</code>。</li></ul><p><strong>set_type_override_by_name &#x2F; set_inst_override_by_name（按类名字符串）</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">uvm_factory::get()<span class="variable">.set_type_override_by_name</span>(</span><br><span class="line">  <span class="string">&quot;father_class_name&quot;</span>,</span><br><span class="line">  <span class="string">&quot;son_class_name&quot;</span>,</span><br><span class="line">  <span class="number">1</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">uvm_factory::get()<span class="variable">.set_inst_override_by_name</span>(</span><br><span class="line">  <span class="string">&quot;env.agt.drv&quot;</span>,</span><br><span class="line">  <span class="string">&quot;father_class_name&quot;</span>,</span><br><span class="line">  <span class="string">&quot;son_class_name&quot;</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>实例代码 1：重载 driver（type override）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> base_drv <span class="keyword">extends</span> uvm_driver<span class="variable">#(my_trans)</span>;</span><br><span class="line">  `uvm_component_utils(base_drv)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> fast_drv <span class="keyword">extends</span> base_drv;</span><br><span class="line">  `uvm_component_utils(fast_drv)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> base_test <span class="keyword">extends</span> uvm_test;</span><br><span class="line">  `uvm_component_utils(base_test)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    uvm_factory::get()<span class="variable">.set_type_override_by_type</span>(base_drv::get_type(), fast_drv::get_type(), <span class="number">1</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>实例代码 2：只重载某一个实例（inst override）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">  <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">  uvm_factory::get()<span class="variable">.set_inst_override_by_type</span>(</span><br><span class="line">    <span class="string">&quot;env.agt.drv&quot;</span>,</span><br><span class="line">    base_drv::get_type(),</span><br><span class="line">    fast_drv::get_type()</span><br><span class="line">  );</span><br><span class="line"><span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><p>注意事项（容易踩坑）：</p><ul><li>必须走 factory 创建：component 用 <code>type_id::create</code>，object 用 <code>type_id::create</code>；如果直接 <code>new()</code>，override 不会生效</li><li>father&#x2F;son 都必须注册到 factory：component 用 <code>uvm_component_utils</code>，object 用 <code>uvm_object_utils</code></li><li>override 必须发生在 create 之前：一般放在 test 的 build_phase 早期（env&#x2F;agent&#x2F;driver 创建之前），或放在 default_sequence 启动前</li><li>inst_override 的路径用“最终实例的完整层级路径”，需要和实际 <code>get_full_name()</code> 对得上</li></ul><h3 id="13-3-factory-重载要求"><a href="#13-3-factory-重载要求" class="headerlink" title="13.3 factory 重载要求"></a>13.3 factory 重载要求</h3><blockquote><p><strong>重点</strong> 需要在类创建之前调用重载函数（避免实例已创建导致重载不生效）。</p></blockquote><ul><li>被重载类与重载类都需要注册到 factory：<ul><li>component 使用 <code>uvm_component_utils()</code></li><li>object 使用 <code>uvm_object_utils()</code></li></ul></li><li>被重载类实例化需要走 factory，而不能用 new()：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xxx_inst = xxx::type_id::create(<span class="string">&quot;xxx&quot;</span>);</span><br></pre></td></tr></table></figure><ul><li>重载类与被重载类必须有派生关系：重载类派生自被重载类（被重载类为父类）。</li></ul><p>在 base case 的 end_of_elaboration_phase 打印当前 factory 注册与重载情况（便于确认 override 生效）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> end_of_elaboration_phase(uvm_phase phase);</span><br><span class="line">  <span class="keyword">super</span><span class="variable">.end_of_elaboration_phase</span>(phase);</span><br><span class="line">  uvm_factory::get()<span class="variable">.print</span>();</span><br><span class="line"><span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><h2 id="14-编译选项"><a href="#14-编译选项" class="headerlink" title="14 编译选项"></a>14 编译选项</h2><p>在 UVM 验证环境中，常见的编译选项&#x2F;参数用于控制验证环境、组件以及 DUT 的行为与功能：</p><table><thead><tr><th>选项</th><th>含义</th><th>常见用途</th></tr></thead><tbody><tr><td>UVM_OPT</td><td>UVM 相关选项</td><td>控制 UVM 功能、配置组件行为、设置消息冗余度等</td></tr><tr><td>DUT_OPT</td><td>DUT 相关选项</td><td>配置 DUT 参数&#x2F;功能开关等</td></tr><tr><td>COMP_OPT</td><td>组件编译选项</td><td>配置组件功能、宏定义等</td></tr><tr><td>ELAB_OPT</td><td>elaboration 选项</td><td>控制实例化&#x2F;综合阶段的配置与优化策略等</td></tr></tbody></table><h3 id="14-1-VCS-常用编译选项（vcs）"><a href="#14-1-VCS-常用编译选项（vcs）" class="headerlink" title="14.1 VCS 常用编译选项（vcs）"></a>14.1 VCS 常用编译选项（vcs）</h3><table><thead><tr><th>分类</th><th>选项示例</th><th>说明</th></tr></thead><tbody><tr><td>64 位</td><td><code>-full64</code></td><td>64 位编译</td></tr><tr><td>verilog</td><td><code>-sverilog</code></td><td>启用 verilog</td></tr><tr><td>文件列表</td><td><code>-f filelist.f</code></td><td>从 filelist 读取 RTL&#x2F;库&#x2F;选项</td></tr><tr><td>include 路径</td><td><code>+incdir+./tb</code></td><td>追加 include 搜索路径（可多条）</td></tr><tr><td>宏定义</td><td><code>+define+UVM_NO_DEPRECATED</code></td><td>追加宏定义（可多条）</td></tr><tr><td>timescale</td><td><code>-timescale=1ns/1ps</code></td><td>统一 timescale（也可在源码中 <code>\</code>timescale&#96;）</td></tr><tr><td>顶层</td><td><code>-top tb_top</code></td><td>指定 top（多 top 场景常用）</td></tr><tr><td>输出</td><td><code>-o simv</code></td><td>指定生成的仿真可执行文件名</td></tr><tr><td>日志</td><td><code>-l compile.log</code></td><td>编译日志</td></tr><tr><td>增量编译</td><td><code>-Mupdate</code></td><td>只重编变化文件（回归常用）</td></tr><tr><td>并行</td><td><code>-j 8</code></td><td>编译并行度</td></tr><tr><td>调试</td><td><code>-debug_access+all</code></td><td>便于波形&#x2F;交互调试（会增加编译体积）</td></tr><tr><td>调试数据库</td><td><code>-kdb</code></td><td>生成调试数据库（常配合 Verdi&#x2F;DVE）</td></tr><tr><td>覆盖率</td><td><code>-cm line+cond+branch+tgl+fsm</code></td><td>编译打开覆盖率（配合 run 生成数据）</td></tr><tr><td>覆盖率输出</td><td><code>-cm_dir ./cov.vdb</code></td><td>覆盖率数据库目录</td></tr><tr><td>覆盖率命名</td><td><code>-cm_name regress_001</code></td><td>覆盖率 run 名称</td></tr></tbody></table><p>常见编译命令形态：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vcs -full64 -sverilog -f filelist.f -top tb_top -o simv -l compile.log</span><br></pre></td></tr></table></figure><h3 id="14-2-VCS-常用运行选项（-simv）"><a href="#14-2-VCS-常用运行选项（-simv）" class="headerlink" title="14.2 VCS 常用运行选项（.&#x2F;simv）"></a>14.2 VCS 常用运行选项（.&#x2F;simv）</h3><table><thead><tr><th>分类</th><th>选项示例</th><th>说明</th></tr></thead><tbody><tr><td>日志</td><td><code>-l sim.log</code></td><td>仿真日志</td></tr><tr><td>UVM 用例</td><td><code>+UVM_TESTNAME=smoke_test</code></td><td>选择 test</td></tr><tr><td>UVM 详细度</td><td><code>+UVM_VERBOSITY=UVM_MEDIUM</code></td><td>控制信息打印量</td></tr><tr><td>随机种子</td><td><code>+ntb_random_seed=123</code></td><td>固定随机种子便于复现</td></tr><tr><td>超时</td><td><code>+UVM_TIMEOUT=1000000</code></td><td>UVM 超时（时间单位依赖 timescale）</td></tr><tr><td>GUI</td><td><code>-gui</code></td><td>打开 DVE（若环境支持）</td></tr></tbody></table><p>常见运行命令形态：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./simv -l sim.log +UVM_TESTNAME=smoke_test +ntb_random_seed=1</span><br></pre></td></tr></table></figure><h3 id="14-3-波形（Verdi-FSDB）常见选项"><a href="#14-3-波形（Verdi-FSDB）常见选项" class="headerlink" title="14.3 波形（Verdi&#x2F;FSDB）常见选项"></a>14.3 波形（Verdi&#x2F;FSDB）常见选项</h3><p>常见做法：编译阶段加载 FSDB PLI，运行阶段指定 dump 文件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vcs -full64 -sverilog -f filelist.f -debug_access+all -kdb -o simv</span><br><span class="line">./simv -l sim.log +fsdbfile+wave.fsdb</span><br></pre></td></tr></table></figure><h3 id="14-4-后仿（门级-后布局）常见选项（GLS-SDF）"><a href="#14-4-后仿（门级-后布局）常见选项（GLS-SDF）" class="headerlink" title="14.4 后仿（门级&#x2F;后布局）常见选项（GLS &#x2F; SDF）"></a>14.4 后仿（门级&#x2F;后布局）常见选项（GLS &#x2F; SDF）</h3><p>后仿常见输入：<code>gate_netlist.v</code>（门级网表）、<code>stdcell_lib.v</code>（库模型）、可选 <code>dut.sdf</code>（时延回标）。</p><p>编译侧常见要点：</p><ul><li>把门级网表与标准单元库模型加入编译（通常通过 <code>-f</code> 或 <code>-v/-y/+libext</code> 管理）</li><li>按需要选择 delay 模式：<code>+maxdelays</code> &#x2F; <code>+typdelays</code> &#x2F; <code>+mindelays</code></li><li>纯功能门仿（不关心时序）时常用：<code>+notimingcheck</code></li></ul><p>运行侧常见要点：</p><ul><li>用 <code>-sdf</code> 回标 SDF 到指定实例</li><li>结合 delay 模式与日志，快速定位回标&#x2F;时序检查报错</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vcs -full64 -sverilog -f gls_filelist.f -top tb_top -o simv_gls -l gls_compile.log</span><br><span class="line">./simv_gls -l gls_sim.log +maxdelays -sdf typ:tb_top.dut:./dut.sdf</span><br></pre></td></tr></table></figure><h2 id="15-UVM-仿真停止"><a href="#15-UVM-仿真停止" class="headerlink" title="15 UVM 仿真停止"></a>15 UVM 仿真停止</h2><p>在UVM中，若在end_of_elaboration_phase及其前的phase中，如果出现一个或多个UVM_ERROR，那么UVM会认为出现了致命错误，会调用uvm_fatal结束仿真。</p><h2 id="16-seq-仲裁机制"><a href="#16-seq-仲裁机制" class="headerlink" title="16 seq 仲裁机制"></a>16 seq 仲裁机制</h2><p>若同一sequencer上同时启动多个sequence，在默认情况下sequencer的仲裁算法是SEQ_ARB_FIFO。</p><ul><li>SEQ_ARB_FIFO：严格 FIFO 仲裁</li><li>SEQ_ARB_STRICT_FIFO：按优先级仲裁；同优先级按 FIFO</li><li>SEQ_ARB_STRICT_RANDOM：按优先级仲裁；同优先级随机选择</li></ul><p>使用步骤：</p><ul><li>设置 sequencer 仲裁算法</li><li>设置 sequence 优先级</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">env<span class="variable">.i_agt</span><span class="variable">.sqr</span><span class="variable">.set_arbitration</span>(SEQ_ARB_STRICT_FIFO);</span><br><span class="line">seq1<span class="variable">.start</span>(env<span class="variable">.i_agt</span><span class="variable">.sqr</span>, <span class="literal">null</span>, <span class="number">100</span>);</span><br><span class="line">seq2<span class="variable">.start</span>(env<span class="variable">.i_agt</span><span class="variable">.sqr</span>, <span class="literal">null</span>, <span class="number">200</span>);</span><br></pre></td></tr></table></figure><p>若seq2和seq1同时启动，且同时挂载在同一sqr上，则seq1先启动。</p><h2 id="17-virtual-sequence"><a href="#17-virtual-sequence" class="headerlink" title="17 virtual sequence"></a>17 virtual sequence</h2><p>virtual sequence (vseq) 本质还是 sequence, 但它通常不直接发 transaction, 而是统一编排多个 agent 上的多个 sequence, 用来描述跨接口的场景流程.</p><p>典型使用场景:</p><ul><li>多端口联动: 同一用例同时驱动多个接口或多个方向</li><li>多 agent 协同: 同时启动多个 seq, 控制并发与先后关系</li><li>性能流量: 多流按比例发包, 支持突发与背压注入, 统一收敛结束条件</li></ul><p>核心概念:</p><ul><li>virtual sequencer (vsqr): 只保存各 agent 的 sequencer 句柄, 自身不驱动 DUT</li><li>virtual sequence (vseq): 运行在 vsqr 上, 在 body 里用 <code>p_sequencer.xxx_sqr</code> 取到真实 sequencer, 然后 start 子 sequence</li><li>真实 transaction 的路径: vseq -&gt; 子 sequence -&gt; 真实 sequencer -&gt; driver -&gt; DUT</li></ul><p>结构示意:</p><pre><code class="highlight mermaid">flowchart TD    T[test] --&gt;|start| V[vseq]    V --&gt;|runs_on| VS[vsqr]    VS --&gt; SA[sqr_a]    VS --&gt; SB[sqr_b]    SA --&gt; DA[drv_a]    SB --&gt; DB[drv_b]    DA --&gt; IA[dut_if_a]    DB --&gt; IB[dut_if_b]</code></pre><p>使用步骤 (建议工程做法):</p><ul><li><ol><li>env 里创建 vsqr (component), connect_phase 把各 agent 的 sequencer 句柄挂到 vsqr</li></ol></li><li><ol start="2"><li>写 vseq (object), 用 <code>uvm_declare_p_sequencer(vsqr_type)</code> 得到类型正确的 <code>p_sequencer</code></li></ol></li><li><ol start="3"><li>vseq.body() 里创建并启动子 sequence (串行 start 或 fork 并发)</li></ol></li><li><ol start="4"><li>test 的 main_phase (或 run_phase) 里 <code>vseq.start(env.vsqr)</code> 启动整个场景</li></ol></li></ul><p>示例: vsqr 声明句柄, env 负责连接</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_vsqr <span class="keyword">extends</span> uvm_sequencer<span class="variable">#(uvm_sequence_item)</span>;</span><br><span class="line">  `uvm_component_utils(my_vsqr)</span><br><span class="line">  my_sqr sqr_a;</span><br><span class="line">  my_sqr sqr_b;</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> my_env <span class="keyword">extends</span> uvm_env;</span><br><span class="line">  `uvm_component_utils(my_env)</span><br><span class="line">  my_agent agt_a;</span><br><span class="line">  my_agent agt_b;</span><br><span class="line">  my_vsqr  vsqr;</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    agt_a = my_agent::type_id::create(<span class="string">&quot;agt_a&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    agt_b = my_agent::type_id::create(<span class="string">&quot;agt_b&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    vsqr  = my_vsqr::type_id::create(<span class="string">&quot;vsqr&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> connect_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.connect_phase</span>(phase);</span><br><span class="line">    vsqr<span class="variable">.sqr_a</span> = agt_a<span class="variable">.sqr</span>;</span><br><span class="line">    vsqr<span class="variable">.sqr_b</span> = agt_b<span class="variable">.sqr</span>;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>示例: vseq 在 body 里并发启动子 sequence</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_vseq <span class="keyword">extends</span> uvm_sequence<span class="variable">#(uvm_sequence_item)</span>;</span><br><span class="line">  `uvm_object_utils(my_vseq)</span><br><span class="line">  `uvm_declare_p_sequencer(my_vsqr)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;my_vseq&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> pre_body();</span><br><span class="line">    <span class="keyword">if</span> (starting_phase != <span class="literal">null</span>) starting_phase<span class="variable">.raise_objection</span>(<span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> post_body();</span><br><span class="line">    <span class="keyword">if</span> (starting_phase != <span class="literal">null</span>) starting_phase<span class="variable">.drop_objection</span>(<span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">    my_seq_a seq_a;</span><br><span class="line">    my_seq_b seq_b;</span><br><span class="line">    seq_a = my_seq_a::type_id::create(<span class="string">&quot;seq_a&quot;</span>);</span><br><span class="line">    seq_b = my_seq_b::type_id::create(<span class="string">&quot;seq_b&quot;</span>);</span><br><span class="line">    <span class="keyword">fork</span></span><br><span class="line">      seq_a<span class="variable">.start</span>(p_sequencer<span class="variable">.sqr_a</span>);</span><br><span class="line">      seq_b<span class="variable">.start</span>(p_sequencer<span class="variable">.sqr_b</span>);</span><br><span class="line">    <span class="keyword">join</span></span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>时序示意 (vseq 并发启动两个子 sequence):</p><pre><code class="highlight mermaid">sequenceDiagram    participant T as test    participant V as vseq    participant A as seq_a    participant B as seq_b    participant SA as sqr_a    participant SB as sqr_b    T-&gt;&gt;V: start(vsqr)    V-&gt;&gt;A: start(sqr_a)    A-&gt;&gt;SA: start_item and finish_item    V-&gt;&gt;B: start(sqr_b)    B-&gt;&gt;SB: start_item and finish_item</code></pre><p>注意事项:</p><ul><li>vsqr 里放的是句柄, 不是新创建的 sequencer; 真实 sequencer 仍在 agent 内 create</li><li>vseq 与子 sequence 都建议用 <code>type_id::create</code>, 便于 factory override</li><li>如果用 default_sequence 自动启动, 用 <code>starting_phase</code> 管理 objection</li></ul><h2 id="18-TLM-通信"><a href="#18-TLM-通信" class="headerlink" title="18 TLM 通信"></a>18 TLM 通信</h2><h3 id="18-1-analysis-端口通信"><a href="#18-1-analysis-端口通信" class="headerlink" title="18.1 analysis 端口通信"></a>18.1 analysis 端口通信</h3><p>analysis_port（analysis_export）与 imp 之间的通信是一对多的通信，且对于 analysis_port 和 analysis_export 来说，没有阻塞&#x2F;非阻塞的区别（只有一种操作：write）。analysis_imp 所在的 component 必须定义名为 write 的函数；当 analysis_port&#x2F;export 执行 write 时，对应的 write 函数会自动调用。</p><p>大致步骤：（以rm-&gt;scb为例）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rm 组件</span></span><br><span class="line">uvm_analysis_port<span class="variable">#(trans)</span> a_ap;</span><br><span class="line"></span><br><span class="line"><span class="comment">// scb 组件</span></span><br><span class="line">uvm_analysis_imp<span class="variable">#(trans, class)</span> b_imp;</span><br><span class="line"></span><br><span class="line"><span class="comment">// env 组件</span></span><br><span class="line">rm<span class="variable">.a_ap</span><span class="variable">.connect</span>(scb<span class="variable">.b_imp</span>);</span><br></pre></td></tr></table></figure><p>拓展：考虑到有多路数据接入scb，而write函数只有一个，因此，UVM定义的宏<code>uvm_analysis_imp_decl(a)可用来定义新的uvm_analysis_imp类型，同时会存在write_a函数，其会自动执行。如使用</code>uvm_analysis_imp_decl(_rm_chk)，则新定义一个数据类型uvm_analysis_imp_rm_chk，其本质还是uvm_analysis_imp类型，同时有数据发送时，会自动调用write_rm_chk函数。</p><p>（2）其它 put&#x2F;get 通信：略</p><h3 id="18-2-FIFO-通信"><a href="#18-2-FIFO-通信" class="headerlink" title="18.2 FIFO 通信"></a>18.2 FIFO 通信</h3><p>在 agent 和 scoreboard 之间添加 uvm_analysis_fifo。FIFO 本质是“缓存 + 两个 imp”：</p><ul><li>monitor -&gt; FIFO：monitor 仍是 analysis_port，FIFO 为 uvm_analysis_imp，数据流&#x2F;控制流方向相同</li><li>scoreboard &lt;-&gt; FIFO：scoreboard 使用 blocking_get_port，FIFO 使用 get_export，控制流从 scoreboard 到 FIFO，数据流从 FIFO 到 scoreboard</li></ul><p>大致步骤是：（以mon采集DUT，与scb通信为例，其余类似）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// agent 方向</span></span><br><span class="line">uvm_analysis_port<span class="variable">#(trans)</span> ap;</span><br><span class="line">ap = <span class="keyword">new</span>(<span class="string">&quot;ap&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// scoreboard 方向</span></span><br><span class="line">uvm_blocking_get_port<span class="variable">#(trans)</span> act_port;</span><br><span class="line">act_port = <span class="keyword">new</span>(<span class="string">&quot;act_port&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// env 方向</span></span><br><span class="line">uvm_tlm_analysis_fifo <span class="variable">#(trans)</span> agt_scb_fifo;</span><br><span class="line">agt_scb_fifo = <span class="keyword">new</span>(<span class="string">&quot;agt_scb_fifo&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// connect_phase 连接</span></span><br><span class="line">o_agt<span class="variable">.ap</span><span class="variable">.connect</span>(agt_scb_fifo<span class="variable">.analysis_export</span>);</span><br><span class="line">scb<span class="variable">.act_port</span><span class="variable">.connect</span>(agt_scb_fifo<span class="variable">.blocking_get_export</span>);</span><br></pre></td></tr></table></figure><p>同理的话，rm和i_agt之间的通信，rm和scb之间的通信都是如此。</p><div class="note info flat"><blockquote><p><strong>注意</strong> 除了 TLM FIFO 需要例化，两边的通信端口也需要例化。接收端使用 get 获取 trans 会阻塞，但不影响主进程。</p></blockquote></div><blockquote><p><strong>特别重要</strong> 使用 fork…join_none 进行 get 采样时，同时刻采样多个 trans 可能乱序，尽量避免用 fork…join_none 采样。</p></blockquote><p>tlm_analysis_fifo.flush()可以清空tlm fifo的内部存储数据。</p><h3 id="18-3-TLM1-端口选型与连接规则速查（摘记）"><a href="#18-3-TLM1-端口选型与连接规则速查（摘记）" class="headerlink" title="18.3 TLM1 端口选型与连接规则速查（摘记）"></a>18.3 TLM1 端口选型与连接规则速查（摘记）</h3><p>参考原文：<a href="https://www.cnblogs.com/LeslieQ/p/19109584">向UVM-TLM通信发起决战</a></p><p>TLM 在 UVM 里更像“事务血液循环”：没有端口&#x2F;连接，transaction 很难在 driver&#x2F;monitor&#x2F;scoreboard&#x2F;reference model 等组件间流动，导致环境搭不起来、代码也难读。</p><h4 id="18-3-1-TLM1-0-vs-TLM2-0（UVM1-2-视角）"><a href="#18-3-1-TLM1-0-vs-TLM2-0（UVM1-2-视角）" class="headerlink" title="18.3.1 TLM1.0 vs TLM2.0（UVM1.2 视角）"></a>18.3.1 TLM1.0 vs TLM2.0（UVM1.2 视角）</h4><ul><li>UVM 的 uvm_pkg.sv 中同时包含 TLM1 和 TLM2</li><li>TLM2 不是在 TLM1 上“完善&#x2F;优化”的同一套类，而是一套新的接口与方法</li><li>TLM1 常用于功能验证：put&#x2F;get&#x2F;peek 等基础传输方法，对时序支持有限</li><li>TLM2 更强调时序建模：通过 nb_transport_fw&#x2F;nb_transport_bw 等接口支持更复杂、更精确的建模</li></ul><h4 id="18-3-2-端口家族与“能不能连”"><a href="#18-3-2-端口家族与“能不能连”" class="headerlink" title="18.3.2 端口家族与“能不能连”"></a>18.3.2 端口家族与“能不能连”</h4><ul><li>端口必须例化在 component 内，端口本身不能脱离 component 单独存在</li><li>端口分两大类：带 analysis 与不带 analysis<ul><li>带 analysis：analysis_port &#x2F; analysis_export &#x2F; analysis_imp，一对多；仅有 write() 方法</li><li>不带 analysis：port &#x2F; export &#x2F; imp，点对点</li></ul></li><li>两类端口不互通：analysis 端口只能连 analysis 端口；非 analysis 端口只能连非 analysis 端口</li></ul><h4 id="18-3-3-port-export-imp-的角色（更偏“控制流”）"><a href="#18-3-3-port-export-imp-的角色（更偏“控制流”）" class="headerlink" title="18.3.3 port &#x2F; export &#x2F; imp 的角色（更偏“控制流”）"></a>18.3.3 port &#x2F; export &#x2F; imp 的角色（更偏“控制流”）</h4><ul><li>port 端口所在组件通常是主动方（master），发起 put&#x2F;get&#x2F;peek 等操作</li><li>imp 端口所在组件通常是被动方（slave），最终落到该组件内部方法实现</li><li>export 更多承担“转发&#x2F;桥接”的角色</li></ul><pre><code class="highlight mermaid">flowchart TD    A[master component] --&gt; P[&quot;uvm_*_port&quot;]    P --&gt;|connect| E[&quot;uvm_*_export&quot;]    E --&gt;|connect| I[&quot;uvm_*_imp&quot;]    I --&gt; B[&quot;slave component 实现&quot;]</code></pre><p>连接规则要点：</p><ul><li>连接的发起方必须是更高“地位”的端口：port &gt; export &gt; imp</li><li>connect 调用要有始有终：开始一定是 port 发起，结束一定落到 imp</li></ul><h4 id="18-3-4-阻塞-非阻塞方法"><a href="#18-3-4-阻塞-非阻塞方法" class="headerlink" title="18.3.4 阻塞&#x2F;非阻塞方法"></a>18.3.4 阻塞&#x2F;非阻塞方法</h4><table><thead><tr><th>分类</th><th>方法</th><th>说明</th></tr></thead><tbody><tr><td>阻塞（task）</td><td>put&#x2F;get&#x2F;peek</td><td>阻塞当前进程，直到发送&#x2F;获取成功</td></tr><tr><td>非阻塞（function）</td><td>try_put&#x2F;try_get&#x2F;try_peek</td><td>尝试操作，成功返回 1，失败返回 0</td></tr><tr><td>非阻塞（function）</td><td>can_put&#x2F;can_get&#x2F;can_peek</td><td>检查对端是否具备条件</td></tr><tr><td>analysis 专属</td><td>write</td><td>一对多广播式写入</td></tr></tbody></table><h4 id="18-3-5-以-put-为例的调用链"><a href="#18-3-5-以-put-为例的调用链" class="headerlink" title="18.3.5 以 put 为例的调用链"></a>18.3.5 以 put 为例的调用链</h4><pre><code class="highlight mermaid">sequenceDiagram    participant M as master component    participant P as port    participant E as export    participant I as imp    participant S as slave component    M-&gt;&gt;P: put(t)    P-&gt;&gt;E: put(t)    E-&gt;&gt;I: put(t)    I-&gt;&gt;S: put(t) (最终实现)</code></pre><h4 id="18-3-6-端口类名的选型直觉（以-put-为例）"><a href="#18-3-6-端口类名的选型直觉（以-put-为例）" class="headerlink" title="18.3.6 端口类名的选型直觉（以 put 为例）"></a>18.3.6 端口类名的选型直觉（以 put 为例）</h4><ul><li>uvm_blocking_put_port：只包含 put()</li><li>uvm_nonblocking_put_port：只包含 try_put&#x2F;can_put</li><li>uvm_put_port：同时包含阻塞与非阻塞 put 相关方法</li></ul><h4 id="18-3-7-connect-组合速查（谁能-connect-谁）"><a href="#18-3-7-connect-组合速查（谁能-connect-谁）" class="headerlink" title="18.3.7 connect 组合速查（谁能 connect 谁）"></a>18.3.7 connect 组合速查（谁能 connect 谁）</h4><ul><li>非 analysis（点对点）：<ul><li>port.connect(port&#x2F;export&#x2F;imp)</li><li>export.connect(export&#x2F;imp)</li><li>imp 不能发起 connect</li></ul></li><li>analysis（一对多）：<ul><li>analysis_port.connect(analysis_export&#x2F;analysis_imp)</li><li>analysis_export.connect(analysis_export&#x2F;analysis_imp)</li><li>analysis_imp 不能发起 connect</li></ul></li></ul><h4 id="18-3-8-port-export-imp：控制流与数据流是两回事"><a href="#18-3-8-port-export-imp：控制流与数据流是两回事" class="headerlink" title="18.3.8 port&#x2F;export&#x2F;imp：控制流与数据流是两回事"></a>18.3.8 port&#x2F;export&#x2F;imp：控制流与数据流是两回事</h4><ul><li>port&#x2F;export&#x2F;imp 更偏“控制流”分层（谁发起方法调用，谁承接&#x2F;转发调用）</li><li>put 操作的数据流：port → imp（像 master 写）</li><li>get 操作的数据流：imp → port（像 master 读）</li><li>analysis 的 write：广播式 push，接收方需要立即处理并返回</li></ul><pre><code class="highlight mermaid">flowchart LR    PUT[&quot;put：数据 port→imp&quot;]    P1[port] --&gt;|data: tx| I1[imp]    GET[&quot;get：数据 imp→port&quot;]    I2[imp] --&gt;|data: tx| P2[port]</code></pre><h4 id="18-3-9-源码视角：端口类的“基类骨架”（简化）"><a href="#18-3-9-源码视角：端口类的“基类骨架”（简化）" class="headerlink" title="18.3.9 源码视角：端口类的“基类骨架”（简化）"></a>18.3.9 源码视角：端口类的“基类骨架”（简化）</h4><ul><li>uvm_tlm_if_base#(T1,T2)：TLM1 常用 put&#x2F;get&#x2F;peek&#x2F;try_*&#x2F;can_*&#x2F;write 等方法的接口基类（virtual class）</li><li>uvm_sqr_if_base#(REQ,RSP)：sequence&#x2F;sequencer&#x2F;driver 专用接口（get_next_item&#x2F;item_done 等）</li><li>uvm_port_base#(IF)：几乎所有 port&#x2F;export&#x2F;imp 的核心基类（connect 的核心也在这里）</li><li>uvm_*<em>port &#x2F; uvm</em><em><em>export &#x2F; uvm</em></em>_imp：同前缀三件套，封装的方法集合不同（blocking&#x2F;nonblocking&#x2F;combined）</li></ul><p>端口三件套前缀需要匹配，否则 connect 会失败，例如：</p><ul><li>uvm_nonblocking_get_port 只能连 uvm_nonblocking_get_export&#x2F;imp</li></ul><h4 id="18-3-10-FIFO：端口-vs-组件"><a href="#18-3-10-FIFO：端口-vs-组件" class="headerlink" title="18.3.10 FIFO：端口 vs 组件"></a>18.3.10 FIFO：端口 vs 组件</h4><ul><li>端口（port&#x2F;export&#x2F;imp&#x2F;analysis_*）是“组件的门”，必须例化在 component 里，本身不是 component</li><li>FIFO（uvm_tlm_fifo &#x2F; uvm_tlm_analysis_fifo）是 component，可作为跨线程&#x2F;解耦的缓冲区</li><li>uvm_tlm_analysis_fifo：在 FIFO 基础上增加 analysis_export，适配 analysis 链路（monitor→fifo→后处理）</li><li>典型连线代码示例：可对照本笔记的 <a href="#182-fifo-%E9%80%9A%E4%BF%A1">18.2</a></li></ul><pre><code class="highlight mermaid">flowchart TD    A[component A] --&gt;|put| FIFO[uvm_tlm_fifo]    FIFO --&gt;|get| B[component B]</code></pre><h4 id="18-3-11-sequence-机制的特殊端口：seq-item-pull"><a href="#18-3-11-sequence-机制的特殊端口：seq-item-pull" class="headerlink" title="18.3.11 sequence 机制的特殊端口：seq_item_pull_*"></a>18.3.11 sequence 机制的特殊端口：seq_item_pull_*</h4><ul><li>driver&#x2F;sequencer 之间不是 uvm_tlm_if_base，而是基于 uvm_sqr_if_base 的专用接口</li><li>典型连接：<code>drv.seq_item_port.connect(sqr.seq_item_export)</code></li><li>典型调用链：drv.get_next_item → sqr.get_next_item → 等待 sequence 发 item；drv.item_done → sqr.item_done</li><li>握手时序图：可对照本笔记的 <a href="#216-start_item--finish_item-%E4%B8%8E-get_next_item--item_done-%E7%9A%84%E6%8F%A1%E6%89%8B%E5%9B%BE%E7%89%87%E9%87%8D%E7%94%BB">2.1.6</a></li></ul><h4 id="18-3-12-端口选型的实用规则（够用版）"><a href="#18-3-12-端口选型的实用规则（够用版）" class="headerlink" title="18.3.12 端口选型的实用规则（够用版）"></a>18.3.12 端口选型的实用规则（够用版）</h4><ul><li>先决定通信语义：push(put) &#x2F; pull(get) &#x2F; 广播(write)</li><li>再决定是否阻塞：blocking_* &#x2F; nonblocking_* &#x2F; 同时支持（无前缀或 combined）</li><li>最后按“方法集合”选类：组件只需要哪些方法，就选只暴露这些方法的端口类</li></ul><h2 id="19-phase-跳转"><a href="#19-phase-跳转" class="headerlink" title="19 phase 跳转"></a>19 phase 跳转</h2><p>在 function phase 和 task phase 中，使用 <code>phase.jump(uvm_reset_phase::get())</code> 跳转至 reset_phase，注意：</p><ul><li>不能跳转至 run_phase</li><li>只能跳转 uvm_pre_reset_phase 之后的所有 phase</li><li>可以向当前 phase 之前跳转，也可以向之后跳转</li></ul><p>注：常用于二次复位测试</p><p>扩展：<br>sequencer的stop_sequences()方法，作用是告知sequencer终止当前在sequencer上运行的所有sequence和子sequence，并删除当前排队的所有请求、锁定和响应。这实际上是将sequencer复位到空闲状态。<br>但是，stop_sequences()并不检查driver是否正在驱动任何sequence_items，因此可能会报get_next_item()和item_done()未成对的fatal，所以要保证先调用get_next_item()获取待处理的事务，再调用item_done()来标记事务的处理完成。<br>除此之外，在 main_phase 中使用 phase.jump() 后，若后面不跟 clock，则会直接执行到 drop_objection；若跟 clock，则不会执行到 drop_objection，直接跳转。</p><h2 id="20-callback-回调"><a href="#20-callback-回调" class="headerlink" title="20 callback 回调"></a>20 callback 回调</h2><p>以 drive 组件为例：</p><h3 id="20-1-注册与放置回调"><a href="#20-1-注册与放置回调" class="headerlink" title="20.1 注册与放置回调"></a>20.1 注册与放置回调</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> drive <span class="keyword">extends</span> uvm_driver<span class="variable">#(trans)</span>;</span><br><span class="line">  `uvm_register_cb(drive, drive_callback)</span><br><span class="line">  `uvm_do_callbacks(drive, drive_callback, fun(tr) / <span class="keyword">task</span>(tr))</span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="20-2-定义回调基类"><a href="#20-2-定义回调基类" class="headerlink" title="20.2 定义回调基类"></a>20.2 定义回调基类</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> drive_callback <span class="keyword">extends</span> uvm_callback;</span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> fun(<span class="keyword">ref</span> trans tr); <span class="keyword">endfunction</span></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> task_fn(<span class="keyword">ref</span> trans tr); <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="20-3-扩展回调类"><a href="#20-3-扩展回调类" class="headerlink" title="20.3 扩展回调类"></a>20.3 扩展回调类</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_drive_callback <span class="keyword">extends</span> drive_callback;</span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> fun(<span class="keyword">ref</span> trans tr); <span class="keyword">endfunction</span></span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">task</span> task_fn(<span class="keyword">ref</span> trans tr); <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="20-4-在-test-中例化并注册"><a href="#20-4-在-test-中例化并注册" class="headerlink" title="20.4 在 test 中例化并注册"></a>20.4 在 test 中例化并注册</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> test <span class="keyword">extends</span> base_test;</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> connect_phase(uvm_phase phase);</span><br><span class="line">    my_drive_callback my_drv_callback;</span><br><span class="line">    my_drv_callback = my_drive_callback::type_id::create(<span class="string">&quot;my_drv_callback&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    uvm_callbacks<span class="variable">#(drive, drive_callback)::add(env.i_agt.drv, my_drv_callback)</span>;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>callback 回调步骤：</p><ul><li>将 UVM Callback 方法内嵌入组件中</li><li>创建最基本的 UVM Callback 类以供扩展</li><li>从上一步的类中扩展出所需的 callback 类</li><li>在顶层实例化并注册 Callback 对象</li></ul><h2 id="21-uvm-report-server"><a href="#21-uvm-report-server" class="headerlink" title="21 uvm_report_server"></a>21 uvm_report_server</h2><p>在UVM中，uvm_report_server是一个用于处理和管理报告消息的组件，其主要作用是收集来自测试环境中的各个组件（如测试用例、测试类、环境等）发出的报告消息。<br>一般使用方法：</p><ul><li>在 report_phase 中声明 <code>uvm_report_server server;</code></li><li><code>server = uvm_report_server::get_server()</code> 或 <code>server = get_report_server()</code> 获取 server</li><li>使用 <code>server.get_severity_count(...)</code> 获取统计，再汇总报告</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">uvm_report_server server;</span><br><span class="line"><span class="keyword">int</span> error, fatal, warning;</span><br><span class="line"></span><br><span class="line">server  = uvm_report_server::get_server();</span><br><span class="line">error   = server<span class="variable">.get_severity_count</span>(UVM_ERROR);</span><br><span class="line">fatal   = server<span class="variable">.get_severity_count</span>(UVM_FATAL);</span><br><span class="line">warning = server<span class="variable">.get_severity_count</span>(UVM_WARNING);</span><br></pre></td></tr></table></figure><h2 id="22-print-topology"><a href="#22-print-topology" class="headerlink" title="22 print_topology"></a>22 print_topology</h2><p>在verilog中，print_topology通常是指在UVM测试环境中使用一种方法或命令，用于打印出UVM测试环境中各个组件（components）之间的层次结构或拓扑结构。如：uvm_top.print_topology可以打印出UVM测试环境中各个组件之间的连接关系。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uvm_top<span class="variable">.print_topology</span>();</span><br></pre></td></tr></table></figure><h2 id="23-sequence-相关宏及其实现"><a href="#23-sequence-相关宏及其实现" class="headerlink" title="23 sequence 相关宏及其实现"></a>23 sequence 相关宏及其实现</h2><h3 id="23-1-常用用法"><a href="#23-1-常用用法" class="headerlink" title="23.1 常用用法"></a>23.1 常用用法</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">seq = <span class="keyword">new</span>();</span><br><span class="line">seq<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123; &#125;;</span><br><span class="line">seq<span class="variable">.start</span>(sqr);</span><br><span class="line"></span><br><span class="line">transaction trans;</span><br><span class="line">trans = <span class="keyword">new</span>();</span><br><span class="line">trans<span class="variable">.randomize</span>();</span><br><span class="line">start_item(trans);</span><br><span class="line">finish_item(trans);</span><br></pre></td></tr></table></figure><h3 id="23-2-uvm-do-系列（默认-sqr-为-m-sequencer）"><a href="#23-2-uvm-do-系列（默认-sqr-为-m-sequencer）" class="headerlink" title="23.2 &#96;uvm_do 系列（默认 sqr 为 m_sequencer）"></a>23.2 &#96;uvm_do 系列（默认 sqr 为 m_sequencer）</h3><p>此系列宏实际上集成度较高，宏定义并没有给出seq&#x2F;tr在哪个sequencer上启动，因此该系列宏都是从默认的m_sequencer上启动的，也就是通过seq.start函数传递的sqr指针。</p><table><thead><tr><th>宏</th><th>参数说明</th></tr></thead><tbody><tr><td>&#96;uvm_do(tr_or_seq)</td><td>1 个参数：transaction 或 sequence</td></tr><tr><td>&#96;uvm_do_with(tr_or_seq, {cons})</td><td>2 个参数：tr&#x2F;seq + 约束</td></tr><tr><td>&#96;uvm_do_pri(tr_or_seq, priority)</td><td>2 个参数：tr&#x2F;seq + 优先级</td></tr><tr><td>&#96;uvm_do_pri_with(tr_or_seq, pri, {cons})</td><td>3 个参数：tr&#x2F;seq + 优先级 + 约束</td></tr></tbody></table><h3 id="23-3-uvm-do-on-系列（可指定-sqr）"><a href="#23-3-uvm-do-on-系列（可指定-sqr）" class="headerlink" title="23.3 &#96;uvm_do_on 系列（可指定 sqr）"></a>23.3 &#96;uvm_do_on 系列（可指定 sqr）</h3><p><code>uvm_do_on系列宏可以指定sequence或者transaction在哪个sqr上启动，特别是如果系统中包含多个sequencer，顶层通过virtual sequencer控制，可以通过在sequence中使用</code>uvm_declare_p_sequencer(my_sqr)来指定sequence的启动位置。</p><table><thead><tr><th>宏</th><th>参数说明</th></tr></thead><tbody><tr><td>&#96;uvm_do_on(tr_or_seq, sqr)</td><td>2 个参数：第二个为 sqr 指针</td></tr><tr><td>&#96;uvm_do_on_with(tr_or_seq, sqr, {cons})</td><td>3 个参数：sqr + 约束</td></tr><tr><td>&#96;uvm_do_on_pri(tr_or_seq, sqr, pri)</td><td>3 个参数：第三个为优先级</td></tr><tr><td>&#96;uvm_do_on_pri_with(tr_or_seq, sqr, pri, {cons})</td><td>4 个参数：优先级 + 约束</td></tr></tbody></table><p>无论是<code>uvm_do系列宏还是</code>uvm_do_on系列宏，底层都是使用&#96;uvm_do_on_pri_with这个参数最全的宏定义，不一样的宏分别对这个宏做了参数固化。上述中如果sequence是参数，那么不需要将sequence例化了。</p><h3 id="23-4-uvm-create-与-uvm-send"><a href="#23-4-uvm-create-与-uvm-send" class="headerlink" title="23.4 uvm_create 与 uvm_send"></a>23.4 <code>uvm_create 与 </code>uvm_send</h3><p>使用<code>uvm_create宏生成trans，再使用</code>uvm_send宏将trans发送出去。</p><div class="note info flat"><blockquote><p><strong>注意</strong> 使用内嵌约束 <code>randomize() with { CONSTRAINT }</code> 时，约束体里变量名的查找顺序默认从被随机化对象开始，逐级向上查找同名变量。如果 randomize() 的局部域中也存在同名变量，需要使用 <code>local::</code> 显式声明变量来源。</p></blockquote></div><p>另外使用class.randomize(a)with{a&#x3D;&#x3D;valuex;};时，指明对a进行随机化，因此class中的b、c…等等的会保持初始的值。未指明则是对class所有随机变量进行随机，指明了则对指明的随机变量进行随机。</p><blockquote><p><strong>重点</strong> 当 body 执行完成时，该 sequence 即完成使命，任务结束。</p></blockquote><p>若sequence宏的启动方式，参数是trans，则会自动调用start_item和finish_item，若是sequence则会调用start任务，启动sequence。</p><h2 id="24-p-sequencer-与-m-sequencer"><a href="#24-p-sequencer-与-m-sequencer" class="headerlink" title="24 p_sequencer 与 m_sequencer"></a>24 p_sequencer 与 m_sequencer</h2><ul><li><p>m_sequencer（uvm_sequencer_base 类型）定义在 uvm_sequence_item 类中，每个 uvm_sequence 默认有一个 m_sequencer。<code>uvm_sequence.start(uvm_sequencer)</code> 后，m_sequencer 指向该 uvm_sequencer（父类指向子类）。</p></li><li><p><code>uvm_declare_p_sequencer(SEQUENCER)</code>：本质是声明一个 SEQUENCER 类型的成员变量。</p></li></ul><p><code>uvm_declare_p_sequencer(my_sequencer)</code> 的源码（节选）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> uvm_declare_p_sequencer(SEQUENCER) \</span></span><br><span class="line">  SEQUENCER p_sequencer; \</span><br><span class="line">  <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> m_set_p_sequencer();\</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.m_set_p_sequencer</span>(); \</span><br><span class="line">    <span class="keyword">if</span>( !<span class="built_in">$cast</span>(p_sequencer, m_sequencer)) \  <span class="comment">//子----&gt;父</span></span><br><span class="line">        `uvm_fatal(<span class="string">&quot;DCLPSQ&quot;</span>, <span class="string">&quot;xxxxxxx&quot;</span>)\</span><br><span class="line">  <span class="keyword">endfunction</span>  </span><br></pre></td></tr></table></figure><p>之后会自动将my_sequencer通过cast转换成p_sequencer。这个过程在pre_body()之前就完成了，这样就可以直接使用my_sequencer内的成员变量了。</p><p>细节：<br>（1）m_sequencer是sequence的成员变量，属于uvm_sequencer_base类型，sequence启动后，m_sequencer指向uvm_sequencer（父指向子），由此搭建了sequence和sequencer的桥梁，关于m_sequencer的使用就由uvm自动完成。</p><p>（2）对于复杂模型，多个sequence启动时，为方便统一管理，使用virtual_sequencer管理多个sequencer，virtual_sequence包含多个sequence，此时virtual_sequence启动，m_sequencer指向virtual_sequencer，此时使用&#96;uvm_declare_p_sequencer(virtual_sequencer)，则相当于$cast(p_sequencer,m_sequencer)向下类型转换，p_sequencer指向virtual_sequencer，则virtual_sequence里面的各sequencex可以start(p_sequencer.sqrx)来启动，由此完成sequence的统一管理，简化代码量。</p><p>9.11总结：<br>（1）sequence继承uvm_sequence类，里面定义了m_sequencer（属于uvm_sequcner_base类），sequence启动后，m_sequencer则指向了sequencer（属于uvm_sequencer），此处是父类指向子类，由此实现sequence和sequencer的联系。<br>（2）p_sequencer（属于uvm_sequencer）的目的是为实现sequence读取sequencer中的变量，使用父类指向子类的向上转换，$cast的向下转换。常用在virtual_sequencer和virtual_sequence的使用，因为virtual_sequencer中有sqr1，sqr2，而virtual_sequence中seq1，seq2启动后，想得到sqr1和sqr2，则需要先m_sequencer指向virtual_sequencer，然后再p_sequencer指向m_sequencer，这样p_sequencer指向virtual_sequencer，则再virtual_sequence中，可以通过p_sequencer得到sqr1，sqr2。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> a;</span><br><span class="line">  <span class="keyword">int</span> val = <span class="number">13</span>;</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> b <span class="keyword">extends</span> a;</span><br><span class="line">  <span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">  b b1;</span><br><span class="line">  b b2;</span><br><span class="line">  a a1;</span><br><span class="line"></span><br><span class="line">  b1 = <span class="keyword">new</span>();</span><br><span class="line">  b1<span class="variable">.val</span> = <span class="number">44</span>;</span><br><span class="line">  a1 = b1;</span><br><span class="line">  <span class="built_in">$cast</span>(b2, a1);</span><br><span class="line">  <span class="built_in">$display</span>(<span class="string">&quot;val:%0d&quot;</span>, b2<span class="variable">.val</span>);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h2 id="25-最大-UVM-ERROR-个数停止"><a href="#25-最大-UVM-ERROR-个数停止" class="headerlink" title="25 最大 UVM_ERROR 个数停止"></a>25 最大 UVM_ERROR 个数停止</h2><p>当uvm_fatal出现时，会自动结束仿真。同时，UVM也支持UVM_ERROR达到一定数量时结束仿真，即set_report_max_quit_count函数，调用方式：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set_report_max_quit_count(n);</span><br></pre></td></tr></table></figure><p>也支持在命令行加入：<code>UVM_MAX_QUIT_COUNT=n</code>。</p><h2 id="26-uvm-re-match-uvm-glob-to-re"><a href="#26-uvm-re-match-uvm-glob-to-re" class="headerlink" title="26 uvm_re_match &#x2F; uvm_glob_to_re"></a>26 uvm_re_match &#x2F; uvm_glob_to_re</h2><p>函数原型：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="keyword">int</span> uvm_re_match(<span class="keyword">string</span> re, <span class="keyword">string</span> str);</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">string</span> uvm_glob_to_re(<span class="keyword">string</span> glob);</span><br></pre></td></tr></table></figure><p>使用：</p><ul><li>uvm_glob_to_re：输入想匹配的字符串，返回正则表达式</li><li>uvm_re_match：输入正则 re 与目标 str，匹配成功返回 0，否则返回 1</li></ul><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><p>（1）component组件的new函数有两个参数、objection的new函数有一个参数；<br>对于component组件，在type_id::create例化时，参数会加this；而非component，在使用type_id::create例化时，不用加this。</p><p>（2）UVM环境的启动顺序是：（1）tb_top全局的run_test；（2）根据UVM_TESTNAME产生my_case0的实例，（3）依次执行build_phase，形成完整的UVM树；（4）顺序执行UVM树各结点的connect_phase、main_phase等；（5）所有的phase执行完毕，结束仿真。</p><p>（4）冒烟测试就是DUT版本最基本的功能测试，如果通过测试，才会进入下一步的测试（功能测试，集成测试，系统测试）。</p><p>（6）build_phase函数用于组件例化，比如调用了其它类，然后new或者type_id例化，还有收信get也在build_phase中；而connect_phase内部是用来组件与组件之间的通信的，比如driver和sequencer的相互连接，比如env内connect的TLM通信（ap,export,port等等）。</p><p>（7）build_phase的执行顺序是自上而下，connect_phase的执行顺序是自下而上。</p><p>（8）driver负责驱动transaction，不负责产生，因此要做成一个无限循环while(1)的形式。这与monitor、reference model和scoreboard的情况非常类似。因为都在main_phase中做循环，因此在raise_objection时提起，在drop_objection撤销，则仿真结束。</p><p>（9）在interface中，里面的各个变量如果没有被赋值的话，那么就会默认是X态。（logic为四值状态，默认初态为X态）</p><p>（10）环境中模拟FIFO等存储模块时，需要在环境中，同RTL的入口wr和数据对齐，另外出口rd与数据也要对齐，这样在环境中队列深度才可能对齐DUT。（时序模型）</p><p>（11）经验理解：在搭建UVM环境时，如DRV，RM，MON，SCB等时，可以在reset_phase将组件内用到的变量初始化，这样可以在以后使用jump来跳转phase。<br>同时尽量使用全局变量，尽量不要使用静态变量static，可以方便复位。</p><p>（12）全局变量a可以作用在全局，如果一个task或function没有定义a，那么就使用全局变量a，如果task或function有定义a，那么就使用自己内部定义的a操作。</p><p>（13）scoreboard用于检查测试结果，一般并不需要在内部使用时钟，所有不需要加@(posedge); 这是因为scoreboard的输入和输出与被测模块的输入和输出相连接，在测试过程中，输入信号的变化会自动触发scoreboard的操作并计算结果。</p><p>（14）在环境中每个时钟使用interface赋值给interface，会出现类似于“毛刺”波形（从verdi波形，0变为0，但是0&#x3D;&#x3D;0），若右侧有至少一个变量，那么就不会出现这种情况。</p><p>（15）logic类型是一种四状态值的变量：X（未知）、Z（高阻）、0（逻辑低）和1（逻辑高）。另外，还有integer，reg和wire都是四值逻辑。</p><p>（16）bit、byte、shortint、int和longint为双状态的数据类型，只有0（逻辑低）和1（逻辑高）两种状态。注意：双状态变量被赋值x或z时，会被默认赋为0。</p><p>（17）objection机制：raise_objection()必须要在第一个消耗仿真时间之前。<br>drop_objection()必须要在最后一个消耗仿真时间之后。<br>注意：不消耗仿真时间的语句可以随机放置，其都会执行。消耗仿真时间的语句若随意放置，可能不会执行且报错。如在raise_objection语句前或在drop_objection语句后执行耗时语句，则此不会执行。</p><p>（18）仿真时间单位<code>timescale 定义是：时间单位/时间精度（</code>timescale time_unit&#x2F;time_precision）。例如延迟的时间#a，那么需要延时a*time_unit，同时需要四舍五入，与time_precision有关，为其整数倍。<br>注意：时间精度小于时间单位。</p><p>（19）UVM环境中，想当拍拿到DUT的信号，方法1：使用assign后门访问DUT信号，再#1可以拿到当拍数据；方法2：另外也可#1后，使用uvm_hdl_read的方法后门访问DUT信号。（此方法不行，还是需要#来延时）</p><p>（20）验证环境需要在解复位之前，将接口变量初始化（可用SV的系统函数deposit初始化变量，可在reset_phase将接口初始化），否则可能会出现X态的传播（DUT内部X保存着）。</p><p>（21）task phase中，可以多次提起&#x2F;撤销objection，每个raise_objection-&gt;drop_objection都可执行一次。<br>注意：当phase内的所有raise_objection-&gt;drop_objection都执行完成后，则此phase结束。</p><p>（24）使用TLM通信时，每次通过write的方式发送trans（句柄）给RM或者SCB时，都需要new()来新开辟trans空间，否则write过去的多个句柄都指向同一片空间，内容是一样的，都是最后一次修改值。如下例子：</p><p>上述表示一个句柄存入多个队列或多个句柄指向同一空间，若空间的内容发生变化，则所有指向此片空间的句柄，其取的空间内容也会发生变化。<br>（25）激励和驱动（seq和drv）的构造，需要考虑（四大天王）：<br>1、数据包个数；<br>2、背靠背的情况；<br>3、数据的内部字段填充；<br>4、响应DUT的反压；<br>（26）phase的new函数，不能使用virtual进行修饰。<br>寄存器模型<br>1、寄存器模型介绍<br>在UVM平台中，为了便于寄存器的操作和验证，我们通过寄存器模型对DUT中具有地址映射的寄存器和存储器进行建模，从而得到寄存器模型。<br>（1）寄存器模型可来源于寄存器描述文件，该文件由系统工程师编写并维护，设计、验证和软件都使用相同的描述文件，确保对寄存器理解的一致性。如REGDB<br>（2）寄存器模型可通过脚本工具自动化生成，确保寄存器模型正确性，并提高升级维护的效率。如寄存器模型更新<br>（3）寄存器模型集成在验证环境中，它与DUT中的寄存器模块中包含的寄存器信息完全一致，形成一个抽象的层次化的寄存器列表，它所包含的地址、域、属性等信息都与DUT中的寄存器完全相同。<br>（4）在验证环境中，寄存器模型封装了寄存器的访问，将直接总线访问寄存器抽象为寄存器模型的访问，对于寄存器地址更改、域的添加、属性变更等寄存器后期的变化，都不会对已有激励产生影响，大大提高了高层测试激励的复用性。<br>（5）寄存器模型提供了前门总线访问模式和后门访问模式，并内嵌多个sequence实现对寄存器的扫描。</p><p>2、寄存器模型的构成<br>（1）uvm_reg_field为寄存器模型中的最小单位，用寄存器的功能域来构建对应的bit位。<br>（2）uvm_reg与单个register对应，其可以例化多个uvm_reg_field对象。<br>（3）uvm_reg_map用来存储寄存器列表的各个寄存器的偏移地址。当寄存器模型使用前门访问方式来实现读或写操作时，uvm_reg_map就会将地址转换成绝对地址，启动读或写的sequence，并将读或写的结果返回。<br>（4）uvm_mem用来匹配硬件（DUT）存储模型。<br>（5）uvm_reg_block可容纳多个uvm_reg、uvm_mem和uvm_reg_map类，而且可以嵌套其它的uvm_reg_block。其中的uvm_reg_map类的对象default_map用来进行地址映射，以及用来完成寄存器的前后门访问。</p><p>上述类均继承自uvm_object类，将uvm_reg_field、uvm_reg、uvm_mem放在uvm_reg_block中，就组成了完整的register model。</p><p>如的plane_bitmap寄存器的uvm_reg如下所示：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> ral_reg_OXU_PLANE_BITMAP <span class="keyword">extends</span> uvm_reg;</span><br><span class="line"><span class="keyword">rand</span> uvm_reg_field UC;</span><br><span class="line"><span class="keyword">rand</span> uvm_reg_field MC;</span><br><span class="line"><span class="keyword">rand</span> uvm_reg_field TDM;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;OXU_PLANE_BITMAP&quot;</span>);</span><br><span class="line"><span class="keyword">super</span><span class="variable">.new</span>(name, <span class="number">32</span>,build_coverage(UVM_NO_COVERAGE));</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line">   <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> build();</span><br><span class="line">      <span class="keyword">this</span><span class="variable">.UC</span> = uvm_reg_field::type_id::create(<span class="string">&quot;UC&quot;</span>,,get_full_name());</span><br><span class="line">      <span class="keyword">this</span><span class="variable">.UC</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>, <span class="number">8&#x27;h00</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line">      <span class="keyword">this</span><span class="variable">.MC</span> = uvm_reg_field::type_id::create(<span class="string">&quot;MC&quot;</span>,,get_full_name());</span><br><span class="line">      <span class="keyword">this</span><span class="variable">.MC</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="number">8</span>, <span class="number">8</span>, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>, <span class="number">8&#x27;h00</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line">      <span class="keyword">this</span><span class="variable">.TDM</span> = uvm_reg_field::type_id::create(<span class="string">&quot;TDM&quot;</span>,,get_full_name());</span><br><span class="line">      <span class="keyword">this</span><span class="variable">.TDM</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="number">8</span>, <span class="number">16</span>, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>, <span class="number">8&#x27;h00</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line">   <span class="keyword">endfunction</span>: build</span><br><span class="line"></span><br><span class="line">`uvm_object_utils(ral_reg_OXU_PLANE_BITMAP)</span><br><span class="line"><span class="keyword">endclass</span> : ral_reg_OXU_PLANE_BITMAP</span><br></pre></td></tr></table></figure><p>其中，uvm_reg_field是一个类，其里面的方法configure中的参数的意义分别是：<br>eg：寄存器plane_bitmap</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span><span class="variable">.UC</span> = uvm_reg_field::type_id::create(<span class="string">&quot;UC&quot;</span>,,get_full_name());</span><br><span class="line"><span class="keyword">this</span><span class="variable">.UC</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>, <span class="number">8&#x27;h00</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.MC</span> = uvm_reg_field::type_id::create(<span class="string">&quot;MC&quot;</span>,,get_full_name());</span><br><span class="line"><span class="keyword">this</span><span class="variable">.MC</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="number">8</span>, <span class="number">8</span>, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>, <span class="number">8&#x27;h00</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.TDM</span> = uvm_reg_field::type_id::create(<span class="string">&quot;TDM&quot;</span>,,get_full_name());</span><br><span class="line"><span class="keyword">this</span><span class="variable">.TDM</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="number">8</span>, <span class="number">16</span>, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>, <span class="number">8&#x27;h00</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br></pre></td></tr></table></figure><p>1、第一个参数为此域的父类，即此域位于哪个寄存器中。<br>2、第二个参数是此域的宽度，上述每个域段各占8bit。<br>3、第三个参数是此域的最低位在整个寄存器中的位置。<br>4、第四个参数是此域的读与写的属性。<br>5、第五个参数是否是易失的（volatile），这个参数一般不会使用。<br>6、第六个参数是此域上电复位后的默认值。<br>7、第七个参数是此域是否有复位值，一般寄存器上电后都有复位值。<br>8、第八个参数是此域是否可以随机化，主要用于对寄存器进行随机写测试。<br>9、第九个参数是此域是否可以单独读写。</p><p>中uvm_reg_block中build函数中对uvm_reg寄存器plane_bitmap的例化和映射部分内容如下：（需要对uvm_reg_block下的所有uvm_reg寄存器都执行一下操作）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span><span class="variable">.default_map</span> = create_map(<span class="string">&quot;&quot;</span>, <span class="number">0</span>, <span class="number">4</span>, UVM_LITTLE_ENDIAN, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.PLANE_BITMAP</span> = ral_reg_OXU_PLANE_BITMAP::type_id::create(<span class="string">&quot;PLANE_BITMAP&quot;</span>,,get_full_name());</span><br><span class="line"><span class="keyword">this</span><span class="variable">.PLANE_BITMAP</span><span class="variable">.configure</span>(<span class="keyword">this</span>, <span class="literal">null</span>, <span class="string">&quot;&quot;</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.PLANE_BITMAP</span><span class="variable">.build</span>();</span><br><span class="line"><span class="keyword">this</span><span class="variable">.PLANE_BITMAP</span><span class="variable">.add_hdl_path</span>(&#x27;&#123;</span><br><span class="line">      &#x27;&#123;<span class="string">&quot;plane_bitmap&quot;</span>, -<span class="number">1</span>, -<span class="number">1</span>&#125;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.default_map</span><span class="variable">.add_reg</span>(<span class="keyword">this</span><span class="variable">.PLANE_BITMAP</span>, `UVM_REG_ADDR_WIDTH&#x27;h11E, <span class="string">&quot;RW&quot;</span>, <span class="number">0</span>);</span><br></pre></td></tr></table></figure><p>其中，调用create_map函数可以返回一个uvm_reg_map类，即default_map。uvm_reg_map作用是存储所有寄存器的地址，因此通过add_reg将实例化的PLANE_BITMAP加入到map映射中。</p><p>3、寄存器模型集成<br>验证环境中（ENV环境中）集成寄存器模型需要定义两个成员变量，第一个是寄存器模型reg_model类，第二个是转换器adapter类（内部有：reg2hbus和hbus2reg），之后步骤如下：<br>（1）声明与例化reg_model后，调用寄存器模型reg_model的configure函数。<br>（2）调用reg_model的build函数，将uvm_reg_block的所有uvm_reg、uvm_reg_field和uvm_reg_map进行例化，并将所有寄存器地址存储进uvm_reg_map。<br>（3）调用reg_model的lock_model函数，表示不再添加新的寄存器。<br>（4）调用reg_model的reset函数，将寄存器的初值转为设置的复位值，否则reg_model中所有寄存器初值为0.<br>（5）reg_model的前门访问操作由uvm_reg_map完成，因此在connect_phase中，需要将转换器adapter和hbus_sequencer通过set_sequencer函数告知reg_model的default_map，并将default_map设置为自动预测状态。</p><p>uvm_reg_block调用完后，需要配置后门访问路径 <code>set_hdl_paht_root()</code>。</p><p>常见使用：<br>在verilog中，寄存器模型提供了write_reg_by_name方法来按照寄存器名称动态地更新某一个寄存器的值。方法如下：reg_model.write_reg_by_name(reg_name,value);<br>同理read_reg_by_name可以按照寄存器名称动态读寄存器的值。</p><p>通过regmodel对hostreg进行读写时，若regdb和hostreg对不上，可能通过regmodel进行读写时，地址对应上不确定的reg，从而导致读写不期望的reg。（regmodel会给hbus_if地址、数据、有效信号等，然后对hostreg进行读写，由于regdb与hostreg对不上，所以地址与期望不符，所以会出现读写错误）</p><h1 id="二、System-Verilog"><a href="#二、System-Verilog" class="headerlink" title="二、System Verilog"></a>二、System Verilog</h1><h2 id="1-队列"><a href="#1-队列" class="headerlink" title="1 队列"></a>1 队列</h2><h3 id="1-1-常用操作"><a href="#1-1-常用操作" class="headerlink" title="1.1 常用操作"></a>1.1 常用操作</h3><ul><li>队列声明使用带 <code>$</code> 的下标：<code>[$]</code>。队列元素编号从 <code>0</code> 到 <code>$</code>。</li><li>在范围表达式中：<code>$</code> 在左侧表示最小值，<code>$</code> 在右侧表示最大值。</li><li><code>q.push_back(m)</code>：在末尾插入 <code>m</code>，长度 +1。</li><li><code>q.pop_front()</code>：取出第 0 个元素，长度 -1。</li><li><code>q.push_front(m)</code>：在开头插入 <code>m</code>，长度 +1。</li><li><code>q.pop_back()</code>：取出末尾元素，长度 -1。</li><li><code>q.insert(i, m)</code>：在第 <code>i</code> 位之后插入 <code>m</code>。</li><li><code>q.delete()</code>：删除队列所有元素（清空），也可指定删除第 <code>i</code> 个元素。</li></ul><div class="note info flat"><blockquote><p><strong>注意</strong></p></blockquote></div><blockquote><ul><li>队列未 push 数据时，默认 <code>size == 0</code>；读取队列的数据读到的也是 0。</li><li>往队列 push 数据 0 后，<code>size == 1</code>，读第 0 个数据也是 0。</li></ul></blockquote><h3 id="1-2-扩展"><a href="#1-2-扩展" class="headerlink" title="1.2 扩展"></a>1.2 扩展</h3><ul><li><code>q[$]</code> 表示队列最后一个元素。</li><li>队列合并：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> q1[$] = &#123;<span class="number">2</span>, <span class="number">3</span>&#125;, q2[$] = &#123;<span class="number">5</span>, <span class="number">6</span>&#125;;</span><br><span class="line">q1 = &#123;q1, q2&#125;; <span class="comment">// 结果：2,3,5,6</span></span><br></pre></td></tr></table></figure><ul><li>多维队列：<code>int que[num][$]</code> 表示有 num 个队列。</li><li>查找（所有 find 方法返回的都是 queue）：</li><li>find()：返回满足表达式的所有元素</li><li>find_index()：返回满足表达式的所有索引</li><li>find_first()：返回第一个满足表达式的元素</li><li>find_first_index()：返回第一个满足表达式的索引</li><li>find_last()：返回最后一个满足表达式的元素</li><li>find_last_index()：返回最后一个满足表达式的索引</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">que<span class="variable">.find</span>       <span class="keyword">with</span> (item &gt; <span class="number">3</span>);  <span class="comment">// 返回所有大于 3 的元素</span></span><br><span class="line">que<span class="variable">.find_index</span> <span class="keyword">with</span> (item == <span class="number">3</span>); <span class="comment">// 返回所有等于 3 的索引</span></span><br></pre></td></tr></table></figure><ul><li><code>q.shuffle()</code>：随机打乱队列元素顺序。</li></ul><h2 id="2-数组"><a href="#2-数组" class="headerlink" title="2 数组"></a>2 数组</h2><h3 id="2-1-合并数组"><a href="#2-1-合并数组" class="headerlink" title="2.1 合并数组"></a>2.1 合并数组</h3><ul><li>示例：<code>bit [n-1:0][m-1:0] array</code> 表示 n 个元素、每个元素位宽为 m；以整体连续存储、整体赋值。</li><li>数组大小定义格式必须是 <code>[msb:lsb]</code>，而不是 <code>[size]</code>。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> [n-<span class="number">1</span>:<span class="number">0</span>][m-<span class="number">1</span>:<span class="number">0</span>] array;</span><br><span class="line"><span class="keyword">bit</span> [<span class="number">2</span>:<span class="number">0</span>][<span class="number">7</span>:<span class="number">0</span>] array5;</span><br></pre></td></tr></table></figure><h3 id="2-2-非合并数组"><a href="#2-2-非合并数组" class="headerlink" title="2.2 非合并数组"></a>2.2 非合并数组</h3><ul><li>示例：<code>bit [n-1:0] array[m]</code> 表示 m 个元素、每个元素位宽为 n；分开存储、按维度赋值。</li><li>特性：可为任意数据类型；数组大小写在名字后；bit 组在存储上不连续。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> [<span class="number">7</span>:<span class="number">0</span>] array4[<span class="number">2</span>:<span class="number">0</span>];</span><br><span class="line"><span class="keyword">bit</span> [<span class="number">7</span>:<span class="number">0</span>] array4[<span class="number">3</span>];</span><br></pre></td></tr></table></figure><blockquote><p><strong>注</strong> 合并数组和非合并数组可以混用，例如：</p></blockquote><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> [<span class="number">3</span>:<span class="number">0</span>][<span class="number">7</span>:<span class="number">0</span>] barry[<span class="number">3</span>];</span><br></pre></td></tr></table></figure><blockquote><p><strong>总结</strong> 合并数组是连续存储的，非合并数组不是连续存储的。</p></blockquote><h3 id="2-3-关联数组"><a href="#2-3-关联数组" class="headerlink" title="2.3 关联数组"></a>2.3 关联数组</h3><p>动态数组容量过大且存储数据“稀疏”时，可以使用关联数组节省存储空间。</p><ul><li>关联数组没有固定大小，仿真器可采用树或哈希表存放。</li><li>定义示例：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> [<span class="number">63</span>:<span class="number">0</span>] assoc[<span class="keyword">bit</span> [<span class="number">63</span>:<span class="number">0</span>]];</span><br></pre></td></tr></table></figure><ul><li>foreach 遍历时，只遍历存储数据的部分。</li><li><code>.num</code> 表明关联数组大小（仅包含已存储数据的部分）。</li><li><code>.delete()</code> 删除关联数组全部内容。</li></ul><h3 id="2-4-数组初始化"><a href="#2-4-数组初始化" class="headerlink" title="2.4 数组初始化"></a>2.4 数组初始化</h3><p>SV 中数组可用 <code>&#123;&#125;</code> 列表初始化：</p><ul><li>使用 for&#x2F;foreach 循环初始化</li><li>使用默认初始化：</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a = &#x27;&#123;<span class="keyword">default</span>: <span class="number">0</span>&#125;;</span><br><span class="line">a = &#x27;&#123;<span class="keyword">default</span>: &#x27;x&#125;;</span><br></pre></td></tr></table></figure><p>扩展：数组的 inside 操作，<code>value inside arry</code> 返回布尔值，表示 value 是否在 arry 中。</p><h2 id="3-函数与任务"><a href="#3-函数与任务" class="headerlink" title="3 函数与任务"></a>3 函数与任务</h2><h3 id="3-1-function"><a href="#3-1-function" class="headerlink" title="3.1 function"></a>3.1 function</h3><ul><li>function 不消耗仿真时间。</li><li>function 一般不调用 task；但若 task 不含时间消耗，function 可调用该 task。</li><li>function 可有返回值，也可无返回值（void）。</li><li>function 可有输入&#x2F;输出，也可无输入&#x2F;输出。</li><li>function 若使用 void 无返回值，则调用结果不能赋值给其它变量（包括 string）。</li><li>函数名可以作为返回值返回。</li></ul><div class="note info flat"><blockquote><p><strong>注意</strong> 调用 function 时，若无 return 语句，函数名可以当作返回值返回（给函数名赋值即可）；若有 return，以 return 的值为准。执行到 return 后会退出 function。</p></blockquote></div><h3 id="3-2-task"><a href="#3-2-task" class="headerlink" title="3.2 task"></a>3.2 task</h3><ul><li>task 可以有 return；执行到 return 后会退出 task。</li><li>task 内可以消耗时间。</li></ul><p>拓展：task 和 function 通常按参数定义顺序传递；也可使用命名参数传递，提高可读性并跳过不需要的参数。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fun_a(<span class="variable">.a</span>(val1), <span class="variable">.b</span>(val2), <span class="variable">.sum</span>(val3));</span><br></pre></td></tr></table></figure><h2 id="4-位拼接操作符"><a href="#4-位拼接操作符" class="headerlink" title="4 位拼接操作符"></a>4 位拼接操作符</h2><p>位拼接是由一个或多个表达式产生的bit位连接在一起的结果。<br>常见拼接操作符：<br>eg：{a, b[3:0], w, 3’b101}; &#x3D;&#x3D;&#x3D;{a, b[3], b[2], b[1], b[0], w, 1’b1, b’b0, 1’b1}<br>复制操作符：<br>eg：{b, {3{a, b}}}&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;{b, {a,b}, {a,b}, {a,b}}&#x3D;&#x3D;{b,a,b,a,b,a,b}<br>字符串连接：<br>赋值的左侧不允许字符串连接，只允许作为表达式使用。<br>eg：string hello &#x3D; “hello”;</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;hello, “ “, “world”&#125;;</span><br></pre></td></tr></table></figure><p>&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;hello world<br>eg：{4{a}} &#x3D;&#x3D;&#x3D;&gt;{a,a,a,a}，{4{a[3:0]}}&#x3D;&#x3D;&#x3D;&gt;{a[3:0],a[3:0],a[3:0],a[3:0]}，从外往内进行“拆分”，一层一层分。</p><p>（2）注意拼接运算符：<br>eg：{1’b1,31{1’b0}}这个是错误的，正确的形式是{1’b1,{31{1’b0}}}</p><p>（3）使用parameter的方式拼接</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">parameter</span> A = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">bit</span>[<span class="number">9</span>:<span class="number">0</span>] value;</span><br><span class="line">value = &#123;<span class="number">1</span>’b1,&#123;(A-<span class="number">2</span>)&#123;<span class="number">1</span>b’<span class="number">0</span>&#125;&#125;,<span class="number">1</span>’b1&#125;;</span><br></pre></td></tr></table></figure><p>结果是10’h10000_00001。<br>6、循环语句<br>（1）for循环</p><p>执行顺序：1&#x3D;&#x3D;&gt;2&#x3D;&#x3D;&gt;3&#x3D;&#x3D;&gt;4&#x3D;&#x3D;&gt;2&#x3D;&#x3D;&gt;3&#x3D;&#x3D;&gt;4&#x3D;&#x3D;&gt;2&#x3D;&#x3D;&gt;…….循环进行，直到条件2不满足即可退出。</p><p>注意：在for循环里面定义了int i&#x3D;0，那么这个i变量只会用在这个for循环内，在for之外会被释放掉。若没定义i，则会使用全部变量的i。</p><p>（2）foreach循环<br>在foreach循环中，只需要指定数组名并在其后面的方括号中给出索引变量，verilog便会自动遍历数组中的元素。索引变量将自动声明，并只在循环内有效。foreach退出后，索引会被释放掉。foreach循环的条件常见为数组的大小。</p><p>注意：对于bit[3:0] data; &#x2F;&#x2F;使用foreach(data[i])来循环，循环四次，i是从3开始的，即3，2，1，0；<br>而对于bit[3:0] data[3:0]; &#x2F;&#x2F;使用foreach(data[i])来循环，循环四次，i是从3开始的，即3，2，1，0；<br>而对于bit[3:0] data[4]; &#x2F;&#x2F;使用foreach(data[i])来循环，循环四次，i是从0开始的，即0，1，2，3；</p><p>注意：对于二维数组的循环，使用foreach循环的话，需要一层一层的循环，即foreach(a[i][j])的i和j有一个必须是确定的，因此二维数组使用foreach循环如下：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">foreach</span>(a[i]) <span class="comment">//确定多少行循环</span></span><br><span class="line">  <span class="keyword">foreach</span>(a[i][j]) <span class="comment">//确定该行有多少列循环</span></span><br><span class="line">    xxxx <span class="comment">//总共循环i*j次</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span>(a[i,j])<span class="comment">//遍历a所有元素</span></span><br><span class="line">  xxxx <span class="comment">//总共循环i*j次</span></span><br></pre></td></tr></table></figure><p>注意：foreach进行循环时，对于多维数组使用foreach进行循环，若使用foreach([i,j,k…])来循环，语法是正确的，且i、j、k…变量属于foreach函数内部，不受外部影响；若使用foreach([i][j][k][.][.])来循环，语法是错误的，错误会显示i,j,k…未声明定义，因此需要外部定义i、j、k…..的值，只保留一个变量用于循环，则不会报错，其i、j、k….受外部影响，最后一个变量不受外部影响。</p><p>拓展：循环的顺序按照下述顺序</p><p>例子：</p><p>7、随机函数<br>randomize 、pre_randomize和post_randomize介绍：<br>randomize()、pre_randomize()和post_randomize()函数都是System Verilog的内置函数。<br>1、其中randomize()函数不是VMM和UVM的函数，可以随时调用，只会对代码中的rand和randc属性的变量做随机初始化，若执行成功返回值1，执行失败返回值0。<br>（1）randomize执行失败后，不会再执行post_randomize()函数。<br>（2）randomize()函数不能被重写。<br>（3）randomize()函数的随机种子可以被srandom()函数修改。</p><p>2、三个函数的执行顺序是pre_randomize()-randomize-post_randomize()，在执行randomize()之前或者之后会分别执行pre和post这两个函数，因此pre和post可以看作是randomize()函数的回调函数（callback function）<br>pre_randomize()和post_randomize()函数可以被用户重写。</p><p>3、pre_randomize()和post_randomize()函数可以被用户修改，用户使用pre_randomize()函数，常在随机前修改代码中非随机变量的值，如上下限、权重等，post_randmize()函数可以在随机后修改随机值或做一些其它的计算。pre_randomize()和post_randmize()是function类型，里面不能消耗时间，不能阻塞。</p><p>注意：<br>（1）随机函数对变量随机化，变量要是可随机化属性的。也就是说需要是rand和randc类型的才可以使用随机函数randomize随机化。<br>（2）randomize(a,b,c)可以指定随机变量，即传递参数变量，只有参数列表的变量才会被随机化。若参数列表中有非随机化变量，即使传递也不会修改非随机化变量的值。</p><p>拓展：<br>assert形式随机化：assert(class.randomize()with{});&#x2F;&#x2F;随机失败返回0且打印log，否则返回1。</p><p>8、随机数函数<br>1、$urandom_range<br>语法如下：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="keyword">int</span> <span class="keyword">unsigned</span> $urandom_range(<span class="keyword">int</span> <span class="keyword">unsigned</span> maxval,</span><br><span class="line">                                     <span class="keyword">int</span> <span class="keyword">unsigned</span> minval = <span class="number">0</span>);</span><br></pre></td></tr></table></figure><p>参数最小值min可以省略，且最大最小值的位置是可以互换的。<br>用法如下:</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Val1 = $urandom_range(<span class="number">7</span>,<span class="number">0</span>);</span><br><span class="line">Val2 = $urandom_range(<span class="number">7</span>);</span><br><span class="line">Val3 = $urandom_range(<span class="number">0</span>,<span class="number">7</span>); </span><br></pre></td></tr></table></figure><p>注意：返回指定范围的32bit无符号数。</p><p>2、$random()和$urandom()<br>$random()平均分布，返回32bit有符号随机数。<br>$urandom()平均分布，返回32bit位无符号随机数。</p><p>注意：上述随机数函数是随机一个数值后，再赋值给对应变量。</p><p>3、std::randomize() with 静态约束（内嵌约束）<br>可对非 rand&#x2F;randc 变量直接施加约束并随机化：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> a;</span><br><span class="line"><span class="keyword">int</span> b = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">int</span> c = <span class="number">20</span>;</span><br><span class="line"><span class="keyword">void</span>&#x27;(std::randomize(a) <span class="keyword">with</span> &#123; a <span class="keyword">inside</span> &#123;[b:c]&#125;; &#125;);</span><br></pre></td></tr></table></figure><p>9、随机变量<br>（1）关键词rand声明的随机变量，随机变量的值在指定范围内均匀分布；如果不添加约束，随机变量可以是指定有效范围内的任何值。（可重复）<br>（2）关键词randc声明的周期性随机变量，周期性随机变量的值在有效范围周期性出现，其数据类型只可以是bit或者enum型。</p><p>注意：1、randc对单一变量来说，具有唯一性，即每个变量在随机函数randomize随机后，都会有唯一值。比如randc bit[7:0] a，对a随机64次，那么每一次的值都会不一样。<br>2、对于数组类型而言，则可能重复。比如randc bit[7:0] a[3]，其中a[0]、a[1]和a[2]都是一个单一变量，那么在随机函数randomize随机后，a[0]、a[1]和a[2]可能相等。</p><p>因此产生唯一数组的方法：<br>（1）使用rand产生具有唯一元素的数组，使用foreach。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">rand</span> <span class="keyword">bit</span>[<span class="number">7</span>:<span class="number">0</span>] ua[<span class="number">64</span>];</span><br><span class="line"><span class="keyword">constraint</span> c&#123;</span><br><span class="line"><span class="keyword">foreach</span>(ua[i])</span><br><span class="line"><span class="keyword">foreach</span>(ua[j])</span><br><span class="line"><span class="keyword">if</span>(i != j)</span><br><span class="line">ua[i] != ua[j];</span><br><span class="line">&#125; <span class="comment">//约束使用&#123;&#125;</span></span><br></pre></td></tr></table></figure><p>（2）使用randc产生唯一元素数组。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span>[<span class="number">7</span>:<span class="number">0</span>] ua[<span class="number">64</span>];</span><br><span class="line"><span class="keyword">randc</span> <span class="keyword">bit</span>[<span class="number">7</span>:<span class="number">0</span>] val;</span><br><span class="line"><span class="keyword">foreach</span>(ua[<span class="number">64</span>])<span class="keyword">begin</span></span><br><span class="line">randomize();</span><br><span class="line">ua[i] = val;</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>注意：randc变量随机时，不能设置权重。<br>10、内嵌约束<br>产生一个随机数，可以使用随机数函数，同时也可以使用randomize()with{}来做约束：<br>比如：<br>std::randomize(a)with{a inside {[b:c]};};<br>表示a的值从b和c的值中选。其中a不需要指定是rand或randc类型。<br>又比如：<br>std::randomize(a)with{a dist {[b:c]:&#x2F;d,[e:f]:&#x2F;g};};<br>上述表示a的值按照百分比来选择。相比随机函数，内嵌约束可以选择变量值的占比等。</p><p>注意：内嵌约束需要使用{}来包裹约束内容，即约束块应该使用{}来包裹。同时前面的变量也需要用()包裹起来。<br>11、常用约束<br>声明约束时必须采用分段的表达，且必须具有固定的顺序。</p><p>（1）constraint的使用</p><p>constraint约束表达式的求解是由SV的约束求解器完成，满足约束的值由伪随机数发生器（PRNG）产生。</p><p>（2）inside的使用</p><p>inside是常见的约束运算符，表示变量应属于某个集合，除非存在别的约束，否则随机变量在集合里取值的概率是相等的。</p><p>拓展：<br>{val inside {[a:b]};};        &#x2F;&#x2F;表示在指定范围内；<br>{!(val inside {[a:b]});}      &#x2F;&#x2F;表示在指定范围外。</p><p>（3）dist的使用</p><p>关键词dist可以在约束中产生随机数的权重分布，符号用 :&#x3D; 或者 :&#x2F;<br>（1）:&#x3D;表示取值范围内的每一个值的权重都是相同的。<br>（2）:&#x2F;表示权重平均分到取值范围内的每一个值。</p><p>（4）solve A before B<br>表示在约束语句块B之前，先约束语句块A。使用solve…before约束后，将会改变随机数值的出现几率，使得某些特定的取值情况更易出现。<br>    使用solve before不能是randc型，且变量需要是整数型。</p><p>（5）关系操作（双向约束）<br>-&gt;操作用于表示约束表达式中的分配操作，将约束表达式的左侧变量与右侧表达式进行关联。<br>如约束块中(x&#x3D;&#x3D;0)-&gt;(y&#x3D;&#x3D;0);表示x&#x3D;0则y&#x3D;0，反之亦然。<br>（1）当x &#x3D; 0的时候y一定为0；<br>（2）当x !&#x3D; 0的时候，y的值随意；<br>（3）当y &#x3D;&#x3D; 0的时候，x值是随意的；<br>（4）当 y !&#x3D; 0的时候，x一定不为0；</p><p>注意：关系操作-&gt;是双向的。</p><p>（6）常用约束操作符<br>以下是verilog中常用的约束关系操作符：<br>相等关系：&#x3D;&#x3D;、!&#x3D;<br>大小关系：&lt;、&lt;&#x3D;、&gt;、&gt;&#x3D;<br>范围关系：inside、outside<br>包含关系：inside<br>逻辑关系：&amp;&amp;、||</p><p>（7）数组约束<br>a.sum() with (int’(item)) &#x3D;&#x3D; b 表示的意思是数组a进行求和，求和的大小sum为b，这么做可以防止数据求和后的溢出。</p><p>（8）软约束soft<br>soft为软约束，在constraint约束块中，可使用soft修饰约束表达式。soft软约束相对于其它未使用soft约束块的优先级要低，若与未soft修饰的约束表达式冲突，则soft修饰的约束表达式会失效。总结如下：<br>1、soft约束若与其它硬约束冲突的话，则soft约束会失效。<br>2、soft约束与其它硬约束有交集，则soft软约束和其它硬约束的交集则为约束值。<br>    3、若硬约束之间有冲突的话，仿真器会报错。</p><p>（9）条件约束</p><p>注意：上述约束块都是由{}包裹的。</p><p>（10）unique约束<br>可以用于生成变量集的唯一值或数组的唯一元素。如下所示：（生成多个不相同变量，或生成元素不相同的数组）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">rand</span> <span class="keyword">bit</span>[<span class="number">3</span>:<span class="number">0</span>] var1,var2,var3;</span><br><span class="line"><span class="keyword">rand</span> <span class="keyword">bit</span>[<span class="number">7</span>:<span class="number">0</span>] array[<span class="number">6</span>];</span><br><span class="line"><span class="keyword">constraint</span> cons_var1 &#123;<span class="keyword">unique</span> &#123;var1,var2,var3&#125;;&#125;</span><br><span class="line"><span class="keyword">constraint</span> cons_var2 &#123;<span class="keyword">unique</span> &#123;array&#125;;&#125;</span><br></pre></td></tr></table></figure><p>12、new函数<br>两者的相同点就是都申请内存并初始化变量。<br>（1）new()函数仅创建一个对象，new()可以使用参数设置对象的数值，即参数传递。<br>（2）new[]操作则建立一个含有多个元素的数组，而new[]只需使用一个数值来设置数组的大小。<br>13、cast使用<br>$cast(child,father)为向下类型转换（向上类型转换：父类指向子类），仅当父类指针指向的对象和待转换的类型一致时，$cast才会成功。eg</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> father;</span><br><span class="line">xxx</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> child <span class="keyword">extends</span> father;</span><br><span class="line">xxxx</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">father f1;</span><br><span class="line">child c1,c2;</span><br><span class="line">c1 = <span class="keyword">new</span>();</span><br><span class="line">f1 = c1;      <span class="comment">//f1句柄指向c1空间</span></span><br><span class="line"><span class="built_in">$cast</span>(c2,f1);  <span class="comment">//c2句柄指向c1空间</span></span><br></pre></td></tr></table></figure><p>使用场景：uvm中的p_sequencer通过$cast向下转换$cast(p_sequencer,m_sequencer)，指向virtual_sequencer。其中p_sequencer和virtual_sequencer都属于uvm_sequencer类型。<br>14、class类<br>1、属性和方法<br>（1）class类中的变量为属性；类中的程序也称为方法（task&#x2F;function）。<br>（2）类外定义方法需先将方法的原型定义（方法名和参数），并加入extern。在类外部需在方法名前加入类名和两个冒号（::作用域操作符，表示属于某个class类）</p><p>注意：在类中定义方法不需要加::作用域，如classa::taska()；在类外定义方法需要加::作用域表面方法属于哪一个类。</p><p>2、class的声明和例化<br>（1）SV通过new构造函数来创建对象。派生类的new函数会先调用父类的new函数。<br>（2）1、类的声明是声明一个句柄，其句柄指向类，即指向此类的指针。2、例化是创建对象，分配内存空间，并将句柄指向这一段内存空间。如下：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> A;</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line">A a;       <span class="comment">//声明了一个a句柄指向A。</span></span><br><span class="line">a = <span class="keyword">new</span>();  <span class="comment">//创建一个A类的实例，并将其分配给a句柄。</span></span><br></pre></td></tr></table></figure><p>总结：声明一个句柄，例化一个对象，使句柄指向开辟的空间。</p><p>3、对象销毁<br>当一个对象的空间没有句柄指向时，即不被“需要”，SV的内存管理会释放此空间。</p><p>４、extends继承<br>extends关键字用于创建一个类的继承关系。通过extends可以使类派生另一个类，并继承其属性和方法。（1）派生类中可以重写（重定义）基类的方法（task&#x2F;function）和属性（variable）；（2）派生类中可以新定义新方法和属性，以实现自己的特定行为。<br>super关键字可用于引用父类中的成员、参数等。若派生类对基类的方法A重写了，又想使用基类的方法A，可以使用super.A()来引用父类的方法A。</p><p>总结：子类继承于父类，子类可使用父类的方法和属性并重写，或子类自新增属性和方法。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Base;</span><br><span class="line">   <span class="keyword">int</span> a = <span class="number">3</span>;</span><br><span class="line">   <span class="keyword">function</span> <span class="keyword">void</span> myFunction();</span><br><span class="line">       <span class="built_in">$display</span>(<span class="string">&quot;Base class %d&quot;</span>,a);</span><br><span class="line">   <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Derived <span class="keyword">extends</span> Base;</span><br><span class="line">    <span class="keyword">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">void</span> myFunction();</span><br><span class="line">        a = <span class="number">12</span>;</span><br><span class="line">        <span class="built_in">$display</span>(<span class="string">&quot;Derived class %d&quot;</span>,a);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>若子类Derived被声明且例化后，子类空间存在两个变量，即super.a和this.a；</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">derived = <span class="keyword">new</span>();</span><br><span class="line">base = derived;</span><br><span class="line">derived<span class="variable">.myFunction</span>();</span><br><span class="line">base<span class="variable">.myFunction</span>();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;base_test %d&quot;</span>,base<span class="variable">.a</span>);</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;drv_test %d&quot;</span>,derived<span class="variable">.a</span>);</span><br></pre></td></tr></table></figure><p>若父类指向子类，则打印结果为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Derived class     12</span><br><span class="line">Base class        3     //父类类无virtual，所以不调用子类方法</span><br><span class="line">base_test        3     //父类句柄指向子类空间，父类见不到子类的this.a，找的super.a</span><br><span class="line">drv_test         12    //子类调用自己的this.a</span><br></pre></td></tr></table></figure><p>注意：（1）若父类指向子类，子类新增的方法和属性对于父类是不可见的；<br>注意：super只能用一层，多层使用不行。</p><p>5、virtual虚方法<br>virtual虚方法就是一个基本的多态结构，父类使用virtual后，则可以“见到”子类的方法。</p><p>父类中使用virtual定义方法function时，父类句柄在指向子类对象后，可以动态索引到子类重写的子类方法。子类若存在相同的方法function，那么父类会直接调用子类的方法function。若父类中无virtual定义方法function，那么父类只能调用自己的方法function。</p><p>（1）在父类的方法定义时，若方法日后会覆盖和重载，那么加virtual。<br>（2）virtual只需要声明一次，子类可以无需声明。<br>（3）成员变量不能添加virtual，不能使用父类句柄找子类中的成员变量。<br>（4）虚方法尽量定义在最底层的父类中。</p><p>注意：可以小指针指向大对象（父类&#x3D;子类），即父类句柄指向子类空间，指向后，父类只能访问子类中属于自己的成员变量；但是不能大指针指向小对象（子类&#x3D;父类），即子类句柄指向父类空间，否则会报错（除非cast转换）。</p><p>UVM中interface为硬件与软件的接口，因此要加virtual来定义interface</p><p>扩展：<br>子类继承父类，父类的方法A使用了virtual来声明，则调用父类的方法A时，会直接调用子类的同名方法A，此时若子类里新增一个属性（变量a），则子类的方法A可以直接使用属性a来做逻辑。<br>15、宏定义<br>（1）宏定义（<code>define A xxx） </code>define A xxx是在编译时完成的，而不是执行时，也就是说并会不因为某一个分支（比如if….else if…..条件分支）未执行而不进行宏定义。如果是条件编译即可（<code>ifdef….</code>else…条件编译），如下：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">ifdef</span> MACRO_A</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> A xxx</span></span><br><span class="line"><span class="meta">`<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> A yyy</span></span><br><span class="line"><span class="meta">`<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">`<span class="keyword">ifdef</span> MACRO_A</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> A xxx</span></span><br><span class="line"><span class="meta">`<span class="keyword">elsif</span> MACRO_B</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> A yyy</span></span><br><span class="line">……</span><br><span class="line"><span class="meta">`<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>可以对宏定义进行选择。（在编译选项中选择定义MACRO_A或MACRO_B来&#96;define A的值）</p><p>若没有定义宏MACRO_A和宏MACRO_B，则可使用：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">ifndef</span> MACRO_A</span></span><br><span class="line"><span class="meta">`<span class="keyword">ifndef</span> MACRO_B</span></span><br><span class="line"><span class="meta">`<span class="keyword">define</span> A xxx</span></span><br><span class="line"><span class="meta">`<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">`<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>（2）跨行的宏定义<br>使用反引号\（续行符）连接，定义一个交换数值的多行宏，使用反斜杠连接不同行，比如：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> SWAP(a,b) do &#123; \</span></span><br><span class="line"><span class="meta">    int t = 0;\</span></span><br><span class="line"><span class="meta">    t = a; \</span></span><br><span class="line"><span class="meta">    a = b; \</span></span><br><span class="line"><span class="meta">    b = t; \</span></span><br><span class="line"><span class="meta">&#125; while(0)</span></span><br></pre></td></tr></table></figure><p>调用时：&#96;SWAP(a,b)<br>注意：在行尾的反斜杠“ \ ”之后不能有空格或字符，否则编译器会报错<br>注意：续行符的作用是将宏定义的一行代码分多行书写，提高代码的可读性。若不加续行符则宏定义只有一行，影响美观。</p><p>（3）防止头文件被重复包含</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> BODYDEF_H </span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BODYDEF_H </span></span><br><span class="line"><span class="comment">//头文件内容 </span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>注意：若<code>define A 1后，之后使用宏A的值时，需要</code>A来获取宏A的值。</p><p>（4）带参数的宏（宏文本）<br>1、使用<code>str</code>（&#96;&#96;双引号，分隔符）区分引用内部的变量和其它部分。比如：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> fnoc_path(str) dut.side_in.``str``.data</span></span><br></pre></td></tr></table></figure><p>调用时&#96;fnoc_path(fifo)则表示dut.side_in.fifo.data</p><p>2、使用<code>”str</code>”（&#96;反引号，”双引号）表示引用内部的变量也会被替换。比如：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> fnoc_path(str) “str.data”</span></span><br></pre></td></tr></table></figure><p>调用时&#96;fnoc_path(side_in)则不会替换：”str.data”</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> fnoc_path(str) `”str.data`”</span></span><br></pre></td></tr></table></figure><p>调用时&#96;fnoc_path(side_in)则可以替换：”side_in.data”</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> fnoc_path(str) `”data_str_data`”</span></span><br></pre></td></tr></table></figure><p>调用时&#96;fnoc_path(data)则不会替换：”data_str_data”</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">`<span class="keyword">define</span> fnoc_path(str) `”data_``str``_data`”</span></span><br></pre></td></tr></table></figure><p>调用时&#96;fnoc_path(data)则可以替换：”data_data_data”</p><p>注意：宏定义传参的本质是替换</p><p>扩展：<br>用法：&#96;undef MACRO<br>作用：解除宏定义<br>16、@和wait<br>1、电平敏感事件：wait(&lt;条件表达式&gt;)是电平触发，即括号中的内容为真时触发。<br>eg：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">wait</span>(enable == <span class="number">1</span>)<span class="keyword">begin</span> xxx <span class="keyword">end</span>; <span class="comment">/*等待且阻塞后续进程*/</span></span><br></pre></td></tr></table></figure><p>等待enable信号，当条件表达式为“真”时，则立刻执行语句块；否则仿真程序进入等待状态，直到条件表达式为真。</p><p>2、边沿触发事件：@(&lt;事件表达式&gt;)是边沿触发，即括号中的事件发生跳变时触发。<br>eg：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@(<span class="keyword">posedge</span> clk)<span class="keyword">begin</span> xxx <span class="keyword">end</span>; <span class="comment">/*等待且阻塞后续进程*/</span></span><br></pre></td></tr></table></figure><p>等待时钟敏感，时钟发生正跳变后退出等待状态，继续执行下一条语句<br>eg：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@(a)<span class="keyword">begin</span> xxx <span class="keyword">end</span>; <span class="comment">/*等待且阻塞后续进程*/</span></span><br></pre></td></tr></table></figure><p>等待a敏感，a发生边沿跳变时退出等待状态，继续执行下一条语句</p><p>总结：<br>（1）wait和@的使用：wait等待电平敏感；@等待边沿敏感。<br>（2）wait常放在fork….join中，此时不会阻塞其它并行语句的执行。<br>（3）@(clk)常放在while循环中，一直随clk边沿触发。</p><p>注意：在@的使用中，多个while语句块的执行过程中，语句块的语句执行后，若while未退出，每次执行完“一次语句块”后，都会在@处等待下一次语句块的执行。<br>17、时钟块<br>（1）clocking……endclocking块是对所在的module&#x2F;interface&#x2F;checker&#x2F;program里信号的采样和驱动的timing属性进行声明。<br>（2）同一个module&#x2F;interface&#x2F;checker&#x2F;program中可以声明多个clocking…endclocking，同一个信号也可以出现在不同的clocking….endclocking中。<br>（3）Default的clocking skew作用在所有未明确声明的信号。对于声明为input的信号，clocking skew是指在clock event到来之前多少时刻对其进行取样。对于output信号，则是指clock event发生后多少时刻对其进行驱动。</p><p>（1）SV中的时间单位step等于全局时间精度，如果未指明，则default input skew是1step，default output skew是0。</p><p>18、枚举类型<br>枚举类型的定义：enum 枚举标签类型 {A &#x3D; value, B, C,,,,} enum_e;<br>在枚举标签类型和value缺省的情况下，默认枚举标签类型为int类型，value的值从0开始依次加1，即A&#x3D;0，B&#x3D;1，C&#x3D;2，，，，。若B&#x3D;value，则C&#x3D;value+1，A等于0</p><p>注意：没有特别指出的话，枚举类型会默认当成int类型存储。</p><p>拓展：枚举类型可以作为数组的索引，如：int arry[enum_e];则arry[A]、arry[B]和arry[C]等都为一个数组元素，且以枚举列表标签为索引。（enum_e必须typedef 枚举标签类型 {A&#x3D;value,B,C,,,} enum_e这么定义才可以int arry[enum_e]这么定义数组）</p><p>注意：arry[enum_e]在未赋值时，$size(arry)大小为0，赋值多少则size大小为多少，数组最大size，则由枚举标签类型决定。（自动变化）</p><p>19、typedef&#x2F;struct&#x2F;union<br>（1）typedef是创建新的类型（创建的类型可以用来定义新的变量，有点类似于&#96;define），<br>用法：typedef 已有数据类型 新类型;</p><p>（2）<br>1、packed为填充（压缩的）的，unpacked为非填充的（非压缩的，以4个字节为一部分）。默认情况下为非填充的类型，使用关键字packed则为填充的类型。若为填充的结构体，压缩结构体按照指定的顺序以相邻的位来存储结构体成员。压缩结构体被当做一个向量存储，结构体的第一个成员在向量的最左边。（还有压缩联合体，压缩数组等）</p><p>2、packed structure的成员可以通过成员名引用（<struct_name>.<mem_name>）也可以使用结构体向量的相应位来引用（<struct_name>[M:N]）。</p><p>（3）struct是创建结构体（结构体内可以由多个不同类型变量组成。），即描述一组相关的数据，常见用法typedef struct packed{}xxx_t;，可以通过.成员变量的方法引用。</p><p>（4）联合体union。<br>1、联合体只存储一个元素，但该元素可以有多种表示方法，每种表示方法可以是不同数据类型<br>2、union声明及成员引用方法同struct，关键词为union。<br>3、union内的成员公用同一存储空间。所以对其中一个成员赋值，其他成员也会相应变化，只是数据类型不同而已。（不能有多驱动，即对多个元素驱动）</p><p>扩展：结构体初始化，可以是用str &#x3D; ‘{default:0}; 使用此方法结构体则全部初始化为0。</p><p>注意：压缩的（合并的）结构体&#x2F;联合体，若内部有非合并的成员（如非合并数组），则编译器会报错。（Unpacked member found in a packed structure or union:<br>  Packed structure ‘str’ contains unpacked members.）</p><p>注意：合并数组中，若某时刻对合并数组多次赋值操作，使用interface阻塞采样合并数组变量中的单bit成员，可能会出现X态，原因可能是合并数组的成员变量，在存储上是相连的，采样导致地址冲突。<br>20、常用逻辑操作<br>1、取反<br><del>表示按位取反，而!表示逻辑非（非真即假）。比如!7&#x3D;0，</del>6&#x3D;~110&#x3D;001</p><p>2、取余%<br>%（取模，即取余数），例如3%7&#x3D;3，7%3&#x3D;1，即余数的意思，即经过除操作后，剩下的余数。</p><p>21、流操作<br>{&lt;&lt;{}}和{&gt;&gt;{}}属于stream operation流操作符<br>（1）流操作{&lt;&lt;{}}按照从右到左的形式转换成流；<br>（2）流操作{&gt;&gt;{}}按照从左到右的形式转换成流。</p><p>22、fork语句<br>begin……end语句以顺序方式执行，而fork…join中的语句则以并发方式执行，在所有语句执行完成后，会退出fork….join语句块去执行后面的语句。fork….join内的语句，如果多个语句“同时并行执行”，其实是“顺序”执行的，而如果加了延时的话，那么就会有先后，时间少的先执行，时间多的后执行。<br>1、fork…join<br>语句块是并行执行的，多个语句块在同一时刻执行，那么会先执行前一个语句块，再执行后一个语句块，但是所有的语句块都是在一个clk内执行完成。<br>2、fork…join_none<br>在调度其块内语句时，父线程继续执行，不等待。其余与fork…join相似。<br>3、fork…join_any<br>对块内语句进行调度时，当第一个语句完成后，父线程才继续执行，其它停顿的线程也得以继续。其余与fork…join相似。</p><p>注意：在fork语句块内若存在一个while条件循环，如while(a&gt;10)，若初始时判断while条件不满足，则表明此while(a&gt;10)不会再执行，即使之后存在的其它语句块使a&gt;10，其也不会执行。</p><p>扩展1：for循环中使用fork…..join_none</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">3</span>; i++)<span class="keyword">begin</span></span><br><span class="line"><span class="keyword">fork</span></span><br><span class="line"><span class="built_in">$display</span>(“i=%<span class="number">0</span>d”,i);</span><br><span class="line"><span class="keyword">join_none</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>$display打印的三次值都为3，因为i就一个地址，当i等于3时，再执行$display打印（3个进程）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">3</span>; i++)<span class="keyword">begin</span></span><br><span class="line"><span class="keyword">fork</span></span><br><span class="line"><span class="keyword">automatic</span> <span class="keyword">int</span> k = i;</span><br><span class="line"><span class="built_in">$display</span>(“k=%<span class="number">0</span>d”,k);</span><br><span class="line"><span class="keyword">join_none</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>$display打印的三次值分别为0、1和2，因为automatic每次循环会初始化一个变量k，即一个新的地址并拷贝当前i值，三次各不一样，再执行$display打印（3个进程）。</p><p>扩展2：wait fork的使用</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fork</span></span><br><span class="line">check_trans(tr1);</span><br><span class="line">check_trans(tr2);</span><br><span class="line">check_trans(tr3);</span><br><span class="line"><span class="keyword">join_none</span></span><br><span class="line"><span class="keyword">wait</span> <span class="keyword">fork</span></span><br></pre></td></tr></table></figure><p>语句wait fork等待上述fork创建的并行线程结束。（作用范围：wait fork与fork同一层级）</p><p>扩展3：disable的使用</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fork</span></span><br><span class="line">check_trans(tr1);</span><br><span class="line">check_trans(tr2);</span><br><span class="line">check_trans(tr3);</span><br><span class="line"><span class="keyword">join_none</span></span><br><span class="line">#<span class="number">1</span> <span class="keyword">disable</span> <span class="keyword">fork</span></span><br></pre></td></tr></table></figure><p>语句disable fork在#1后，终止fork进程以及其所有子线程。（作用范围：disable fork与fork同一层级，如果放在fork内，不会生效）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fork</span>:fork1</span><br><span class="line"><span class="keyword">begin</span>:begin1</span><br><span class="line">check_trans(tr1);</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">begin</span>:begin2</span><br><span class="line">check_trans(tr2);</span><br><span class="line">#<span class="number">1</span> <span class="keyword">disable</span> fork1/begin1/begin2</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">join_none</span></span><br><span class="line"><span class="keyword">wait</span> <span class="keyword">fork</span></span><br></pre></td></tr></table></figure><p>语句disable fork1&#x2F;begin1&#x2F;begin2（发在同级或内部其它地方，前提是此进程被执行过，否则不会生效。）在#1后，会终止指定进程fork1&#x2F;begin1&#x2F;begin2。如果这里写disable fork则实际不会终止fork进程。<br>23、break和continue<br>1、break直接退出包含它的循环，不再执行break后的语句。<br>2、continue结束本次包含它的循环，即continue之后的语句不再执行，结束当前本次循环，不影响之后的循环。</p><p>多层循环嵌套：break退出包含它的循环（同层级循环），如果在里层循环，则退出里层循环，如果在外层循环，则退出外出整个循环。（continue类似）<br>24、event事件<br>定义：event eve; &#x2F;&#x2F;eve是一个事件。<br>事件是静态的同步对象句柄，可以像参数一样在子程序中传递，可以用来同步多个并发的进程，比如某个进程等待着事件，另一个进程则触发这个事件。</p><p>事件的触发和阻塞等待<br>触发：-&gt;eve 或 -&gt;&gt; eve;<br>等待：@(eve) 或 wait(eve.triggered())</p><p>wait_order的使用<br>wait_order阻塞等待多个事件的触发，并且要求这多个事件按照用户决定顺序触发。wait_order可以和else一同使用，当多个事件按顺序触发时，执行wait_order后的语句，否则执行else后的语句。</p><p>wait_order里面的a，b，c需要注意事件顺序，否则会报SV错误。<br>event事件和task任务的区别：<br>1、触发事件后，主程序可以继续往下执行，不受触发的事件何时结束的影响；<br>2、在调用一个任务后，需要等待任务执行完毕后，才可以继续往下执行。</p><p>25、系统函数<br>（1）deposit函数<br>在 verilog 中，<code>$deposit</code> 是一个系统函数，用于在仿真过程中将一个值存储到指定的变量中。使用方法：<code>$deposit(variable, value);</code><br>常用于在初始时刻，给输入赋一个初值，常赋值为0。</p><p>（2）<code>$onehot(BUS)</code>、<code>$onehot0(BUS)</code> 和 <code>$countbits(exp, x, x)</code><br>1、<code>$onehot(BUS)</code>：BUS 中有且仅有 1 bit 为 1，其它为 0，则返回真，否则返回假。<br><code>$onehot(expression)</code> 等价于 <code>$countbits(expression, 1) == 1</code>，返回 <code>true (1&#39;b1)</code>，否则返回 <code>false (1&#39;b0)</code>。</p><p>2、<code>$onehot0(BUS)</code>：BUS 中不超过 1 bit 为 1（允许全 0），则返回真，否则返回假。<br><code>$onehot0(expression)</code> 等价于 <code>$countbits(expression, 1) &lt;= 1</code>，返回 <code>true (1&#39;b1)</code>，否则返回 <code>false (1&#39;b0)</code>。</p><p>3、<code>$countbits(expression, control_bit, control_bit)</code>：计算位向量中指定的 <code>0/1/x/z</code> 数量，返回值为整数。<br><code>$countbits(expression, 1)</code>：返回表达式中 <code>1</code> 的数量；<br><code>$countbits(expression, 0, 1)</code>：返回表达式中 <code>0</code> 和 <code>1</code> 的总数量；<br><code>$countbits(expression, x, z)</code>：返回表达式中 <code>x</code> 和 <code>z</code> 的总数量；</p><p>扩展：可以用于约束，比如约束nbit变量中，有多少bit拉高。比如：<br>std::randomize(signal)with{$countbits(signal,1) &#x3D;&#x3D;3;}; &#x2F;&#x2F;将约束变量signal仅3bit拉高。</p><p>（3）文本系统函数<br>1、<code>$fopen</code>：<code>fd = $fopen(&quot;file_name&quot;, &quot;mode&quot;);</code> 其中 <code>file_name</code> 为文件名，<code>mode</code> 常见 <code>r/w/a</code>，<code>fd</code> 为文件句柄。<br>2、<code>$fwrite</code>：<code>$fwrite(fd, &quot;%d,%h&quot;, a, b);</code> 向文件写数据；也可用 <code>$sformatf(&quot;x=%0d&quot;, x)</code> 生成字符串后写入。<br>3、<code>$fclose</code>：<code>$fclose(fd);</code> 关闭文件句柄。</p><p>（4）$typename系统函数<br>1、系统函数 <code>$typename()</code> 用于在运行时获取变量或表达式的数据类型，并以字符串形式返回类型名。用法：<code>string_a = $typename(a);</code></p><p>（5）$timeformat使用<br>用法：<code>$timeformat(units_number, precision_number, suffix_string, minimum_field_width);</code><br>1、<code>units_number</code>：<code>0 ~ -15</code> 之间的整数，表示打印时间单位：<code>0</code> 秒 s，<code>-3</code> 毫秒 ms，<code>-6</code> 微秒 us，<code>-9</code> 纳秒 ns，<code>-12</code> 皮秒 ps，<code>-15</code> 飞秒 fs。<br>2、<code>precision_number</code>：小数点后保留位数，默认 0。<br>3、<code>suffix_string</code>：时间值后缀字符串，默认空。<br>4、<code>minimum_field_width</code>：最小字段宽度，默认 20。</p><p>（6）、$clog2()使用<br>用法：$clog2(n);<br>n为整数，其功能就是对输入整数实现以2为底对数，其结果向上取整。</p><p>（7）$value$plusargs(user_string,variable)使用<br><code>$value$plusargs(user_string, variable)</code> 用于在仿真时，将参数传递到环境内部。<br>例如：<code>$value$plusargs(&quot;string_t=%s&quot;, variable)</code>，同时在命令行中带 <code>+string_t=xxx</code>（以 Makefile 为准），最后 <code>variable</code> 得到 <code>xxx</code> 字符串。</p><p>注：可以用来传递其它变量，如int、bit、long等类型。</p><p>（8）$test$plusargs(string)使用<br><code>$test$plusargs(string)</code> 用于在命令行查找字符串 <code>string</code>，若查到则返回 1，否则返回 0。命令行仿真时需要将 <code>+string</code> 加入命令行（以 Makefile 为准）。</p><p>（9）$readmemh和$readmemb<br>读取的内容只包括：空白位置，注释行、二进制或十六进制的数字。<br>数字中不能包含位宽说明和格式说明，其中readmemb要求每个数字是二进制数，readmemh要求每个数字必须是十六进制数。数字中不定值x或X，高阻值z或Z，和下划线（_）的使用方法和代表意义与一般Verilog HDL程序中的用法一致。</p><p>在Verilog语法中，一共有以下六种用法：<br>（1）$readmemb(“&lt;数据文件名&gt;”,&lt;存储器名&gt;);<br>（2）$readmemb(“&lt;数据文件名&gt;”,&lt;存储器名&gt;,&lt;起始地址&gt;);<br>（3）$readmemb(“&lt;数据文件名&gt;”,&lt;存储器名&gt;,&lt;起始地址&gt;,&lt;终止地址&gt;);<br>（4）$readmemh(“&lt;数据文件名&gt;”,&lt;存储器名&gt;);<br>（5）$readmemh(“&lt;数据文件名&gt;”,&lt;存储器名&gt;,&lt;起始地址&gt;);<br>（6）$readmemh(“&lt;数据文件名&gt;”,&lt;存储器名&gt;,&lt;起始地址&gt;,&lt;终止地址&gt;);</p><p>$readmemb和$readmemh是把数据文件的内容读到存储器中<br>数据文件的格式：1111 1010 0101 1x1z 1_1_ 1_111<br>或者：<br>1111<br>1010<br>0101<br>1x1z<br>1_1_<br>1_111</p><p>（10）$writememh和$writememb<br>同$readmemh和$readmemb的用法类似，作用是将存储器的数据写入数据文件中。<br>26、force与release<br>force语句的用法：force &lt;寄存器变量或者线网&gt; &#x3D; &lt;&lt;赋值表达式&gt;&gt;; &#x2F;&#x2F;左边输出，右边输入<br>release语句的用法：release &lt;寄存器变量或者线网&gt;<br>force语句应用于寄存器变量或者线网变量时，则在force语句执行后，该变量将强制由&lt;赋值表达式&gt;进行连续驱动，此时将忽略较低优先级的驱动，比如assign，直到有一条release语句执行为止。<br>27、时钟块<br>时钟块（clocking block）是一种用于描述时钟和时序约束的结构，用于控制同步信号的时序。<br>1）时钟块默认格式为：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">clocking</span> cb(<span class="keyword">posedge</span> clk);</span><br><span class="line"><span class="keyword">default</span> <span class="keyword">input</span> #<span class="number">1</span>step <span class="keyword">output</span> #<span class="number">0</span>;</span><br><span class="line"><span class="keyword">input</span> a;</span><br><span class="line"><span class="keyword">output</span> b;</span><br><span class="line"><span class="keyword">endclocking</span></span><br></pre></td></tr></table></figure><p>上述a为采样DUT的信号，b为驱动DUT的信号。时钟块的默认时序是在#1step延时之后采样输入信号（在前一个时间片的Postponed区域），在#0延时之后驱动输出信号。<br>2）指定setup、hold下的采样与驱动</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">clocking</span> cb@(<span class="keyword">posedge</span> clk);</span><br><span class="line"><span class="keyword">default</span> <span class="keyword">input</span> #t1 <span class="keyword">output</span> #t2;</span><br><span class="line"><span class="keyword">input</span> a;</span><br><span class="line"><span class="keyword">output</span> b;</span><br><span class="line"><span class="keyword">endclocking</span></span><br></pre></td></tr></table></figure><pre><code>上述表示a在时钟沿之前的t1时刻进行采样（Setup_time），b在时钟沿之后的t2时刻进行驱动（hold_time）。</code></pre><p>总结：时钟块在边沿采样时，采样setup_time前的信号值，而在驱动时，时钟块的值在hold_time后再驱动DUT。（采样setup_time的值，值等hold_time后驱动）</p><p>注意：在时钟块中应当使用同步驱动，即“&lt;&#x3D;”操作符来驱动信号。<br>28、package包<br>使用如下：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> pkg_all;</span><br><span class="line"><span class="keyword">import</span> pkg1::*;</span><br><span class="line"><span class="keyword">import</span> pkg2::*;</span><br><span class="line"><span class="meta">`<span class="keyword">include</span> “file1.sv”</span></span><br><span class="line"><span class="meta">`<span class="keyword">include</span> “file2.sv”</span></span><br><span class="line"><span class="keyword">endpackage</span></span><br></pre></td></tr></table></figure><p>总体来说，对于SV文件的编译，要么将文件在filelist中列出，要么在top外include进去。对于嵌套型的pkg，pkg中的内容只对当前pkg可见，不可跨多层。（重要）</p><p>注意：<br>（1）不能在package中include “interface.sv”，否则报错；<br>（2）不能在module和package内include “pkg.sv”，否则报错；<br>（3）可以在module和package内使用import pkg::*<br>（4）注意文件放置的顺序，文件的编译与顺序也有关<br>（5）方式1：filelist中列出文件路径，再结合package中的相对路径一同作用，使编译通过。（通常使用这种方法）方式2：不用filelist列出文件路径，package中写绝对路径，使用编译通过。</p><p>注意使用import xxx_pkg.sv进行导包后，;不能忘记，应该是import xxx_pkg.sv;</p><p>29、fopen文件操作<br>verilog中，文件操作用于读取外部数据或写入结果。<br>1）$fopen用于打开一个文件，并返回一个文件句柄（integer类型）。如果文件无法打开，则返回值为 0<br>语法：integer $fopen(string file_name, string mode);<br>file_name：要打开的文件名（包括路径）。<br>mode：文件打开模式，常用的模式有：<br>“r”：以只读模式打开文件（读取文件内容）。<br>“w”：以写入模式打开文件（如果文件存在，则清空内容；如果文件不存在，则创建新文件）。<br>“a”：以追加模式打开文件（如果文件存在，则在文件末尾追加内容；如果文件不存在，则创建新文件）。<br>返回值<br>成功打开文件时，返回一个非零的文件句柄（integer类型）。<br>如果文件无法打开（如文件不存在或权限不足），返回0。</p><p>2）$feof用于检查文件是否已经到达末尾。到达末尾，则返回1；否则返回0。<br>语法：integer $feof(integer fd);<br>fd：文件句柄，由$fopen返回。<br>返回值<br>如果文件到达末尾，返回1。<br>如果文件未到达末尾，返回0。</p><p>3）$fscanf用于从文件中读取格式化的数据，并将其存储到指定的变量中。<br>语法：integer $fscanf(integer fd, string format, output args, …);<br>fd：文件句柄，由$fopen返回。<br>format：格式化字符串，用于指定如何解析文件中的数据。常用的格式说明符包括：<br>%d：读取十进制整数。<br>%x：读取十六进制整数。<br>%f：读取浮点数。<br>%s：读取字符串。<br>%c：读取单个字符。<br>%%：匹配百分号本身。<br>output args：输出变量，用于存储从文件中读取的数据。<br>返回值<br>返回成功读取的字段数量。<br>如果文件结束或发生错误，返回-1。</p><p>代码例子：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">fd = <span class="built_in">$fopen</span>(<span class="string">&quot;file.sv&quot;</span>,<span class="string">&quot;r&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> (fd == <span class="number">0</span>) <span class="keyword">begin</span> <span class="comment">//xxx end   </span></span><br><span class="line"><span class="comment">////循环读取文件的每一行</span></span><br><span class="line"><span class="comment">//while (!$feof(fd)) begin // $feof(fd) 检查是否到达文件末尾</span></span><br><span class="line"><span class="comment">//    if ($fgets(line, fd)) begin // $fgets 读取一行内容</span></span><br><span class="line"><span class="comment">//        $display(&quot;Line: %s&quot;, line);</span></span><br><span class="line"><span class="comment">//    end else begin</span></span><br><span class="line"><span class="comment">//        $display(&quot;Error reading file.&quot;);</span></span><br><span class="line"><span class="comment">//    end</span></span><br><span class="line"><span class="comment">//end</span></span><br><span class="line"><span class="keyword">while</span> (!<span class="built_in">$feof</span>(fd)) <span class="keyword">begin</span> <span class="comment">// $feof(fd) 检查是否到达文件末尾</span></span><br><span class="line">    result = <span class="built_in">$fscanf</span>(fd, <span class="string">&quot;%s&quot;</span>, str);</span><br><span class="line">    <span class="built_in">$display</span>(<span class="string">&quot;str:%s&quot;</span>,str);</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="built_in">$fclose</span>(fd);     <span class="comment">// 关闭文件</span></span><br></pre></td></tr></table></figure><p>30、参数化类<br>通用的类可以在例化的时候修改数组大小和数据类型等<br>常用方式1：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> packet <span class="variable">#(int size = 1)</span>;</span><br><span class="line"><span class="keyword">bit</span>[size-<span class="number">1</span>:<span class="number">0</span>] <span class="keyword">var</span>;</span><br><span class="line">………</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">packet <span class="variable">#(.size(16))</span> p1;  <span class="comment">//var为16bit变量</span></span><br><span class="line">packet <span class="variable">#(16)</span> p2;<span class="comment">//var为16bit变量</span></span><br></pre></td></tr></table></figure><p>常用方式2：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> packet <span class="variable">#(type T=int)</span>;</span><br><span class="line">T t;</span><br><span class="line">……..</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">packet<span class="variable">#(bit[3:0])</span> p1;<span class="comment">//T的类型为bit[3:0]</span></span><br><span class="line">packet<span class="variable">#(.T(bit[3:0]))</span> p2;<span class="comment">//T的类型为bit[3:0]</span></span><br></pre></td></tr></table></figure><p>常用方式3：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> packet_t<span class="variable">#(type A) extends packet#(bit[7:0])</span>;</span><br><span class="line">A a;</span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>packet_t子类使用bit[7:0]扩展了基类packet，本身也是一个参数化的子类。</p><p>31、set_drain_time使用<br>作用：使phase在drop_objection后，再执行一段设置的时间。一个phase对应一个drain_time，并不是所有的phase共享一个drain_time。</p><p>使用方法：phase.phase_done.set_drain_time(this, time);</p><h1 id="篇外1：SVA-断言"><a href="#篇外1：SVA-断言" class="headerlink" title="篇外1：SVA 断言"></a>篇外1：SVA 断言</h1><p>断言是对设计行为属性的描述。在仿真过程中，如果一个被检查的属性与预期不符，那么断言失败。SVA 常见的使用场景有：接口时序规则类检测（如 APB&#x2F;AHB 等时序关系）、特定规则类检查（如 soc 和 eoc 之间 vld 必须为高）、延时类检查（如向 BMU 申请地址后必须 3 拍返回地址）、白盒验证（验证设计意图时）等。</p><p>SVA 语法主要分为五个结构层次：</p><ul><li>最底层：布尔表达式</li><li>第二层：序列（sequence），可包含操作符（如 <code>##</code> 时隙延迟、重复操作符、序列操作符等）；序列是封装格式，可在不同地方复用</li><li>第三层：属性（property），重要的封装方式，可封装 sequence，内部可定义蕴涵操作符（<code>|-&gt;</code>、<code>|=&gt;</code>）</li><li>第四层：断言指示层，采用 assert 对特定属性&#x2F;序列做行为检查，或采用 cover 做覆盖率统计</li><li>第五层：断言的最后封装，可通过 module&#x2F;program&#x2F;interface 封装</li></ul><p>断言的建立过程与格式：</p><p>断言的三种定义：</p><ul><li>断言成功：满足断言条件，并得到期望结果</li><li>断言失败：满足断言条件，但未得到期望结果</li><li>空成功：断言条件始终不满足，断言未触发（伪成功）</li></ul><h2 id="1-交叠蕴含-非交叠蕴含"><a href="#1-交叠蕴含-非交叠蕴含" class="headerlink" title="1 交叠蕴含 &#x2F; 非交叠蕴含"></a>1 交叠蕴含 &#x2F; 非交叠蕴含</h2><ul><li>交叠蕴含 <code>|-&gt;</code>：起因序列与结果序列处于同一时钟周期（类似 if…then）</li><li>非交叠蕴含 <code>|=&gt;</code>：结果序列处于起因序列的下一个时钟周期（类似 if…next then）</li></ul><p>蕴含操作符只能用于属性定义中，不能用于序列中。</p><p>蕴含操作符（仅当if满足时，才执行then，if不满足，则“空成功”）<br>交叠蕴含“|-&gt;”：表示起因序列与结果序列处于同一时钟周期，相当于if…..then…</p><p>非交叠蕴含“|&#x3D;&gt;”：表示结果序列处于起因序列的下一个时钟周期，相当于if….下一个时钟周期then….。</p><h2 id="2-sequence-序列"><a href="#2-sequence-序列" class="headerlink" title="2 sequence 序列"></a>2 sequence 序列</h2><p>序列是描述一种信号时序关系的基本语句，表示一些事情先后发生顺序，大多数序列用##运算描述符。<br>格式：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">sequence</span> name_s;</span><br><span class="line">  &lt;test expression&gt;;</span><br><span class="line"><span class="keyword">endsequence</span></span><br></pre></td></tr></table></figure><h2 id="3-时隙延时运算符"><a href="#3-时隙延时运算符" class="headerlink" title="3 ## 时隙延时运算符"></a>3 ## 时隙延时运算符</h2><p>图一表示，A&#x3D;1时，继续检查，2个clock后，B也为1。同理，图2和图3也类似。<br>eg：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">property</span> prty;</span><br><span class="line">@(<span class="keyword">posedge</span> clk) a |-&gt; ##[<span class="number">1</span>:<span class="number">3</span>] b;</span><br><span class="line"><span class="keyword">endproperty</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">property</span> prty;</span><br><span class="line">@(<span class="keyword">posedge</span> clk) a ##[<span class="number">2</span>:<span class="number">3</span>] b;</span><br><span class="line"><span class="keyword">endproperty</span></span><br></pre></td></tr></table></figure><p>注意：此时A执行，过##clk后，B再执行。</p><h2 id="4-重复运算符"><a href="#4-重复运算符" class="headerlink" title="4 重复运算符"></a>4 重复运算符</h2><ul><li><code>[*n]</code>：连续重复 n 次</li><li><code>[*m:n]</code>：连续重复 m 到 n 次（最少 m 次，最多 n 次）</li><li><code>[=n]</code>：非连续（无所谓跟随）重复操作；<code>data [=8] data</code> 表示 data 被采样为真 8 次，期间可以不相邻</li><li><code>[-&gt;n]</code>：非连续跟随操作符；<code>data [-&gt;4] data</code> 表示 data 被采样为真 4 次（可连续或间断），后续表达式在第 4 次采样后马上生效</li></ul><h2 id="5-disable-iff"><a href="#5-disable-iff" class="headerlink" title="5 disable iff"></a>5 disable iff</h2><p>disable iff后面的条件为停止检查的判断条件。<br>Eg：property p;</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">@(<span class="keyword">posedge</span> clk)</span><br><span class="line"><span class="keyword">disable</span> <span class="keyword">iff</span>(reset) a |-&gt; ##<span class="number">1</span> b[-&gt;<span class="number">3</span>] ##<span class="number">1</span> c;</span><br><span class="line"><span class="keyword">endproperty</span></span><br><span class="line">a:<span class="keyword">assert</span> <span class="keyword">property</span>(p);</span><br><span class="line">上面在reset为低时会检查a |-&gt; ##<span class="number">1</span> b[-&gt;<span class="number">3</span>] ##<span class="number">1</span> c，直到reset为高，停止检查。</span><br></pre></td></tr></table></figure><p>（6）常见函数</p><h2 id="6-常见函数"><a href="#6-常见函数" class="headerlink" title="6 常见函数"></a>6 常见函数</h2><table><thead><tr><th>Function</th><th>Description</th><th>Example</th></tr></thead><tbody><tr><td>$onehot</td><td>只有 1bit 为 1</td><td><code>assert property(@(posedge clk) $onehot0(&#123;A,B,C&#125;));</code> 同一时刻最多只有 1bit 为高</td></tr><tr><td>$onehot0</td><td>只有 1bit 为 1 或全为 0</td><td></td></tr><tr><td>$countones</td><td>返回 1 的个数</td><td><code>assert property(@(posedge clk) $countones(A&amp;B) &lt;= 4);</code></td></tr><tr><td>$countzeros</td><td>返回 0 的个数</td><td></td></tr><tr><td>$stable</td><td>判断信号稳定不变</td><td><code>assert property(@(posedge clk) $stable(a));</code></td></tr><tr><td>$past</td><td>前时刻的值</td><td><code>$past(a, n)</code>：a 的前 n 个时钟周期的值</td></tr><tr><td>$rose</td><td>上升沿</td><td>&#96;assert property(@(posedge clk) req</td></tr><tr><td>$fell</td><td>下降沿</td><td>&#96;assert property(@(posedge clk) $fell(done)</td></tr></tbody></table><p>$past 使用：（默认情况下，提供信号在前一个时钟周期的值）</p><p>基本语法：<code>$past(signal_name, number_of_clock_cycles)</code></p><p>例子：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">property</span> ab_high_two_clk_cd_high;</span><br><span class="line">@(<span class="keyword">posedge</span> clk)</span><br><span class="line">(c &amp;&amp; d) |-&gt; <span class="built_in">$past</span>((a &amp;&amp; b), <span class="number">2</span>);</span><br><span class="line"><span class="keyword">endproperty</span></span><br><span class="line"><span class="keyword">assert</span> <span class="keyword">property</span>(ab_high_two_clk_cd_high);</span><br></pre></td></tr></table></figure><p>如果表达式 (c &amp;&amp; d) 为真，那么两个周期前，表达式 (a &amp;&amp; b) 为真。</p><h2 id="7-and-or-用法"><a href="#7-and-or-用法" class="headerlink" title="7 and &#x2F; or 用法"></a>7 and &#x2F; or 用法</h2><p>二进制运算符“and”可以用来组合两个序列。当两个序列都成功时整个属性才成功。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">property</span> proty_and;</span><br><span class="line">@(<span class="keyword">posedge</span> clk) seq1 <span class="keyword">and</span> seq2;</span><br><span class="line"><span class="keyword">endproperty</span></span><br></pre></td></tr></table></figure><p>二进制运算符“or”可以用来组合两个序列。只要其中一个序列成功，整个属性就成功。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">property</span> proty_or;</span><br><span class="line">@(<span class="keyword">posedge</span> clk) seq1 <span class="keyword">or</span> seq2;</span><br><span class="line"><span class="keyword">endproperty</span></span><br></pre></td></tr></table></figure><h2 id="8-SVA-的写法"><a href="#8-SVA-的写法" class="headerlink" title="8 SVA 的写法"></a>8 SVA 的写法</h2><p>两种方法：</p><h3 id="8-1-方法-1：SVA-binding"><a href="#8-1-方法-1：SVA-binding" class="headerlink" title="8.1 方法 1：SVA + binding"></a>8.1 方法 1：SVA + binding</h3><p>需要两个文件。</p><p>demo.sva 示例：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> demo(</span><br><span class="line">  <span class="keyword">input</span> <span class="keyword">wire</span> signal1,</span><br><span class="line">  <span class="keyword">input</span> <span class="keyword">wire</span> signal2</span><br><span class="line">);</span><br><span class="line"><span class="keyword">endmodule</span></span><br></pre></td></tr></table></figure><p>binding.sva 示例：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bind</span> tb_top<span class="variable">.DUT</span> demo demo_inst(</span><br><span class="line">  <span class="variable">.signal1</span>(tb_top<span class="variable">.DUT</span><span class="variable">.signal1</span>),</span><br><span class="line">  <span class="variable">.signal2</span>(tb_top<span class="variable">.DUT</span><span class="variable">.signal2</span>)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>最后将这两个文件 &#96;include 到 tb_top.sv 中。注意：写在 tb_top 的 module 外。</p><h3 id="8-2-方法-2：仅-SVA（不使用-binding）"><a href="#8-2-方法-2：仅-SVA（不使用-binding）" class="headerlink" title="8.2 方法 2：仅 SVA（不使用 binding）"></a>8.2 方法 2：仅 SVA（不使用 binding）</h3><p>只写 demo.sva，不需要 binding 文件。demo.sva 中先声明变量，再通过 assign 连接 DUT 信号。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">logic</span> signal1;</span><br><span class="line"><span class="keyword">assign</span> signal1 = tb_top<span class="variable">.DUT</span><span class="variable">.signal1</span>;</span><br></pre></td></tr></table></figure><p>最后将此文件 &#96;include 到 tb_top.sv 中。注意：写在 tb_top 的 module 内。</p><p>方法2相当于将SVA检验器定义在模块（module）中。<br>方法1相当于将SVA检验器与模块、模块的实例或者一个模块的多个实例进行bind绑定。</p><p>显示断言成功的方法：</p><p>第一步：FSDB 查看 SVA 成功与否（FSDB 中会显示断言成功&#x2F;失败）：</p><p>build_cfg 配置：</p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">COMP_OPT += -assert enable_diag</span><br><span class="line">SIM_OPT  += +fsdb+sva_success</span><br></pre></td></tr></table></figure><p>第二步：sim.do 中：</p><figure class="highlight tcl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fsdbDumpSVA <span class="number">0</span> <span class="string">&quot;xxx_tb_top&quot;</span></span><br></pre></td></tr></table></figure><p>断言成功的地方显示绿色向上箭头，失败的地方显示红色向下箭头。</p><hr><h2 id="9-常见写法示例"><a href="#9-常见写法示例" class="headerlink" title="9 常见写法示例"></a>9 常见写法示例</h2><h3 id="9-1-属性块与-check-分开"><a href="#9-1-属性块与-check-分开" class="headerlink" title="9.1 属性块与 check 分开"></a>9.1 属性块与 check 分开</h3><p>并发断言使用关键字 property…endproperty 描述事件。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">property</span> p_name;</span><br><span class="line">  @(<span class="keyword">posedge</span> clk)</span><br><span class="line">  <span class="keyword">disable</span> <span class="keyword">iff</span>(!rstn)</span><br><span class="line">  !(a &amp;&amp; b);</span><br><span class="line"><span class="keyword">endproperty</span></span><br><span class="line"></span><br><span class="line">s_name: <span class="keyword">assert</span> <span class="keyword">property</span>(p_name)</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">    `uvm_error(<span class="string">&quot;xxxx&quot;</span>);</span><br><span class="line">  <span class="keyword">end</span></span><br></pre></td></tr></table></figure><h3 id="9-2-属性块与-check-合并"><a href="#9-2-属性块与-check-合并" class="headerlink" title="9.2 属性块与 check 合并"></a>9.2 属性块与 check 合并</h3><p>略。</p><h3 id="9-3-generate…for-生成式写法"><a href="#9-3-generate…for-生成式写法" class="headerlink" title="9.3 generate…for 生成式写法"></a>9.3 generate…for 生成式写法</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">property</span> pro_inst_name(<span class="keyword">int</span> a, b);</span><br><span class="line">  @(<span class="keyword">posedge</span> clk) <span class="keyword">disable</span> <span class="keyword">iff</span>(!srst_n) xxxxxxxx;</span><br><span class="line"><span class="keyword">endproperty</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">generate</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">genvar</span> i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++) <span class="keyword">begin</span> : gen_inst_name</span><br><span class="line">    ast_inst_name: <span class="keyword">assert</span> <span class="keyword">property</span>(pro_inst_name(a, b))</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">        `uvm_error(<span class="string">&quot;xxxxxxxx&quot;</span>)</span><br><span class="line">      <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endgenerate</span></span><br></pre></td></tr></table></figure><h3 id="9-4-function-的使用"><a href="#9-4-function-的使用" class="headerlink" title="9.4 function 的使用"></a>9.4 function 的使用</h3><p>可以在属性块property中使用function来实现一些复杂的操作，具体是将function的返回值（可以是return返回，也可以是函数名返回值），如下例子：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> fun_n(<span class="keyword">logic</span> a, b);</span><br><span class="line">  fun_n = xxx;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">property</span> pro_inst;</span><br><span class="line">  @(<span class="keyword">posedge</span> clk) <span class="keyword">disable</span> <span class="keyword">iff</span>(!srst_n) fun_n |-&gt; xxxx;</span><br><span class="line"><span class="keyword">endproperty</span></span><br></pre></td></tr></table></figure><h2 id="10-bind-绑定"><a href="#10-bind-绑定" class="headerlink" title="10 bind 绑定"></a>10 bind 绑定</h2><p>SVA检验器通过关键字bind可以与设计中的任何模块（module）或着实例（instance）绑定。实现绑定时，使用的是设计中的实际信号，语法如下：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bind</span> &lt;module_name <span class="keyword">or</span> instance_name&gt; &lt;checker_name&gt; &lt;checker_instance_name&gt;</span><br><span class="line">&lt;design_signal&gt;</span><br></pre></td></tr></table></figure><h2 id="11-cover-语法"><a href="#11-cover-语法" class="headerlink" title="11 cover 语法"></a>11 cover 语法</h2><p>cover可以用来获得属性property的执行情况，即覆盖属性（cover property），SVA提供的关键词。</p><h2 id="12-其它"><a href="#12-其它" class="headerlink" title="12 其它"></a>12 其它</h2><h3 id="12-1-SVA-开关"><a href="#12-1-SVA-开关" class="headerlink" title="12.1 SVA 开关"></a>12.1 SVA 开关</h3><p>验证环境中控制assertion开关<br>（1）使用define来控制。方法是：使用宏定义的方法，用宏包裹assert property来达到隔离的目的。<br>（2）使用向量结合disable iff()来控制。方法是：在top上构造一个信号，并在testcase中用uvm_hdl_force(path,value)进行赋值，进而满足disable assertion的条件，达到某个case打开断言检查的目的。<br>29、mailbox信箱<br>mailbox是SV中原生FIFO，在线程之间做数据通信或数据缓存时可考虑使用此类型。<br>（1）mailbox和队列queue有相近之处。<br>（2）mailbox是一个对象，必须使用new()来例化，例化时可选参数size来限定存储的最大数量。如果size是0或者未指定，则默认无限大。<br>（3）使用put()可以把数据放入mailbox，使用get()可以从mailbox移除数据。<br>（4）如果信箱为满，则put()会阻塞；如果信箱为空，则get()会阻塞。<br>（5）peek任务可以获取对信箱里数据的拷贝而不移除它。<br>（6）信箱未指明类型时，可放入任何混合类型的数据。（尽量只放入同一类型）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">使用方法：mailbox <span class="variable">#(类型)</span> mbx;    <span class="comment">//相当于一个队列</span></span><br><span class="line">mbx<span class="variable">.put</span>(value)是将数据放入mailbox中，若为满则语句一直阻塞。</span><br><span class="line">mbx<span class="variable">.try_put</span>(value)是将数据放入mailbox中，若为满语句不会阻塞。</span><br><span class="line">mbx<span class="variable">.get</span>(value)是将数据取出，若为空则语句一直阻塞。</span><br><span class="line">mbx<span class="variable">.try_get</span>(value)是将数据取出，若为空语句不会阻塞。</span><br><span class="line">mbx<span class="variable">.num</span>();可以获取信箱当前存储的数据个数。</span><br></pre></td></tr></table></figure><p>30、#延时<br>（1）#0延时用于控制同一时刻运行的两个线程的执行先后顺序，无#0的先执行，eg：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fork</span> </span><br><span class="line">task1() #<span class="number">0</span> <span class="keyword">endtask</span> </span><br><span class="line">task2() <span class="keyword">endtask</span> </span><br><span class="line"><span class="keyword">join</span> <span class="comment">//则同一时刻，task2先执行，task1后执行。</span></span><br></pre></td></tr></table></figure><p>（2）#10为延迟10个时间单位。<br>（3）##与时钟块使用，##10 if.cb.a&lt;&#x3D;1表示延时10个时钟周期且a赋值1。</p><p>31、静态变量&amp;静态方法<br>静态变量和静态方法可以在类没有实例时直接调用。<br>（1）静态变量static variable<br>普通的实例类属性，每个变量都有单独的内存空间，相互独立。而若使用关键字static修饰变量，则类的所有实例都共享此静态变量。eg：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> A; <span class="keyword">static</span> value; <span class="keyword">endclass</span></span><br><span class="line"><span class="keyword">class</span> B; A a1; <span class="keyword">endclass</span>;<span class="comment">//类B中声明定义了类A</span></span><br><span class="line"><span class="keyword">class</span> C; A a2; <span class="keyword">endclass</span>;<span class="comment">//类C中声明定义了类A</span></span><br></pre></td></tr></table></figure><p>则A、B和C共享静态变量value的内存空间。即value变化，被所有A实例共享。</p><p>总结如下：<br>1.与硬件领域例如module，interface不同的是，在class中声明的变量其默认类型为动态变量，即其声明周期在仿真开始后的某时间点开始到某时间点结束。具体来讲，其声明周期开始于对象创建，终于对象销毁。<br>2.如果使用关键字static来声明class内的变量时，则其为静态变量。静态变量的生命开始于编译阶段，贯穿于整个仿真阶段。<br>3.如果在类中声明了静态变量，那么可以直接引用该变量class::var，或者通过例化对象引用object.var。类中的静态变量声明以后，无论例化多少个对象，只可以共享一个同名的静态变量，因此类的静态变量在使用时需要注意共享资源的保护。</p><p>（2）静态方法<br>1.类似于静态变量，在class中定义的方法默认类型是动态方法，而我们也可以通过关键词static修改其类型为静态方法。<br>2.静态方法内可以声明并使用动态变量，但是不能使用类的动态成员变量。原因是因为在调用静态方法时，可能并没有创建具体的对象，也因此没有为动态成员变量开辟空间，因此在静态方法中使用类的动态成员变量时禁止的，可能会造成内存泄漏，但是静态方法可以使用类的静态变量，因为静态方法同静态变量一样在编译阶段就已经为其分配好了内存空间。<br>32、ref参数引用<br>在verilog中，向子程序传递参数时，通常使用复制的方式，而使用ref引用方式可以获取仿真的最佳性能。如果希望子程序不改变参数内容，可以使用const ref类型，此时，编译器会检查参数内容以保证不被修改。<br>ref引用传参（by reference），参数的引用（地址，即共用同一物理地址）被传递给任务&#x2F;函数，内部对参数的修改会影响到调用任务的代码中的变量。如下：</p><p>扩展：若参数传递的是结构体，结构体内有非合并数组，且传递的结构体为结构体数组的某个元素，则会报错。（大概率是结构体的非合并数组，编译器不好地址划分）比如：</p><p>常见问题：<br>使用ref类型时，若有参数缺省方向，则可能出现bug。如下所示：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">task</span> sticky(<span class="keyword">ref</span> <span class="keyword">int</span> array[<span class="number">50</span>], <span class="keyword">int</span> a,b); <span class="comment">//那么a和b都会被编译器认为是ref类型的。</span></span><br></pre></td></tr></table></figure><p>若指明方向，则不会出问题：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">task</span> sticky(<span class="keyword">ref</span> <span class="keyword">int</span> array[<span class="number">50</span>], <span class="keyword">input</span> <span class="keyword">int</span> a,b); <span class="comment">//明确指明方向，不会出问题。</span></span><br></pre></td></tr></table></figure><p>33、timeslot时序区域<br>verilog中，Time slot的simulation regions包含Preponed、Active、Inactive、NBA、Observed、Reactive、Re-Inactive、Re-NBA和Postponed regions。再根据active region set和reactive region set的划分，可以将一个time slot的simulation regions分为五个主要region：Preponed、Active、Observed、Reactive和Postponed。如下图所示：</p><p>Preponed：在一个timeslot内，Prepone region只会执行一次，当仿真时间进入当前timeslot时，它是第一个被执行的region。<br>Active：分为几个小的regions：active，inactive和NBA(nonblocking assignment update) regions。<br>1）Active region进行当前active region set events的评估求值。所有blocking assignments语句在Active region执行。对于nonblocking assignments，RHS的评估求值发生在Active region，而赋值发生在NBA region。<br>2）Inactive region处理完所有active events后。显式的#0延迟控制要求将这个event安排到当前time slot的inactive region进行，以便在下一个inactive到active迭代中恢复process。<br>3）NBA region进行处理完所有inactive events后。Nonblocking assignment（非阻塞赋值的缩写）会在当前或以后仿真时间的NBA region中创建events。<br>Observed：Observed用于触发property expressions(用于concurrent assertions)时对其求值。在property求值后，pass&#x2F;fail的信息将在当前time slot的Reactive region报告出来。<br>Reactive：Reactive包含了Re-active，Re-inactive和Re-NBA regions。<br>1）Re-active进行当前reactive region set的评估求值，并且可以以任何顺序进行处理。Re-active region和active region其实是对偶关系的。只不过active处理design，re-active处理program。<br>2）Re-inactive进行处理完所有re-active events后。Program里显示的#0延迟控制要求将这个event安排到当前timeslot的re-inactive region进行，以便在下一个inactive到active迭代中恢复process。同样的，它也是inactive region的对偶关系。<br>3）Re-NBA进行处理完所有re-inactive events后要。Program里nonblocking assignment会在当前或以后仿真时间的re-NBA region中创建events。<br>Postponed：postponed是当前timeslot的最后1个region。$monitor, $strobe和其它相似的events会安排在这个region执行（注意$display event是在active region和reactive region（如果在program里调用）执行的）。一旦到达postponed region，就不允许在当前time slot中发生新的值更改。在此region内，向任何net或variable进行写入值或在当前region调度任何先前region的event都是非法的。Postponed region PLI events也在这里调度。</p><p>阻塞赋值和非阻塞赋值：<br>1）非阻塞赋值(&lt;&#x3D;)的行为：<br>非阻塞赋值的值计算基于赋值语句执行时的变量值，而不是赋值语句之后变量的变化。<br>非阻塞赋值的效果会在当前时间的末尾生效，但赋值的值在赋值语句执行时就已经确定。<br>2）执行顺序：<br>阻塞赋值(&#x3D;)是立即生效的。<br>非阻塞赋值(&lt;&#x3D;)的值计算发生在赋值语句执行时，但实际赋值操作会被延迟到当前时间的末尾</p><p>9.12补充：两个非阻塞赋值同时给一个变量赋值，那么只会执行最后一个，eg:<br>a &lt;&#x3D; b;<br>a &lt;&#x3D; c;<br>那么之后执行最后的a &lt;&#x3D; c;</p><p>编译选项：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">COMP_OPT += +fsdb+region</span><br><span class="line">SIM_OPT += +fsdb+delta</span><br></pre></td></tr></table></figure><p>第一个编译选项是在波形上打开timeslot区域，第二个运行选项是打开可观测信号跳变的具体时刻。<br>其它<br>（1）在constraint中对数组和队列进行约束时，对数组和队列的size大小进行约束的语句不能放在foreach下。<br>（2）constraint对多个数组和队列随机化，可以使用其它随机化的数组和队列的一些“信息“，比如长度等来约束自身。因为constraint是并行执行的。<br>（3）在VerilogSystem中2^8-1并不是2的8次方减1，而是2与8-1的异或。（重点）<br>（4）在数组array和队列queue通过.sum来进行求和的过程中，即array.sum和queue.sum的过程中，要注意数据位宽，不然可能出现溢出的情况。（重点）<br>eg：bit[8:0] a[$];</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">a = &#123;xxx,xxx,xxx,xxx…..&#125;;</span><br></pre></td></tr></table></figure><p>a.sum的求和大于2的9次方减1就会出现溢出。<br>（5）函数和任务中，变量的定义放在函数和任务内的前面几行，不然会报错。<br>（6）一个sv文件只能被include到一个文件中，但是可以用pkg将其它pkg导进去。<br>（7）带rand的变量，在使用了randomize后，其值会在规定范围内随机变化。<br>（8）如果对class的变量进行赋初值，在例化的时候，其值保持初值，可以在例化后，对其进行赋新值，得到的则是新值。<br>（9）*表示通配符，匹配任意字段。<br>（10）macro：宏<br>（11）在SV语法中，通常都是用begin….end来表示一个语句块的，在约束中使用{….}来表示一个语句块。<br>（12）一个结构体变量a，里面的元素有数组，联合体等变量，如果a定义在class里面，那么在task使用时，将b传递给a，那么可能数据不能全部传递给a；如果a定义在task里面，同时在task内将b传递给a，那么是可以将b给a的。（碰到的奇怪情况）<br>（13）UVM验证环境中尽量使用同一中赋值，阻塞&#x3D;和非阻塞&lt;&#x3D;选择其一，使用阻塞的话，那么fork….join里面的两个task的执行顺序是先上后下，如果使用非阻塞的话，那么这两个task是并行执行的。（前提是这两个task是用一个时钟）。注意注意（20220320：有时候碰到复杂的情况，可能并不会先上后下的顺序执行，具体问题需要具体分析，一般同时刻自上而下执行）。<br>以后在搭环境的时候，可以往每个task的里加入打印（就打印task&#x2F;function名），以此来确定哪个task先执行。另外，可以在下降沿产生某信号，而在上升沿使用此信号。<br>task所处的位置可能会“骗人”，但是时间是不会骗人的。<br>（14）if((a&#x3D;1))表示判断为真，编译时会显示warning（显示为执行了赋值操作），但是不会报错。因此，只要if((a&#x3D;x))，其中x为非0，则判断为真。<br>（15）在SV中，使用value[a:0]和value[0+:a]进行截位（a为变量），即动态的截位，SV编译器会报错，因此可以使用for(int i&#x3D;0; i&lt;a; i++)的方式对每bit进行判断后再截位，另外也可&amp;动态宽度的1来进行截位，即value &amp; {a{1’b1}}<br>（16）在interface上定义一个数组类型的变量，如logic[n:m] singlea[q]; 通过后门访问DUT的信号后（assign singlea &#x3D; dutb）。注意singlea的取值顺序为0,1,2…..q-1，即从小到大，若dutb定义的顺序是dutb[q-1:0]，那么顺序相反，即singlea[0:q-1] &#x3D;&#x3D; dutb[q-1:0]。<br>（17）$display()可以直接打印数字，如$display(123987)会打印出123987，但是$display(abcfcg)则会报错。另外，$display(que)可以直接打印队列。<br>（18）function函数或者task任务，变量的定义需要放置最前面，否则会报错<br>（19）多个进程同时调用一个任务时，这个任务的资源是共享的（即任务内的值改变，可以影响到其它进程的任务，需要注意）。比如FNOC的RM，up、dn、lt和rt都调用side_in的task。<br>（20）使用位或|时，若是对数组使用位或会报错，如bit[1:0] arry[3]，使用|arry则会报错。<br>（21）tb.flist中要包含TB编译的各文件pkg或（.sv&#x2F;.svh等），另外pkg中需要注意包含所需组件的所有要编译文件。</p><h1 id="篇外2：功能覆盖率"><a href="#篇外2：功能覆盖率" class="headerlink" title="篇外2：功能覆盖率"></a>篇外2：功能覆盖率</h1><p>功能覆盖率的两个重要部分是采样的数据和数据被采样的时刻：</p><ul><li>采样时刻：使用 wait&#x2F;@ 阻塞赋值；或使用 sample() 方法</li><li>采样数据：建立 covergroup 与 bins。covergroup 可定义在类&#x2F;程序块&#x2F;模块中；使用前必须实例化（通常在类的 new() 中实例化）</li></ul><p>covergroup 常规写法：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> cov_name();</span><br><span class="line">  cp_name: <span class="keyword">coverpoint</span> signal_name &#123;</span><br><span class="line">    <span class="keyword">bins</span> bins_name0 = &#123;[a:b]&#125;;</span><br><span class="line">    <span class="keyword">bins</span> bins_name1 = &#123;c&#125;;</span><br><span class="line">    xx</span><br><span class="line">    xxx</span><br><span class="line">    xxx</span><br><span class="line">  &#125;</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure><p>自己的理解：1、首先建覆盖组covergroup cov_name…..endgroup，2、然后需要对覆盖组进行声明与例化new()，3、同时需要确定wait或@或sample对覆盖点的signal_name进行采样，最后使用bins来建仓，收集覆盖率。4、包含覆盖组的类需要被例化到环境中，一般是ENV中。</p><p>注意：1、一个covergroup覆盖组可以包含一个或多个coverpoint覆盖点；2、coverpoint内不能写begin……..end，否则会报错。3、可以使用options.auto_bin_max &#x3D; num;来定义默认建仓个数，默认64</p><p>（1）iff关键字<br>iff构造中的表达式指定了一个可选的条件，该条件可以禁用覆盖点的覆盖。如果iff(表达式)在采样点计算为false，则忽略覆盖点。</p><p>（2）default关键字<br>default关键字，定义了一个不与任何已定义值仓相关联的仓。默认仓捕获覆盖点的值，不属于任何已定义的仓。<br>比如：bins a0 &#x3D; default;&#x2F;&#x2F;表示a0仓代表剩余的所有值。<br>（3）bins关键字</p><p>注意：bins a &#x3D; {[num0:num1]};表示的是a的取值范围来自num0～num1，满足则覆盖。<br>bins a[] &#x3D; {[num0:num1]};表示的是a有num1-num0+1个仓，使用时需要注意num0与num1的先后顺序，小的写前面，其覆盖的数为num0～num1。</p><p>（5）翻转覆盖<br>bins bins_name[] &#x3D; (a&#x3D;&gt;b), (c&#x3D;&gt;d);的作用（翻转覆盖率）<br>答：其中a将被自动划分为两个仓，分别记录a&#x3D;&gt;b和c&#x3D;&gt;d值变化状态的仓。其中：<br>1、a&#x3D;&gt;b：这表示一个状态从a转换到b的值变化过程。<br>2、c&#x3D;&gt;d：这表示一个状态从c转换到d的值变化过程。<br>扩展：1、可以用于状态机的覆盖；2、可指定连续的翻转次数，即值保持的周期个数。<br>3、&#x3D;&gt;表示连续（a&#x3D;&gt;b，表示a跳转到b的过程中不能出现其它值），-&gt;表示离散（a-&gt;b，表示a跳转到b的过程中可以出现其它值）</p><p>注意：此处bins不需要加{}来包裹</p><p>解释：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bins</span> b4 = (<span class="number">0</span>[*<span class="number">15</span>]);</span><br><span class="line"><span class="keyword">illegal_bins</span> b5 = (<span class="number">1</span>[*<span class="number">2</span>]);</span><br></pre></td></tr></table></figure><p>表示0出现15次；表示1连续出现两次则非法。<br>（7）不合法的仓<br>illegal_bins的作用是对非法的数值进行检测，用法是illegal_bins bins_name &#x3D; {[a,b]};&#x2F;&#x2F;表示的意思是需要覆盖的值的取值范围不应该在a与b的范围内。</p><p>（8）with约束<br>类似于附加约束，包含再bin中，使最终bins的取值为满足给定表达式的值。<br>比如：<br>bins mod[] &#x3D; {[0:255]} with (item % 3 &#x3D;&#x3D; 0)&#x2F;&#x2F;表示此bins定义为0～255中能被3整除的所有值。<br>（9）忽略数值<br>忽略一些不关心的信号取值，ignore_bins不会用于计算覆盖率。<br>写法：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ignore_bins</span> ign_n1= &#123;a,b,c&#125;;</span><br><span class="line"><span class="keyword">ignore_bins</span> ign_n2=(a=&gt;b=&gt;c);</span><br></pre></td></tr></table></figure><p>不会覆盖a,b,c的值；不会覆盖a翻转到b再翻转到c的值。</p><p>注意：ignore_bins关键字应该与具体的交叉项一起使用，而不是与default关键字一起使用。<br>（4）交叉覆盖<br>对于多个覆盖点组合的覆盖情况，有两种方法：<br>1、一种方法是预处理后，即先判断组合情况后，再建仓进行覆盖测试。<br>2、另外一种则是使用交叉覆盖进行测试。<br>以下为交叉覆盖：<br>交叉覆盖是在覆盖点或变量之间指定的，必须先指定覆盖点，然后才能定义覆盖点之间的交叉覆盖。如果想记录在某一时刻，多个变量之间值的组合情况， 需要使用交叉(cross)覆盖率。</p><p>解释：上述的交叉覆盖建仓16<em>16个，即a的仓数</em>b的仓数</p><p>在交叉覆盖中，除了使用上面自动创建的bins之外，还可以用户自定义交叉bins，这就用到关键字binsof和intersect，如下图。<br>注意，binsof使用的是小括号() ，而intersect 指定的是一个范围 ，所以使用大括号！</p><p>解释：binsof()是取coverpoint的bins；intersect是指定取值或范围；type_option.weight表示不关注此coverpoint覆盖点。</p><p>总结：（1）先在covergroup中创建coverpoint覆盖点（名字需唯一）；（2）对多个coverpoint进行cross操作，即组合情况的覆盖</p><p>（6）covergroup传参<br>covergroup cov_name(xxx)…..endgroup使用new()例化时，可以在()内传参。<br>可用于下面场景：<br>测试接口变量每1bit翻转<br>答：可以声明一个covergroup cov_name(xxx)……endgroup类型的数组，如cov_name cov_name_inst[10]，然后循环使用new()例化cov_name_inst 10次，通过new(参数)传参来测试每bit的翻转情况。</p><p>option.per_instance的作用？？？<br>sample()的作用？？？<br>番外3：覆盖率分析<br>（1）批量exclude相同代码<br>1、使用exclude屏蔽代码后，在file选项选择save exclusions not saved&#x2F;save all exclusions保存文件为xxx.el。<br>2、打开xxx.el文件，修改屏蔽内容后（相似代码exclude），可在下次打开覆盖率文件后，load exclude后，可看到相似代码被批量exclude了。</p><p>save exclusions not saved&#x2F;save all exclusions的作用：<br>save exclusions not saved的作用是保存之前未save的exclusion文件，及exclude到recalculation这段时间所waive的部分。<br>save all exclusions：保存所有exclusion的文件。<br>番外4：gvim&#x2F;linux使用<br>1、GVIM常用操作<br>（1）指令模式（命令模式）：<br>x：删除某个字符<br>（2）编辑模式<br>i、o、a：进入编辑模式<br>（3）命令模式<br>esc：退出到命令模式<br>:w：保存文本<br>:q：退出gvim<br>:wq：保存并退出<br>（4）命令模式下，:&#x2F;string + 回车：可以显示要查找的string，另外按n或者N可以搜索下一个string。set hlsearch：查找的string全部高亮显示。noh：即可取消的高亮显示。<br>（5）在命令模式下，按gf（go file）可以跳转到另一个.sv的文件里。同时使用Ctrl+^可以回到原文件中。<br>（6）在命令模式下，:sp是水平分屏，:vsp是垂直分屏，:vs是垂直分屏。<br>（5）gvimdiff 文件1 文件2，可以打开GVIM，然后高亮对比两个文件的不同。<br>（7）GVIM中的替换命令：1）:%s&#x2F;xxx&#x2F;yyy&#x2F;g；2）:a,bs&#x2F;xxx&#x2F;yyy&#x2F;g；（a行到b行的替换）<br>步骤进行操作：</p><ol><li>打开该文件并进入 <code>gvim</code> 的编辑模式（例如，可以使用命令 <code>gvim example.txt</code>）。</li><li>按下 <code>:</code> 键，进入命令模式。</li><li>在命令模式下输入 <code>:%s/fox/cat/g</code>，其中，<code>%</code> 表示对整个文件的所有行进行替换，<code>s</code> 表示替换命令，<code>/xxx/yyy/g</code> 表示使用字符串 <code>xxx</code> 替换字符串 <code>yyy</code> 并且全局替换。<code>g</code> 则是一个可选参数，表示全局替换，即会替换所有符合条件的字符串</li><li>按下Enter键，<code>gvim</code> 将会执行替换操作。此时，所有的字符串 <code>xxx</code> 都被替换成了字符串 <code>yyy</code>。<br>（8）在GVIM中，使用shift+&#96;可以将字符串的大小写发生转换。<br>（9）GVIM中复制多行，首先将光标停在准备复制的初始行，按v键，之后滑动滚轮，或者最右边的滑条，之后选择复制，也可以按y键复制。<br>（10）GVIM在行首或行尾添加或删除内容：<br>1、在行首添加相同的内容：:%s&#x2F;^&#x2F;添加内容&#x2F;g<br>2、在行尾添加相同的内容：:%s&#x2F;$&#x2F;添加内容&#x2F;g<br>（11）在gvim中，可以使用“shift+3”来标记变量高亮，也可以使用“shift+鼠标单击”来标记变量高亮，后者标记高亮不会跳转。<br>（12）在GVIM中，使用“shift+r”来刷新目录。<br>（13）在命令模式，鼠标左击，然后再在某处鼠标右击，可以赋值左击和右击之间的文本。<br>（14）在gvim的文本中，使用gg可以跳转至文本头，使用G，即shift+g可跳转文本尾，使用0可以跳转行的头，使用$，即shift+4可跳转至行的尾。<br>（15）统计GVIM中某个字符串的个数，可以在命令模式下，输入:%s&#x2F;your_string&#x2F;&#x2F;gn，其中%s为替换命令，g表示全局搜索，n表示只统计匹配到的次数而不进行实际替换。按回车后即可看到统计结果。<br>（16）使用“Ctrl+v”进入块操作，然后按上、下、左、右来选择块，之后使用“shift+i”来插入要输入的内容，再按Esc，则选中的块将全部插入相同的内容。<br>（17）使用“Ctrl+v”进入块操作，然后按上、下、左、右来选择块，之后按“y”来复制选中的块，之后同样使用“Ctrl+v”进入块操作，按上、下、左、右来选择块，再按“p”将选中的块粘贴，则完成了块的复制与粘贴。<br>（18）使用“Ctrl+v”进入块操作，使用shift+u可以将小写字母转换为大写字母。<br>（19）gvim中的命令模式下，按下Ctrl+v，再按Enter，字符^M表示换行。<br>（20）如果要删除a行到b行的所有数据，可以在命令行下使用:a,bd来删除a行到b行。<br>（21）bcompare a b的撤销功能是ctrl+z键，或者点击edit后，选择undo copy to side<br>（22）按esc进入命令模式，然后输入nyy，则可以复制当前光标下n行，然后到需要复制的文本中，输入p，则可以粘贴n行到该文本下。<br>2、Linux常用命令<br>（1）setenv命令<br>Linux中setenv命令用于查询或显示环境变量，setenv为c shell中查询或设置环境变量的指令。<br>语法：setenv [变量名称] [变量值]<br>显示环境变量：echo $变量名称<br>（2）$钱号<br>变量替换的代表符号，取值符号。例子：setenv vrs&#x3D;123，则echo $vrs，那么vrs&#x3D;123。<br>（3）在linux的命令行，点击鼠标的滑轮可以将已经复制的命令直接粘贴到命令行，相当于右击粘贴操作。<br>（4）diff命令<br>比较两个文件的差异，命令格式：diff [参数] [文件1或目录1] [文件2或目录2]。diff命令能比较单个文件或者目录内容。如果指定比较的是文件，则只有当输入为文本文件时才有效。以逐行的方式，比较文本文件的异同处。如果指定比较的是目录的的时候，diff 命令会比较两个目录下名字相同的文本文件。<br>（5）linux中，“ctrl+a”可回到命令的头，“ctrl+e”可回到命令的尾<br>（6）cd -命令的作用是返回到上一次的路径，比如上一次路径是&#x2F;a&#x2F;b&#x2F;c&#x2F;d，当前路径是1&#x2F;2&#x2F;3&#x2F;4，那么使用cd -后，就可以回到路径&#x2F;a&#x2F;b&#x2F;c&#x2F;d下。<br>（7）becompare 文件1 文件2，这个命令是寻找两个文件的不同，并高亮显示。<br>（8）linux上使用ps -ef | grep xxxx | grep xxxx查找服务器上的进程PID，然后使用kill PID即可清除进程。<br>ps -ef命令用于列出所有正在运行的进程。<br>grep命令用于在输入中搜索指定的字符串。<br>命令管道|用于将管道符左边命令的输出作为管道符右边命令的输入。<br>eg：ps -ef | grep dalao | grep xxx<br>ps -ef查找服务器的所有进程，然后使用grep查找包含dalao的进程，再在筛选下的进程找到xxx的进行。最后使用kill xxx，清除进程。<br>同时可以使用ctrl+v来选择多少行多少列，再按delete来进行删除行与列的操作。</li></ol><p>（9）rm（remove）：删除文件或目录。<br>常用参数：<br>-r：递归删除，目录下的文件也全部删除。<br>-f：force，忽略警告、不存在的文件，强制删除。<br>rm -fr一定要小心使用，避免删除一些重要文件。</p><p>（10）mv（move file）：用于文件或目录的改名和移动存放位置。</p><p>（11）mkdir（make directory）：创建目录。</p><p>（12）cp（copy file）：复制文件或目录<br>常用参数：<br>-r：递归复制，用于目录的复制。</p><p>（13）find：在指定目录下查找文件，重点掌握。<br>find .&#x2F; -name “*.v”：在当前目录及其子目录下所有后缀为.v的文件列出来。<br>find .&#x2F; -ctime n：n天状态发生变化的文件。</p><p>find .&#x2F; -maxdepth 1 | wc：在当前目录（不包含子目录），统计所有文件个数</p><p>（14）du（disk usage）：显示文件或目录的大小。<br>常用参数：<br>-s：仅显示总数。<br>-l：重复计算硬件连接的文件。<br>-h：以K，M，G为单位。<br>常用：du -sh显示当前目录下的使用总空间。<br>du -sh xxx显示xxx的大小，可以是文件或文件夹。<br>du -ah显示所有文件的大小<br>du -lh –max-depth&#x3D;1查看当前目录下一级文件和子目录占用的磁盘容量</p><p>（15）In（link files）：为某一个文件在另一个位置建立一个同步链接，分硬链接和软链接。<br>（当需要在不同的目录下，用相同的文件时，可以在某个固定的目录下放该文件，其它目录下用In命令link它就行了，可节省磁盘空间。）<br>常用参数：<br>-s：软链接（符号链接）<br>In -s [源文件或目录] [目标文件或目录]<br>In -s aaa bbb，那么bbb-&gt;aaa（后指向前）</p><p>grep：用于查找文件里符合条件的字符串。常用于搜索关键词，查找定义文件，查找error。<br>常用参数：<br>-i：忽略大小写进行匹配。<br>-r：递归查找子目录中的文件。<br>-n：显示匹配的行号。<br>-s：不显示错误信息。<br>-l：仅显示匹配内容的文件名，不显示实际匹配的具体内容。<br>grep -irsn “xxxx”表示递归且不区分大小写在当前文件夹下查找字符串xxxx，且显示行数。</p><p>同时，可以使用grep “要搜索的字符” 源文件 &gt; 目标文件此命令，作用是搜索结果后导入到另一个文件中。eg：grep -isrn “xxxx” .&#x2F; &gt; yyy.txt</p><blockquote><p>和&gt;&gt;命令：重定向操作符之一，用于将命令的输出重定向到文件中，或用于创建新文件并将输出写入该文件。<br>符号用于将输出重定向到文件中；&gt;&gt;符号用于将输出重定向到文件的末尾。</p></blockquote><h3 id="脚本案例-1（bash）"><a href="#脚本案例-1（bash）" class="headerlink" title="脚本案例 1（bash）"></a>脚本案例 1（bash）</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定要搜索的目录</span></span><br><span class="line">search_dir=<span class="string">&quot;path&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 找到所有包含 block_en = 1 &lt;&lt; block_id 的文件并处理</span></span><br><span class="line">files=$(grep -rl <span class="string">&quot;block_en = 1 &lt;&lt; block_id&quot;</span> <span class="string">&quot;<span class="variable">$search_dir</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> file <span class="keyword">in</span> <span class="variable">$files</span>; <span class="keyword">do</span></span><br><span class="line">  <span class="comment"># 替换 [0:15] 为 [0:11]</span></span><br><span class="line">  sed -i <span class="string">&#x27;s/\[0:15\]/[0:11]/g&#x27;</span> <span class="string">&quot;<span class="variable">$file</span>&quot;</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;Replaced in <span class="variable">$file</span>&quot;</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Replacement done.&quot;</span></span><br></pre></td></tr></table></figure><h3 id="脚本案例-2（tcsh）"><a href="#脚本案例-2（tcsh）" class="headerlink" title="脚本案例 2（tcsh）"></a>脚本案例 2（tcsh）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/tcsh</span><br><span class="line"></span><br><span class="line">set files = `grep -nr --include=\*.sv --include=\*.svh --include=\*.v -E &quot;|Mellanox|Synopsys|Candence|Mentor|Orchip&quot; -lr`</span><br><span class="line">foreach file ($files)</span><br><span class="line">  sed -i &#x27;s/Mellanox/GT/g&#x27; $file</span><br><span class="line">  sed -i &#x27;s/Synopsys/GT/g&#x27; $file</span><br><span class="line">  sed -i &#x27;s/Candence/GT/g&#x27; $file</span><br><span class="line">  sed -i &#x27;s/Mentor/GT/g&#x27; $file</span><br><span class="line">  sed -i &#x27;s/Orchip/GT/g&#x27; $file</span><br><span class="line">  echo &quot;Replaced $file.&quot;</span><br><span class="line">end</span><br><span class="line">echo &quot;Replace Done&quot;</span><br></pre></td></tr></table></figure><p>chmod命令：修改file文件权限，其分为所有者、所属者和其他用户的权限。<br>0：没有权限（—）<br>1：执行权限（–x）<br>2：写权限（-w-）<br>3：写和执行权限（-wx）<br>4：读权限（r–)<br>5：读和执行权限（r-x）<br>6：读和写权限（rw-）<br>7：读、写和执行权限（rwx）<br>常用&#x3D;&#x3D;&#x3D;&gt;chmod 755 file，在执行py文件时，需要文件可执行。</p><p>ctrl+r命令：进入搜索历史命令模式，可以输入关键词，自动选择历史命令。</p><p>sed命令：主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。<br>基本语法：sed [选项] ‘command’ file<br>选项：<br>-i：直接修改文件内容，常用于替换操作。（加-i会修改文件，不加不会修改）<br>-e：允许多个编辑命令。<br>命令：<br>s&#x2F;regexp&#x2F;replacement&#x2F;：替换模式，将匹配正则表达式regexp的内容替换为replacement。<br>d：删除命令，删除匹配的行。<br>p：打印命令，打印匹配的行。<br>i：插入命令，在行之前插入文本。<br>a：添加命令，在行之后追加文本。</p><p>sed -i ‘s&#x2F;old_text&#x2F;new_text&#x2F;g’ filename<br>sed -I -e ‘s&#x2F;old_text1&#x2F;new_text1&#x2F;g’ -e ‘s&#x2F;old_text2&#x2F;new_text2&#x2F;g’ filename</p><p>在Linux下，可以使用sed命令来批量替换多个文件中的文本内容。<br>常见使用：sed -i ‘s&#x2F;old_string&#x2F;new_string&#x2F;g’ file_path<br>比如：<br>sed -i ‘s&#x2F;case_cfg.data_return_num&#x2F;case_cfg.ibe_inch_num&#x2F;g’ &#x2F;path&#x2F;to&#x2F;files&#x2F;<em>.txt<br>在这个命令中：<br>1）-i：选项表示直接修改文件内容，而不是输出到标准输出。<br>2）’s&#x2F;old_text&#x2F;new_text&#x2F;g’是sed 命令的替换语法，其中old_text是要被替换的文本，new_text 是替换后的文本，g表示全局替换。（若替换的字符串有’符号，可以使用””包含表达式以作区分）<br>3）&#x2F;path&#x2F;to&#x2F;files&#x2F;</em>.txt 是包含需要替换的文件的路径。可根据实际情况修改路径和文件名的通配符。<br>注意：在使用 sed -i 命令时，-i 选项会直接修改文件内容，请确保在操作前备份文件以防止意外情况发生。</p><p>扩展：<br>1）替换当前目录子目录下所有文件字符：<br>命令格式：<br>find 目标目录 -type f -exec sed -i ‘s&#x2F;旧字符串&#x2F;信字符串&#x2F;g’ {} +<br>含义：<br>find 目标目录：指定要递归查找的目录（如.表示当前目录，&#x2F;home&#x2F;user&#x2F;docs表示绝对路径）；<br>-type f：只处理普通文件（排除目录、符号链接等）；<br>-exec sed … {} +：对找到的每个文件执行sed替换（{}代表找到的文件，+比;更高效）<br>sed -i：原地替换（直接修改文件内容，无临时文件）；<br>s&#x2F;旧字符串&#x2F;信字符串&#x2F;g：替换规则（s&#x3D;substitute，g&#x3D;global全局替换，不加g只替换每一行第一个匹配项）。</p><p>番外5：脚本语法<br>番外3-1：python语法（需要多学习）<br>1、语法<br>（1）双引号<br>字符串可以用双引号开始和结束，就像用单引号一样。使用双引号的一个好处，就是字符串中可以使用单引号字符。在交互式环境中输入以下代码：</p><blockquote><blockquote><blockquote><p>spam &#x3D; “That is Alice’s cat.”<br>因为字符串以双引号开始，所以 Python 知道单引号是字符串的一部分，而不是表示字符串的结束。<br>（2）转义字符<br>转义字符在编程语言中用于表示一些特殊字符或具有特殊含义的字符序列，转义字符通常在字符串（string）中使用，用于表示特殊字符或字符序列。（此处verilog通用）</p></blockquote></blockquote></blockquote><p>（3）原始字符串<br>在字符串开始的引号之前加上r，使它成为原始字符串。“原始字符串”完全忽略所有的转义字符，打印出字符串中所有的倒斜杠。（转义字符串\无效）</p><blockquote><blockquote><blockquote><p>print(r’That is Carol&#39;s cat.’)<br>That is Carol&#39;s cat.<br>因为是原始字符串，Python认为倒斜杠是字符串的一部分，而不是转义字符的开始。<br>（4）findall方法<br>findall函数的语法：re.findall(pattern,string,flags&#x3D;0)<br>其中，pattern是要匹配的正则表达式模式，string是要搜索的字符串，flags是可选的标志参数，用于控制正则表达式的匹配方式。<br>findall函数会从字符串中找到所有与模式匹配的子串，并将它们以列表的形式返回。如果没有找到匹配的子串，返回的列表将为空。<br>import re<br>string &#x3D; “Hello, my name is John. My email is <a href="mailto:&#106;&#x6f;&#x68;&#x6e;&#x40;&#101;&#120;&#97;&#x6d;&#x70;&#x6c;&#x65;&#x2e;&#x63;&#x6f;&#109;">&#106;&#x6f;&#x68;&#x6e;&#x40;&#101;&#120;&#97;&#x6d;&#x70;&#x6c;&#x65;&#x2e;&#x63;&#x6f;&#109;</a>. Please contact me at <a href="mailto:&#x6a;&#111;&#x68;&#110;&#64;&#101;&#x78;&#x61;&#x6d;&#112;&#x6c;&#101;&#46;&#99;&#111;&#109;">&#x6a;&#111;&#x68;&#110;&#64;&#101;&#x78;&#x61;&#x6d;&#112;&#x6c;&#101;&#46;&#99;&#111;&#109;</a>.”<br>pattern &#x3D; r’\b\w+@\w+.\w+\b’      #####匹配电子邮件地址的正则表达式模式<br>emails &#x3D; re.findall(pattern, string)<br>print(emails)         #####[‘<a href="mailto:&#106;&#111;&#104;&#x6e;&#64;&#101;&#x78;&#x61;&#x6d;&#112;&#x6c;&#x65;&#46;&#x63;&#x6f;&#109;">&#106;&#111;&#104;&#x6e;&#64;&#101;&#x78;&#x61;&#x6d;&#112;&#x6c;&#x65;&#46;&#x63;&#x6f;&#109;</a>‘, ‘<a href="mailto:&#106;&#111;&#104;&#x6e;&#64;&#101;&#x78;&#97;&#x6d;&#x70;&#108;&#x65;&#x2e;&#99;&#x6f;&#x6d;">&#106;&#111;&#104;&#x6e;&#64;&#101;&#x78;&#97;&#x6d;&#x70;&#108;&#x65;&#x2e;&#99;&#x6f;&#x6d;</a>‘]<br>（5）if语句<br>在Python中，if是一个条件语句，用于根据条件的真假来执行不同的代码块。语法如下：<br>if condition:<br>    # 如果条件为真，执行这里的代码块<br>    # 可以是一行或多行代码<br>elif condition2:<br>    # 如果第一个条件为假，但第二个条件为真，执行这里的代码块<br>    # 可以有多个 elif 分支<br>else:<br>    # 如果以上条件都不满足，执行这里的代码块<br>2、正则表达式<br>正则表达式（简称regex）是一种在大多数编程语言中通用的工具，但在具体的实现和用法上可能会有一些差异，总体上是通用的。<br>普通字符：普通字符按照字面意义进行匹配，例如匹配字母”a”将匹配到文本中的”a”字符。<br>元字符：元字符具有特殊的含义，例如\d匹配任意一个数字字符，\w匹配任意一个字母字符，mode{n}匹配mode模式n次，.匹配任意一个字符（除了换行符）等。<br>&#x2F;为斜杆，\为反斜杠<br>（1）括号()<br>圆括号()用于创建子组或捕获组，即用于分组。如：<br>(\d{3})-(\d{4})表示两个分组，第一个圆括号为三个数字组成，第二个圆括号为四个数组组成。<br>对于字符串，正则表达式将匹配()内的字符。<br>（2）竖线|<br>竖线|是一个元字符，表示逻辑上的或操作。用于在正则表达式中指定多个模式中的任意一个匹配。如下：<br>正则表达式：[0-9]|a|b   ###匹配：数字0-9、a或b</p></blockquote></blockquote></blockquote><p>注意：使用|时，会按顺序逐个匹配（从左至右），一旦找到匹配模式，则停止继续匹配。要匹配真正的竖线，需要|。<br>（3）量词<br>问号?<br>问号?是一个元字符，用于指定前面的模式是可选的，可以出现零次或一次。比如：<br>正则表达式：colou?r    ###匹配：color 或 colour</p><p>*表示<em>本身。<br>星号</em><br>    星号<em>用于指定前面的模式可以重复出现零次或多次，通常用于匹配任意的字符或子模式。比如：<br>正则表达式：ab</em>c   ###匹配：ac、abc、abbc、abbbc 等。<br>加号+<br>加号+用于指定前面的模式必须重复出现至少一次或多次。通常用于匹配至少一个或多个字符或子模式。比如：<br>正则表达式：ab+c    ###匹配：abc、abbc、abbbc 等<br>花括号{}<br>    花括号{}用于精确地指定前面的模式重复出现的次数，可以指定一个固定的次数、一个范围或一个范围的最小和最大次数。<br>1、指定固定次数：<br>正则表达式：a{3}       ###匹配：aaa<br>2、指定范围：<br>正则表达式：a{2,4}      ###匹配：aa、aaa、aaaa<br>3、指定最小次数：<br>正则表达式：a{2,}       ###匹配：aa、aaa、aaaa 等（至少出现两次）<br>4、指定最大次数：<br>正则表达式：a{,3}       ###匹配：空字符串、a、aa、aaa（最多出现三次）</p><p>问号?等同于{0,1}; *等同于{0,}; +等同于{1,}<br>（4）贪心和非贪心匹配<br>贪心匹配和非贪心匹配是指在重复模式匹配时的不同行为。贪心匹配是指量词尽可能多地匹配字符；非贪心匹配是指量词尽可能少地匹配字符（即在量词后加上一个?）。比如：<br>正则表达式a.<em>b，匹配字符串aabab，贪心匹配，匹配整个字符串aabab<br>正则表达式a.</em>?b，匹配字符串aabab，非贪心匹配，匹配字符串ab</p><p>注意：?用在量词后，为非贪心匹配。用于字符后，为匹配0次或1次。<br>（5）字符分类<br>常用字符分类的缩写代码<br>缩写字符分类表示<br>\d0到9的任何数字<br>\D除0到9的数字以外的任何字符<br>\w任何字母、数字或下划线字符<br>\W除字母、数字和下划线以外的任何字符<br>\s空格、制表符或换行符（匹配“空白”字符）<br>\S除空格、制表符或换行符以外的任何字符<br>比如：<br>one：正则表达式\d+\s\w+，（\d匹配一个数字，+前面\d出现1次或多次，\s匹配一个空白字符，\w匹配一个字母、数字或下划线，+前面\w出现1次或多次）<br>two：字符串’12 drummers, 11 pipers, 10 lords, 9 ladies, 8 maids, 7 swans, 6 geese, 5 rings, 4 birds, 3 hens, 2 doves, 1 partridge’<br>three：通过findall匹配多个字符串[‘12 drummers’, ‘11 pipers’, ‘10 lords’, ‘9 ladies’, ‘8 maids’, ‘7 swans’, ‘6 geese’, ‘5 rings’, ‘4 birds’, ‘3 hens’, ‘2 doves’, ‘1 partridge’]<br>[]和[^]的作用：<br>[]为匹配括号内任意一个字符，[]内的正则表达式不会被解释。例如[abc]为匹配字符a、b和c；[0-5.]匹配0，1，2，3，4，5和.<br>[^]为匹配除括号内的字符以外的任意一个字符。例如[^abc]匹配除字符a、b和c以外的任意字符。</p><p>（6）美元符号$<br>$用于匹配字符串的结束位置。当$出现在正则表达式的末尾时，表示匹配必须以字符串的结尾结束。比如：<br>xyz$匹配以xyz结尾的字符串。<br>（7）尖括号^<br>^用于匹配字符串的开始位置。当^出现在正则表达式的开头时，表示匹配必须从字符串的开头开始，比如：<br>^abc匹配以abc开头的字符串。<br>（8）通配字符.<br>    .（句号）字符称为通配符，匹配除了换行符之外的所有字符，匹配的是单个字符。<br>常用的.*为匹配任意文本；（匹配除换行外的所有字符）<br>.转义为.<br>（9）正则表达式符号复习<br>正则表达式符号复习：<br>?匹配零次或一次前面的分组。<br><em>匹配零次或多次前面的分组。<br>+匹配一次或多次前面的分组。<br>{n}匹配 n 次前面的分组。<br>{n,}匹配 n 次或更多前面的分组。<br>{,m}匹配零次到 m 次前面的分组。<br>{n,m}匹配至少 n 次、至多 m 次前面的分组。<br>{n,m}?或</em>?或+?对前面的分组进行非贪心匹配。<br>^spam 意味着字符串必须以spam开始。<br>spam$意味着字符串必须以spam结束。<br>.匹配所有字符，换行符除外。<br>\d、\w和\s分别匹配数字、单词和空格。<br>\D、\W和\S分别匹配出数字、单词和空格外的所有字符。<br>[abc]匹配方括号内的任意字符（诸如 a、b 或 c）。<br>[^abc]匹配不在方括号内的任意字符。</p><p>（4）边界匹配<br>\b为匹配单词边界<br>\B为匹配非单词边界<br>（10）应用<br>用法1：  </p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">.oxu_ixu0_ctl_credit_inc</span>,     (oxu_ixu0_ctl_credit_inc),                    </span><br><span class="line"><span class="variable">.ixu1_oxu_ctl_vld</span>,           (ixu1_oxu_ctl_vld),                           </span><br><span class="line"><span class="variable">.ixu1_oxu_ctl_ibe</span>,          (ixu1_oxu_ctl_ibe),                           </span><br><span class="line"><span class="variable">.ixu1_oxu_ctl_chn</span>,           (ixu1_oxu_ctl_chn),  </span><br></pre></td></tr></table></figure><p>比如需要删除中间的逗号（,），那么就可以使用正则表达式，如,(.*),表示逗号,和逗号,之间的所有字符，在gvim中，则可以linex,lineys&#x2F;,(.*),&#x2F; \1,&#x2F;s，那么删除掉中间的逗号,</p><p>用法2：</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:<span class="number">81</span>,<span class="number">101</span>s/\d\+/\=<span class="built_in">submatch</span>(<span class="number">0</span>)+<span class="number">512</span>/g</span><br></pre></td></tr></table></figure><p>表示将81行到101行的，所有数字加512<br>3、code学习<br>if <strong>name</strong> &#x3D;&#x3D; “<strong>main</strong>“: 表示如果这个脚本被直接运行而不是被导入到其他脚本中，则执行下面的代码块。否则如果是被导入到其它脚本中，则不会执行</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sys</span><br><span class="line">sys.argv[<span class="number">0</span>]表示脚本名称</span><br><span class="line">sys.argv[<span class="number">1</span>]表示执行脚本时，命令行的第一个参数，sys.argv[<span class="number">2</span>]为第二个参数，依次类推</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    <span class="keyword">if</span>(<span class="number">2</span>!=<span class="built_in">len</span>(sys.argv)): </span><br><span class="line">        sys.exit(<span class="string">&quot;exit&quot;</span>) <span class="comment">#命令行参数+1个数不为2，则退出</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        function_a(sys.argv[<span class="number">1</span>])</span><br></pre></td></tr></table></figure><p>class类</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,a,b</span>):  <span class="comment">#构造函数，创造属性</span></span><br><span class="line">  <span class="variable language_">self</span>.a = a</span><br><span class="line">  <span class="variable language_">self</span>.b = b</span><br></pre></td></tr></table></figure><p>print打印</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Name:<span class="subst">&#123;self.name&#125;</span>,Age:<span class="subst">&#123;self.age&#125;</span>&quot;</span>) <span class="comment">#f表示是一个f-string带表达式的字符串，&#123;&#125;用来引用变量或表达式。</span></span><br></pre></td></tr></table></figure><p>with使用<br>通常用于管理资源，如文件操作或数据库连接，以确保资源在使用完毕后被正确释放（关闭）。<br>用法：with expression as variable:</p><h1 id="代码块"><a href="#代码块" class="headerlink" title="代码块"></a>代码块</h1><p>例子：<br>#打开文件并写入内容</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;example.txt&quot;</span>, <span class="string">&quot;w&quot;</span>) <span class="keyword">as</span> file: <span class="comment">#打开文件，并将文件句柄给到file</span></span><br><span class="line">    file.write(<span class="string">&quot;Hello, World!&quot;</span>)</span><br></pre></td></tr></table></figure><p>#文件已经在这里被关闭</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(“example.txt”,”r”) <span class="keyword">as</span> file: <span class="comment">#以读的方式打开文件</span></span><br><span class="line">  <span class="keyword">for</span> line <span class="keyword">in</span> file.readlines(): <span class="comment">#读取文件的每一行</span></span><br><span class="line">    line = line.strip() <span class="comment">#去除每行两侧的空白字符（空格、制表符、换行符等）</span></span><br><span class="line">    split1 = line.split(“=”,<span class="number">1</span>) <span class="comment">#以字符中=划分两部分，最多分割1次</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os <span class="comment">#python的标准库</span></span><br><span class="line">files = os.listdir <span class="comment">#用于返回当前目录中文件和子目录的名称列表</span></span><br></pre></td></tr></table></figure><p>列表推导式<br>根据已有的可迭代对象创建一个新的列表，实现常见的转换和筛选操作。<br>[expression for item in iterable if condition]<br>含义：<br>expression：用来处理和转换每个 item 的表达式，生成新的列表元素。<br>item：来自可迭代对象的元素。<br>iterable：可迭代的对象，如列表、元组、集合等。<br>condition：（可选）用来过滤元素的条件，只有满足条件的元素才会包含在最终的列表中<br>例子：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">numbers = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">squared_numbers = [x**<span class="number">2</span> <span class="keyword">for</span> x <span class="keyword">in</span> numbers]</span><br><span class="line"><span class="built_in">print</span>(squared_numbers)  <span class="comment"># 输出：[1, 4, 9, 16, 25]</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line">os.path.abspath(file_path) <span class="comment">#获取file文件的绝对路径</span></span><br><span class="line">file_path.replace(‘-’,’_’) <span class="comment">#将file_path路径中-替换为_</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> xml.dom.minidom <span class="keyword">as</span> minidom</span><br><span class="line">dom = minidom.parse(file) <span class="comment">#将xml文件解析为DOM（Document object Model）对象。DOM是一种树形结构，可以表示XML文档的层次结构。</span></span><br><span class="line">root = dom.documentElement <span class="comment">#获取DOM对象的根元素，即XML文档的顶层元素。</span></span><br><span class="line">elm_name = root.getElementsByTagName(<span class="string">&#x27;elm_name&#x27;</span>) <span class="comment">#从根元素中获取所有名为elm_name的元素（相当于获取根元素下的名为elm_name的子元素）</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> num <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(root.getElementsByTagName(<span class="string">&#x27;registerdb:Name&#x27;</span>))): <span class="comment">#循环根元素下子元素</span></span><br><span class="line">    reg_name = root.getElementsByTagName(<span class="string">&#x27;registerdb:Name&#x27;</span>)[num] <span class="comment">#得到每个元素内容</span></span><br><span class="line">    reg_name_ = reg_name.childNodes[<span class="number">0</span>].data.lower() <span class="comment">#获取文本并将其转换为小写字母形式，获取第一个子节点childNodes的内容data</span></span><br></pre></td></tr></table></figure><p>print(reg_name_1)</p><p>字典（Dictionary）<br>my_dict&#x3D; {} #创建一个空字典<br>my_dict &#x3D; {‘key1’:’value1’, ‘key2’:’value2’} #创建一个带有初始键值对的字典<br>my_dict[‘new_key’] &#x3D; ‘new_value’    #添加新的键值对<br>my_dict[‘key1’] &#x3D; ‘updated_value’    #更新现有键的值<br>del my_dict[‘key1’]   #删除指定键值对<br>my_dict.clear()      #清空字典<br>for key in my_dict:   #遍历所有键<br>    print(key)<br>for value in my_dict.values():    #遍历所有值<br>    print(value)<br>for key, value in my_dict.items():  #遍历所有键值对<br>print(key, value)</p><p> <br>code1：提取宏的python脚本<br>import re<br>def extract_macros(file_path):<br>    macros &#x3D; { #字典<br>        ‘ifdef’: set(), #set确保内部变量唯一性<br>        ‘ifndef’: set(),<br>        ‘define’: set()<br>    }</p><pre><code>with open(file_path, &#39;r&#39;) as file:    for line in file:        line = line.strip() ##去除每行两侧的空白字符(空格,制表符,换行符等)        #匹配 `ifdef 和 `ifndef        if line.startswith(&#39;`ifdef&#39;):            macro_name = line.split(&#39;`ifdef&#39;)[1].strip()            macros[&#39;ifdef&#39;].add(macro_name)        elif line.startswith(&#39;`ifndef&#39;):            macro_name = line.split(&#39;`ifndef&#39;)[1].strip()            macros[&#39;ifndef&#39;].add(macro_name)        #匹配 `define        elif line.startswith(&#39;`define&#39;):            parts = line.split(&#39;`define&#39;)[1].strip().split() ##以`define分割两部分,选取第2部分,删除字符串首尾空格,然后以空格分割两部分            if parts: #非空执行                macro_name = parts[0]                macros[&#39;define&#39;].add(macro_name)#返回字典内容return macros</code></pre><p>def main():<br>    file_path &#x3D; input(“请输入要提取宏的Verilog文件路径:”)<br>    macros &#x3D; extract_macros(file_path)</p><pre><code>print(&quot;提取的宏:&quot;)for macro_type, names in macros.items():    print(f&quot;&#123;macro_type&#125;: &#123;&#39;, &#39;.join(names)&#125;&quot;)</code></pre><p>if <strong>name</strong> &#x3D;&#x3D; “<strong>main</strong>“:<br>    main()<br>番外3-2：shell脚本<br>Shell是一个用 C 语言编写的程序，它是用户使用 Linux 的桥梁。Shell 既是一种命令语言，又是一种程序设计语言。<br>Shell 脚本（shell script），是一种为 shell 编写的脚本程序。<br>（1）shell脚本与python一样使用#注释。<br>（2）shell脚本的开头#!&#x2F;bin&#x2F;bash，#!表示其后所用的为哪一种shell。<br>（3）创建扩展名为sh的文件后，使用chmod赋予文件可执行权限，即chmod +x file.sh。执行文件的命令为.&#x2F;file.sh，此为以二进制的方式执行<br>（1）shell变量<br>变量的取名：<br>1、只能包含数字、字母（大小敏感）和下划线；2、不能以数字开头；3、通常以大写字母表示常量。如：<br>your_name&#x3D;”lee”     ##注意：变量名和等号之间不能有空格。<br>echo “${your_name}good”   ##加{}以指定变量，不加则取$your_namegood为空<br>unset your_name     ##删除变量your_name<br>字符串的使用：<br>字符串是shell中最常用的数据类型，使用单引号’string’和双引号”string”来表示。单引号里的任意字符都会原样输出（字符串中的变量是无效的）；双引号里可以出现变量和转义字符。<br>string&#x3D;”abcd”<br>获取字符串长度${#string}   #得到字符串string长度<br>提取字符串长度${string:1:3}  #提取字符串”bcd”，第一个索引为0</p><p>数组的使用：<br>在shell中，用括号来表示数组，数组元素用空格符号分割开。如：<br>数组名&#x3D;{value1 value2 value3 …. valuen}<br>读取某个元素：${数组名[下标]}  #读取数组的某个元素<br>读取所有元素：${数组名[@]}   #读取数组的所有元素<br>获取数组长度：$[#数组名[@]]   #获取数组元素个数<br>获取数组元素的长度：$[#数组名[n]]  #获取第n个数组长度</p><p>shell基本运算符：</p><p>注意：条件表达式要放在方括号之间，并且要有空格，例如: [$a&#x3D;&#x3D;$b] 是错误的，必须写成 [ $a &#x3D;&#x3D; $b ]。</p><p>命令替换：命令替换是一种在shell脚本中执行命令并将其输出结果赋值给变量的技术。在shell脚本中，有两种主要的命令替换语法：<br>使用反引号（<code>）：在较旧的shell脚本中，命令替换通常使用反引号来实现。例如： result=</code>command&#96;<br>使用$()：较新的shell脚本通常使用$()语法来进行命令替换。例如：<br>result&#x3D;$(command)</p><p>if使用：if语句用于在特定条件满足时执行特定的代码块。if语句的基本语法如下：<br>if [ condition ]<br>then<br>    # Code block to be executed if condition is true<br>fi<br>下面是一个简单的示例，演示了如何在Shell脚本中使用if语句：<br>#!&#x2F;bin&#x2F;bash</p><h1 id="Check-if-a-number-is-greater-than-10"><a href="#Check-if-a-number-is-greater-than-10" class="headerlink" title="Check if a number is greater than 10"></a>Check if a number is greater than 10</h1><p>num&#x3D;15<br>if [ $num -gt 10 ]<br>then<br>    echo “The number is greater than 10.”<br>fi<br>在这个示例中，如果变量num的值大于10，则打印”The number is greater than 10.”。<br>除了基本的if语句之外，还可以使用elif（else if）和else来处理多个条件。以下是一个带有elif和else的示例：<br>#!&#x2F;bin&#x2F;bash</p><h1 id="Check-if-a-number-is-positive-negative-or-zero"><a href="#Check-if-a-number-is-positive-negative-or-zero" class="headerlink" title="Check if a number is positive, negative, or zero"></a>Check if a number is positive, negative, or zero</h1><p>num&#x3D;-5<br>if [ $num -gt 0 ]<br>then<br>    echo “The number is positive.”<br>elif [ $num -lt 0 ]<br>then<br>    echo “The number is negative.”<br>else<br>    echo “The number is zero.”<br>fi<br>在这个示例中，根据变量num的值，会输出数字是正数、负数还是零。</p><p>for使用：for循环用于遍历一系列的值或文件。这是处理多个项的一个常用方法。for循环的基本语法如下：<br>for variable in list<br>do<br>    # Code block to be executed for each item in the list<br>done</p><p>遍历一个数组<br>#!&#x2F;bin&#x2F;bash</p><h1 id="Define-an-array"><a href="#Define-an-array" class="headerlink" title="Define an array"></a>Define an array</h1><p>fruits&#x3D;(“apple” “banana” “orange”)</p><h1 id="Iterate-over-the-array"><a href="#Iterate-over-the-array" class="headerlink" title="Iterate over the array"></a>Iterate over the array</h1><p>for fruit in “${fruits[@]}”<br>do<br>    echo “Fruit: $fruit”<br>done<br>在这个例子中，for循环遍历数组fruits中的每一个元素，并打印出每种水果的名称。</p><p>遍历文件中的行<br>#!&#x2F;bin&#x2F;bash</p><h1 id="Loop-through-each-line-of-a-file"><a href="#Loop-through-each-line-of-a-file" class="headerlink" title="Loop through each line of a file"></a>Loop through each line of a file</h1><p>for line in $(cat myfile.txt)<br>do<br>    echo “Line: $line”<br>done</p><p>while使用：while循环用于在条件为真时重复执行一段代码块。while循环的基本语法如下：</p><ol><li>基本语法<br>while [ condition ]<br>do<h1 id="Code-block-to-be-executed-as-long-as-the-condition-is-true"><a href="#Code-block-to-be-executed-as-long-as-the-condition-is-true" class="headerlink" title="Code block to be executed as long as the condition is true"></a>Code block to be executed as long as the condition is true</h1></li></ol><p>done</p><p>例子 1：基本的while循环<br>#!&#x2F;bin&#x2F;bash<br>count&#x3D;1<br>while [ $count -le 5 ]<br>do<br>    echo “Count: $count”<br>    ((count++))<br>done<br>在这个例子中，while循环会在count小于等于5时重复执行，每次输出当前的计数值，并递增count。</p><p>例子2 ：在while循环中，你也可以使用break和continue关键字来控制循环的执行，与for循环类似。<br>break用于立即退出循环。<br>continue用于跳过当前迭代并进入下一个迭代。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line">count=1</span><br><span class="line"><span class="keyword">while</span> [ <span class="variable">$count</span> -le 5 ]</span><br><span class="line"><span class="keyword">do</span></span><br><span class="line">    <span class="keyword">if</span> [ <span class="variable">$count</span> -eq 3 ]; <span class="keyword">then</span></span><br><span class="line">        ((count++))</span><br><span class="line">        <span class="built_in">continue</span>  <span class="comment"># Skip count 3</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Count: <span class="variable">$count</span>&quot;</span></span><br><span class="line">    ((count++))</span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><p>在这个例子中，continue 语句跳过了计数为 3 的情况，输出将是 1, 2, 4, 5。</p><div class="note info flat"><blockquote><p><strong>注意</strong> 脚本开发完，需要 chmod 增加执行权限。</p></blockquote></div><h2 id="番外6：SV-与-C-交互（待完善）"><a href="#番外6：SV-与-C-交互（待完善）" class="headerlink" title="番外6：SV 与 C 交互（待完善）"></a>番外6：SV 与 C 交互（待完善）</h2><p>verilog 是一种硬件描述语言，主要用于描述数字电路和硬件行为，而不是数学计算。因此在 verilog 中没有直接支持三角函数的内置函数。可以通过查找表（Lookup Table）和 DPI-C（调用 C 的内置三角函数）来实现三角函数或其它数学计算。</p><p><strong>need study</strong></p><h1 id="五、Verdi-工具"><a href="#五、Verdi-工具" class="headerlink" title="五、Verdi 工具"></a>五、Verdi 工具</h1><h2 id="1-Verdi-的使用"><a href="#1-Verdi-的使用" class="headerlink" title="1 Verdi 的使用"></a>1 Verdi 的使用</h2><ul><li>view 选项下的 signal list 可以查看双击文件的各个信号；Source 选项下可 find 目标信号&#x2F;字符串。</li><li>选项卡中 D（Driver）表示信号被谁驱动，L（load）表示信号加载谁；可 next&#x2F;previous 浏览驱动与加载信号。</li><li>波形窗口：鼠标左键确定一个时钟点，鼠标滑轮确定另一个时钟点；两点之间即为时钟差值。</li><li>waveform 工具栏的 Set Search Value 可搜索信号具体数值；位宽过大可截位后再设置，或模糊搜索 <code>*value*</code>。</li><li>Tools → Waveform compare：比较两个信号。</li><li>view → grid options：统计上升沿和下降沿次数。</li><li>双击波形变化点，可在代码区定位导致该变化的代码。</li><li>波形框快捷键：h 显示绝对路径；c&#x2F;t 高亮信号；k 截尾位宽；代码区按 g 可跳转指定行。</li><li>波形框支持 logic operation：logic operation → 逻辑操作 → create&#x2F;modify。</li><li>多波形文件时，”Ctrl + w” 添加信号默认加到主波形；以 Verdi 18 为例，可在 nWave 菜单右侧 “P” 图标（shift+P）设置主波形窗口。</li><li>nWave 的 “By:” 右侧箭头可按任意值&#x2F;上升沿&#x2F;下降沿&#x2F;指定值等方式检索；选中信号后按 N&#x2F;n 向前&#x2F;后搜索。</li><li>波形数据右键：2’s complement 为补码；1’s complement 为反码；signed magnitude 为符号位 + 绝对值。</li><li>SoC 顶层分析：source → Find_Scope，搜索模块后再具体分析。</li><li>截位操作：create bus（快捷键 k）截位；expand as sub-bus 可将位宽划分为多份。</li><li>xxx（示例）：编译 DUT → 编译 comp 环境 → elab&#x2F;接口衔接 → SIM 仿真生成波形。</li><li>view → signal event report：查看上升沿&#x2F;下降沿次数。</li><li>ctrl+f：将变量复制到搜索框中。</li></ul><h3 id="1-1-Dump-命令（FSDB）"><a href="#1-1-Dump-命令（FSDB）" class="headerlink" title="1.1 Dump 命令（FSDB）"></a>1.1 Dump 命令（FSDB）</h3><ul><li>fsdbDumpfile：指定生成 fsdb 文件名</li><li>fsdbDumpvar：指定 dump 的 instance 和层级（0&#x2F;1&#x2F;2…），instance 为 DUT 下模块路径名称</li><li>fsdbDumpSVA：dump 断言处信号变化</li><li>fsdbDumpMDA：dump 多维数组</li><li>fsdbDumpon &#x2F; fsdbDumpoff：打开&#x2F;关闭 FSDB dump</li></ul><p>不同公司用法位置可能不同，通常写在 <code>initial begin ... end</code> 中：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">fsdbDumpfile <span class="string">&quot;fsdb_name.fsdb&quot;</span>;</span><br><span class="line">fsdbDumpvars <span class="number">0</span> <span class="string">&quot;tb_top&quot;</span>;</span><br><span class="line">fsdbDumpMDA <span class="number">0</span> <span class="string">&quot;tb_top&quot;</span>;</span><br><span class="line">fsdbDumpSVA <span class="number">0</span> <span class="string">&quot;tb_top&quot;</span>;</span><br></pre></td></tr></table></figure><ul><li>使用 <code>-gui 1</code> 调试时，左上角可指定调试时间点；选择 absolute time 后输入具体时间即可跳转。</li><li>生成 fsdb 文件后，window → Interactive Debug Mode 可直接进入调试模式，无需重新编译。</li></ul><h2 id="2-Verdi-波形截取"><a href="#2-Verdi-波形截取" class="headerlink" title="2 Verdi 波形截取"></a>2 Verdi 波形截取</h2><p>对仿真波形的截取命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fsdbextract source.fsdb -bt 10ns -et 20ns -o output.fsdb</span><br></pre></td></tr></table></figure><p>source.fsdb 为需要截取的波形；-bt&#x2F;-et 分别为开始&#x2F;结束时刻；-o 为输出文件。</p><h2 id="3-Verdi-生成文件"><a href="#3-Verdi-生成文件" class="headerlink" title="3 Verdi 生成文件"></a>3 Verdi 生成文件</h2><ul><li>novas.rc：Verdi 配置文件，包含外观、窗口布局、颜色方案、快捷键绑定、仿真工具集成等配置项。通常位于 Verdi 安装目录下的 share&#x2F;novas.rc 或类似路径。</li></ul><h2 id="4-Verdi-timeslot-区域查看"><a href="#4-Verdi-timeslot-区域查看" class="headerlink" title="4 Verdi timeslot 区域查看"></a>4 Verdi timeslot 区域查看</h2><ol><li>加入编译&#x2F;运行选项：</li></ol><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">COMP_OPT += +fsdb+region</span><br><span class="line">SIM_OPT  += +fsdb+delta</span><br></pre></td></tr></table></figure><ol start="2"><li>进入 Verdi 界面后：view → Expand Delat → Region Mode &#x2F; Expand&#x2F;Collapse Time at Cursor，查看变量赋值的时间区域。</li><li>选中变量值跳变处，判断赋值发生在 active 区域（阻塞赋值）或 NBA 区域（非阻塞赋值）。</li></ol><h2 id="5-Verdi-自带-VC-Apps"><a href="#5-Verdi-自带-VC-Apps" class="headerlink" title="5 Verdi 自带 VC Apps"></a>5 Verdi 自带 VC Apps</h2><ul><li>不合理波形处双击跳变沿查看驱动；若驱动较多，可看 message 窗口列出所有驱动位置。</li><li>使用 VC Apps Toolbox：Design Exploration → Get Force Statement → OK 导出到文件。</li></ul><h2 id="6-用例定位与断点调试"><a href="#6-用例定位与断点调试" class="headerlink" title="6 用例定位与断点调试"></a>6 用例定位与断点调试</h2><p>declaration 窗口按 ctrl+f 打开搜索窗口，搜索用例后即可断点调试。</p><h1 id="六、常用知识点"><a href="#六、常用知识点" class="headerlink" title="六、常用知识点"></a>六、常用知识点</h1><p>1、异步FIFO空满判断<br>1、同步rd_cntr至clk_write时钟域，再与wr_cntr进行对比来决定FIFO是否满；（判断满wr_cntr-rd_cntr）<br>2、同步wr_cntr至clk_read时钟域，再与rd_cntr进行对比来决定FIFO是否空；（判断空是rd_cntr&#x3D;&#x3D;wr_cntr）<br>为什么要这么判断？因为在写时钟域去判断满，当full时，告诉FIFO不要再写了，而在读时钟域去判断空，当empty时，告诉FIFO已经空了，不能再读了。</p><p>（2）APB的写与读，写就是写，读就是读，写的对面不是读；读的对面不是写。读和写操作的那面就是Master，而被读和写的就是Slave。<br>2、回归<br>在芯片开发过程中，一旦RTL代码做了修改，就有可能引入新的问题，所以这个时候就需要把已经完成了的验证用例重新跑一下，以确保RTL代码的修改没有对已经验证过的功能造成影响，这个过程叫做回归验证（或只叫回归，regress）。</p><p>regression：回归</p><p>3、硬复位和软复位<br>（1）软复位：常用于复位逻辑模块，非配置类寄存器值，如count类寄存器。<br>（2）硬复位：常用于配置寄存器模块，配置信号同步模块.<br>（3）硬复位有效会导致软复位有效，而通过soc总线配置软复位有效时硬复位不受影响。<br>4、同步复位和异步复位<br>1、同步复位是在时钟边沿时刻处理复位信号，即当时钟信号发生变化时，同时对电路的所有触发器进行重置。同步复位常用于时序电路中需要同步控制信号的场景。</p><p>同步复位<br>2、异步复位（或称异步清零）是在任意时刻处理复位信号，即不需要等待时钟信号变化就可以对电路进行复位，一般是通过一个异步或非时序的输入信号来控制。异步复位常用于需要立即停止电路操作的场景，例如发生错误时需要立即停止一个电路的运行。</p><p>异步复位<br>5、秒的单位<br>秒（Second）是国际单位制（SI）中的基本时间单位。它表示时间的持续或间隔。除了秒本身，还有一些常见的时间单位是基于秒的衍生单位。以下是一些常见的时间单位：<br>毫秒（Millisecond）：1毫秒等于0.001秒，即1秒的千分之一 。<br>微秒（Microsecond）：1微秒等于0.000001秒，即1秒的百万分之一。<br>纳秒（Nanosecond）：1纳秒等于0.000000001秒，即1秒的十亿分之一。<br>皮秒（Picosecond）：1皮秒等于0.000000000001秒，即1秒的万亿分之一。<br>飞秒（Femtosecond）：1飞秒等于0.000000000000001秒，即1秒的千万亿分之一。<br>等量关系（常用换算）：</p><ul><li>$1\ \mathrm{s} &#x3D; 10^3\ \mathrm{ms} &#x3D; 10^6\ \mathrm{us} &#x3D; 10^9\ \mathrm{ns}$</li><li>$1\ \mathrm{s} &#x3D; 10^{12}\ \mathrm{ps} &#x3D; 10^{15}\ \mathrm{fs}$</li><li>$1\ \mathrm{ms} &#x3D; 10^3\ \mathrm{us} &#x3D; 10^6\ \mathrm{ns}$</li><li>$1\ \mathrm{us} &#x3D; 10^3\ \mathrm{ns} &#x3D; 10^6\ \mathrm{ps}$<br>这些单位通常用于测量非常短暂的时间间隔，例如电子器件的响应时间、光信号的传播时间等。对于一般的日常时间测量，秒是最常用的单位。<br>6、赫兹的单位<br>赫兹（Hz）是国际单位制（SI）中表示频率的单位，表示“每秒发生多少个周期”。</li></ul><p>数学关系：</p><ul><li>$1\ \mathrm{Hz} &#x3D; 1\ \mathrm{s}^{-1}$</li><li>$f &#x3D; \dfrac{1}{T}$（频率 $f$ 与周期 $T$ 互为倒数）</li></ul><p>常用单位（科学计数法）：</p><ul><li>$1\ \mathrm{kHz} &#x3D; 10^3\ \mathrm{Hz}$</li><li>$1\ \mathrm{MHz} &#x3D; 10^6\ \mathrm{Hz}$</li><li>$1\ \mathrm{GHz} &#x3D; 10^9\ \mathrm{Hz}$</li></ul><p>等量关系：</p><ul><li>$1\ \mathrm{GHz} &#x3D; 10^3\ \mathrm{MHz} &#x3D; 10^6\ \mathrm{kHz} &#x3D; 10^9\ \mathrm{Hz}$<br>7、tape-out<br>流片（tape-out）是指通过一系列工艺步骤在流水线上制造芯片，是集成电路设计的最后环节。流片即为“试生产”，是把电路设计变为ASIC芯片的过程。<br>8、RAM类型<br>RAM分为单口RAM、伪双口RAM和双口RAM。<br>（1）单口RAM：只有一组数据线和地址线，不能同时读写，读写都使用这个口访问RAM。</li></ul><p>（2）伪双端口RAM：一个端口只能写，一个端口只能读（两组数据线和地址线，一组是写数据线，一组是读数据线），一般FIFO内部例化的都是伪双端口RAM。</p><p>（3）真双端口RAM：两个读写端口，每个端口可独立发起读或者写，一组是读或者写数据线，另外一组也是读或者写数据线。</p><p>9、SDF文件<br>SDF文件为标准延迟格式（standard Delay Format，时序文件），将时序文件SDF反标到门级网表上，针对带有时序信息的网表进行仿真，则为时序仿真。</p><p>TB 中回标（吃）SDF 的常见写法：在 top TB 的 <code>initial</code> 中调用 <code>$sdf_annotate</code>，把 SDF 文件绑定到 DUT 的层级实例上。</p><p>示例 1：固定文件名 + 固定实例</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> tb_top;</span><br><span class="line">  dut u_dut();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    $sdf_annotate(<span class="string">&quot;dut.sdf&quot;</span>, u_dut, , , <span class="string">&quot;TYPICAL&quot;</span>);</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endmodule</span></span><br></pre></td></tr></table></figure><p>示例 2：用 plusargs 传 SDF 路径（回归更方便）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> tb_top;</span><br><span class="line">  dut u_dut();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">string</span> sdf_file;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">$value$plusargs</span>(<span class="string">&quot;SDF_FILE=%s&quot;</span>, sdf_file)) sdf_file = <span class="string">&quot;dut.sdf&quot;</span>;</span><br><span class="line">    $sdf_annotate(sdf_file, u_dut, , , <span class="string">&quot;MAXIMUM&quot;</span>);</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endmodule</span></span><br></pre></td></tr></table></figure><p>示例 3：多实例回标（不同模块对应不同 SDF）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> tb_top;</span><br><span class="line">  dut u_dut();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    $sdf_annotate(<span class="string">&quot;dut_top.sdf&quot;</span>, u_dut, , , <span class="string">&quot;TYPICAL&quot;</span>);</span><br><span class="line">    $sdf_annotate(<span class="string">&quot;pcie.sdf&quot;</span>, u_dut<span class="variable">.u_pcie</span>, , , <span class="string">&quot;TYPICAL&quot;</span>);</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endmodule</span></span><br></pre></td></tr></table></figure><p>要点：</p><ul><li><code>$sdf_annotate</code> 的第 2 个参数是“层级实例”，必须和门级网表的实例路径一致</li><li>MTM 选择常见用 <code>MINIMUM/TYPICAL/MAXIMUM</code>，和使用的 SDF 内容、库角有关</li></ul><h1 id="八、验证环境"><a href="#八、验证环境" class="headerlink" title="八、验证环境"></a>八、验证环境</h1><h2 id="1-验证环境与-Test-Bench"><a href="#1-验证环境与-Test-Bench" class="headerlink" title="1 验证环境与 Test Bench"></a>1 验证环境与 Test Bench</h2><p>验证环境就是各组件组合而成的UVM环境，Test Bench就是整体的验证框架（测试平台）。</p><h2 id="2-寄存器模型更新"><a href="#2-寄存器模型更新" class="headerlink" title="2 寄存器模型更新"></a>2 寄存器模型更新</h2><p>目录下。</p><h2 id="3-编译命令"><a href="#3-编译命令" class="headerlink" title="3 编译命令"></a>3 编译命令</h2><h2 id="4-其它"><a href="#4-其它" class="headerlink" title="4 其它"></a>4 其它</h2><p>可以在 build.cfg 文件中加入编译选项，可以是 UVM_OPT 或 COMP_OPT 选项，例如：</p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">COMP_OPT += +<span class="keyword">define</span>+宏定义</span><br><span class="line">UVM_OPT  += +<span class="keyword">define</span>+UVM_HDL_MAX_WIDTH=2048</span><br><span class="line">UVM_OPT  += +<span class="keyword">define</span>+UVM_VERBOSITY=UVM_LOW</span><br></pre></td></tr></table></figure><p>在仿真前，先加入编译选项来屏蔽或提供一些后续的操作。如1：加入宏定义以此达到屏蔽一些check的目的（也可提供if来屏蔽）；如2：提供force数据的最大位宽；如3：屏蔽一些不必要的UVM_INFO打印。</p><h1 id="九、XXX"><a href="#九、XXX" class="headerlink" title="九、XXX"></a>九、XXX</h1><h2 id="1-IPD-项目流程"><a href="#1-IPD-项目流程" class="headerlink" title="1 IPD 项目流程"></a>1 IPD 项目流程</h2><p>芯片设计项目<br>DR：Design Ready（DE完成详细设计）<br>CR：Code Ready（DE完成编码）<br>BC：Basic Check（DV完成basic case验证）<br>MF：Major Function（DV完成主要功能验证）VO 75%？</p><p>TR4：DV完成（DV完成验证，前端&#x2F;软件验证项目关闭）V0100% COV 100%<br>TR5：RTL Freeze<br>TR6：Tape out</p><p>BC交付标准：BT完成主体和高优先级功能测试，完成checklist中BC节点及以前检查项，完成VO checklist刷新，部分模块BC评审遗留项及CHECKLIST等；<br>MF交付标准：BT完成剩余低优先功能及动态，异常，性能和白盒调试等，完成checklist中MF及以前节点检查，功能覆盖率根据策略收集完成等；</p><p>1、SVN<br>1、svn up<br>svn up -r 版本号：更新目录下的所有文件到版本号。<br>svn up 文件 -r 版本号：更新文件夹下的具体文件到某一版本。<br>2、svn checkout<br>svn co 目录路径：将目录路径下的文件check out到本目录文件下。（co&#x3D;checkout）<br>等同于svn checkout <a href="https://xxxxxx文件/">https://xxxxxx文件</a><br>3、svn commit&#x2F;add&#x2F;delete<br>svn ci 文件 目录路径：将文件提交到目录中。（ci&#x3D;commit）<br>等同于svn commit -m “文件注释” xxxx文件。</p><p>svn add file：增加文件至库上，最后需要svn commit file，则完成上传<br>svn delete file：删除库上文件，最后需要svn commit file，则完成删除</p><p>4、svn switch –relocate<br>svn switch –relocate 旧svn地址 新svn地址：将svn旧地址更新为svn新地址。<br>3、svn log<br>svn log用于查看日志，如svn log -l 5 xxx.file，表示文件xxx.flie最近5次的更新改动。<br>4、svn更新冲突<br>svn更新出现冲突的解决方法<br>Select:       (p) postpone, (df) diff-full, (e) edit,<br>(mc) mine-conflict, (tc) theirs-conflict,<br>(s) show all options:</p><p>(e)  edit      - change merged file in an editor                        #直接进入编辑<br>(df) diff-full    - show all changes made to merged file    #显示更改至目标文件的所有变化<br>(r)  resolved   - accept merged version of file<br>(dc) display-conflict  - show all conflicts (ignoring merged version)         #显示所有冲突<br>(mc) mine-conflict   - accept my version for all conflicts (same)           #冲突以本地为准<br>(tc) theirs-conflict    - accept their version for all conflicts (same)        #冲突以服务器为准<br>(mf) mine-full       - accept my version of entire file (even non-conflicts)  #完全以本地为准<br>(tf) theirs-full       - accept their version of entire file (same)           #完全以服务器为准<br>(p)  postpone       - mark the conflict to be resolved later           #标记冲突，稍后解决<br>(l)  launch          - launch external tool to resolve conflict<br>(s)  show all         - show this list</p><p>5、svn st<br>svn st命令用于显示工作副本中文件和目录的状态，以及这些文件和目录在版本控制系统中的状态。<br>通过运行 svn st 命令，您可以查看以下信息：<br>未修改的文件（Unmodified）：显示为 “ “（空格）。<br>已修改的文件（Modified）：显示为 “M”。<br>新添加的文件（Added）：显示为 “A”。<br>已删除的文件（Deleted）：显示为 “D”。<br>有冲突的文件（Conflict）：显示为 “C”。<br>未受版本控制的文件（Unversioned）：显示为 “?”。<br>已被调度删除的文件（Scheduled for deletion）：显示为 “!”。<br>6、svn status<br>svn status命令与svn st命令等效，都用于查看 Subversion（SVN）版本控制系统中工作副本的状态，显示工作副本中文件和目录的状态信息，以及这些文件和目录在版本控制系统中的状态。<br>7、svn revert<br>svn revert命令用于撤销对工作副本中文件或目录的修改，将其还原为最近一次提交到版本库中的状态。<br>使用 svn revert 命令时，需要指定要还原的文件或目录的路径。如果指定的是文件路径，则该文件的本地修改将被撤销；如果指定的是目录路径，则该目录及其所有内容的本地修改都将被撤销。（本地修改会被永久丢弃）</p><p>8、svn diff<br>svn diff -rA<br>对比本地和任意版本A的差异<br>svn diff -rA:B<br>    对比任意历史版本A和任意历史版本B的差异，B相对于A新增或削减的内容</p><h1 id="十、Verilog"><a href="#十、Verilog" class="headerlink" title="十、Verilog"></a>十、Verilog</h1><h2 id="1-generate"><a href="#1-generate" class="headerlink" title="1 generate"></a>1 generate</h2><p>generate主要两种用法，第一是构造循环结构，例如多次实例化某个模块，或者是进行连线；第二种是通过if-generate或者case-generate来在多个代码块之间最多选择一个作为综合的rtl代码。<br>注意，generate for begin后面的名字是必须要有的，之后仿真器会通过这个标识来生成结构。</p><h2 id="2-A-B-或-A-B"><a href="#2-A-B-或-A-B" class="headerlink" title="2 [A+:B] 或 [A-:B]"></a>2 [A+:B] 或 [A-:B]</h2><p>一般形式是data[A+:B]或data[A-:B]，此时A是base，B是width。<br>表示的地址范围：<br>[A+:B] ——A<del>A+B-1;<br>[A-:B]——–A-B+1</del>A;<br>例如：a[3+:4]表示的就是a[6:3]，而a[7-:4]表示的就是a[7:4]，a[7-:5]表示的是a[7:3]<br>注：SV中a[7- :4]中间有空格会报错 。这里实际是个 等差数列。可以根据情况 写出通项找规律</p><p>注意：B必须是一个常量，若是变量或者运行中才可确认的表达式，编译器无法确认位宽且会报错。</p><h2 id="3-同步时钟与异步时钟"><a href="#3-同步时钟与异步时钟" class="headerlink" title="3 同步时钟与异步时钟"></a>3 同步时钟与异步时钟</h2><p>（1）同步时钟：数字设计中，频率相同或频率比为整数倍、且相位相同或相位差固定的两个时钟为同步时钟。<br>（2）异步时钟：时钟相位关系不可控制。</p><h2 id="4-跨时钟处理"><a href="#4-跨时钟处理" class="headerlink" title="4 跨时钟处理"></a>4 跨时钟处理</h2><p>跨时钟与处理：<br>多bit传输：异步FIFO<br>单bit传输：慢到快—延迟打拍；快到慢—握手协议</p><h1 id="十二、C语言"><a href="#十二、C语言" class="headerlink" title="十二、C语言"></a>十二、C语言</h1><h2 id="1-const-的用法"><a href="#1-const-的用法" class="headerlink" title="1 const 的用法"></a>1 const 的用法</h2><p>在C语言中，const是一个关键字，用于声明一个常量。通过使用const关键字，可以将变量声明为只读，即其值在初始化后不能被修改，否则编译器快速报错（好处）。例子：<br>函数参数中使用 const：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">printArray</span><span class="params">(<span class="type">const</span> <span class="type">int</span> arr[], <span class="type">int</span> size)</span> &#123;<span class="comment">//函数体&#125;</span></span><br></pre></td></tr></table></figure><p>在函数参数中使用const指示该参数是只读的，即函数内部不能修改该参数的值。在上述示例中，arr是一个指向int类型的常量数组，函数体内部不能修改数组元素的值。<br>const 修饰指针：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">int</span>* ptr; <span class="comment">//修饰常量，指针指向变量值不可变，指针指向的地址可变。</span></span><br><span class="line"><span class="type">int</span>* <span class="type">const</span> ptr; <span class="comment">//修饰指针，指针不能指向其它地址，指针指向的变量值可变。</span></span><br><span class="line"><span class="type">const</span> <span class="type">int</span>* <span class="type">const</span> ptr; <span class="comment">//常量指针指向常量。</span></span><br></pre></td></tr></table></figure><p>注意：const 关键字只是在编译时提供了一种静态的只读保证，但并不能完全阻止通过其他方式修改变量的值。</p><h2 id="2-malloc-内存分配"><a href="#2-malloc-内存分配" class="headerlink" title="2 malloc 内存分配"></a>2 malloc 内存分配</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">头文件：<span class="meta">#<span class="keyword">include</span><span class="string">&lt;malloc.h&gt;</span>或#<span class="keyword">include</span><span class="string">&lt;alloc.h&gt;</span></span></span><br><span class="line">原型：<span class="keyword">extern</span> <span class="type">void</span> *<span class="title function_">malloc</span><span class="params">(<span class="type">unsigned</span> <span class="type">int</span> num_bytes)</span>;</span><br></pre></td></tr></table></figure><p>功能：分配长度为num_bytes字节的内存块<br>说明：如果分配成功则返回指向被分配内存的指针，否则返回空指针NULL。返回类型是void<em>类型，表示未确定类型的指针，C&#x2F;C++规定，void</em>类型可以强制转换为任何其它类型的指针。当内存不再使用时，应使用free()函数将内存块释放。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">用法：<span class="type">int</span> *p; p=(<span class="type">int</span> *)<span class="built_in">malloc</span>(a); <span class="comment">//分配a大小字节的内存空间，并强制转换为int类型指针。</span></span><br></pre></td></tr></table></figure><h1 id="十一、小知识"><a href="#十一、小知识" class="headerlink" title="十一、小知识"></a>十一、小知识</h1><h2 id="1-质数"><a href="#1-质数" class="headerlink" title="1 质数"></a>1 质数</h2><p>质数是指在大于1的自然数中，除了1和本身以外，不再有其它因数。<br>2、CRC校验<br>循环冗余校验CRC（Cyclic Redundancy Check）是数据通信领域常用的一种数据传输检错技术。通过在发送端对数据按照某种算法计算出校验码，并将得到的校验码附在数据帧的后面，一起发送到接收端。接收端对收到的数据和校验码按照相同算法进行验证，以此判断接收到的数据是否正确、完整。<br>模2除法<br>下面以一个简单示例来展示CRC的计算过程：<br>以g(x)为CRC-4&#x3D;X4+X+1为例，此时除数P&#x3D;10011。假设源数据M为10110011。<br>在发送端将M左移4位，然后除以P。</p><p>发送端CRC计算示例</p><p>计算得到的余数就是0100，也就是CRC校验码。将0100附加到原始数据帧10110011后，组成新帧101100110100发送给接收端。接收端接收到该帧后，会用该帧去除以上面选定的除数P，验证余数是否为0，如果为0，则表示数据在传输过程中没有出现差错。</p><p>接收端CRC校验示例</p><p>的CRC校验码生成：<br>1、通过工具生成的Verilog代码，信元头不使用，提取payload<br>2、有一个old_crc，其表示上一次进行运算生成的CRC码，即new_crc<br>3、new_crc会作为下一次的old_crc，再与flit进行运算（信元存在多个flit），又得到new_crc<br>4、直到最后一个flit后，得到的new_crc即为CRC校验码。</p><p>接收方得到接收数据后，按照相同的处理方式进行CRC比较即可。（不像网上那样，网上是将数据+CRC一起去与除数进行除，最后得到零则表示正确。依公司而定）</p><p>3、ECC校验<br>xxxxx need study<br>4、NA<br>NA：Not Applicable(N&#x2F;A)表示不适用。<br>5、Xprop检查<br>（1）-xprop：X态传播（X-propagation）。<br>（2）verilog和VHDL RTL仿真器会忽略控制信号上的X不定态，在输出上会分配一个固定的数值。由于缺少X的传播，RTL仿真器往往无法检测到和X态相关的设计问题。<br>（3）-xprop用来解决控制信号x态暴露问题的。<br>（4）Standard RTL simulations ignore the uncertainty of X-valued control signals and assign predictable output values. As a result, RTL simulations often fail to detect design problems related to the lack of X-Propagation. However, the same design problems can be detected in gate-level simulations. With X-Propagation support in RTL simulations, engineers can save time and effort in debugging differences between RTL and gate-level simulation results.—user guide<br>翻译：标准RTL模拟忽略X值控制信号的不确定性，并分配可预测的输出值。结果，RTL模拟经常不能检测到与缺乏X传播相关的设计问题。然而，在门级仿真中可以检测到相同的设计问题。借助RTL模拟中的X传播支持，工程师可以节省调试RTL和门级模拟结果之间差异的时间和精力</p><p>注意：若仿真波形出现X态，则需要找到X态传播的根源，以解决X态问题。<br>6、表格操作<br>1、表格填充相同数据<br>鼠标拖动法：在数据区域起始单元格中输入需要的数据，然后移动鼠标至该单元格右下角，会出现黑色的小十字光标，之后拖动到其它单元格就可以实现相同数据填充了。<br>命令法：在数据区域的起始单元格输入需要的数据，再选择需要的单元格，点击“开始”菜单选项卡，找到“填充”命令，在选择对应填充命令。<br>2、表格筛选相同元素的行<br>先选着需要筛选的列，然后在开始选项下选“排序与筛选”下的筛选，之后再根据筛选，选择要筛选的内容即可。</p><p>7、stopat方法<br>在芯片设计中，”stopat” 是一种用于处理内部信号的调试工具。它允许设计工程师在测试环境中指定一个特定的时钟周期或事件，以停止芯片的运行。当芯片达到指定的时钟周期或事件时，它会停止执行，并且可以提供有关芯片状态的信息，例如寄存器的值、信号的状态等。<br>“stopat” 是一种调试工具，通常在测试环境中使用，而不是在最终产品中。它提供了一种方便的方法来观察和分析芯片的内部行为，但在实际产品中不会使用这种调试功能。<br>8、X86和X64的区别<br>X86就是一般用的32位的系统，而X64就是64位的系统。<br>9、clock_gate的作用<br>    “clock_gate” 是一种电路设计技术，用于控制时钟信号的传递，以实现功耗优化和电路性能改进。它的作用是在特定条件下关闭或打开时钟信号的传递，从而控制电路的工作状态。<br>以下是 clock_gate 技术的一些作用和优势：<br>1、功耗优化：通过控制时钟信号的传递，clock_gate 技术可以降低电路的功耗。当电路处于空闲或不需要工作的状态时，可以关闭时钟信号的传递，从而减少电路的功耗。<br>2、时钟域划分：clock_gate 技术可以用于实现时钟域划分，将电路划分为多个时钟域，并根据需要控制时钟信号在不同时钟域之间的传递。这有助于提高电路的可靠性和时序性能。<br>3、动态电源管理：通过控制时钟信号的传递，clock_gate 技术可以与动态电源管理（Dynamic Power Management）技术结合使用，实现对电路的动态功耗管理和调整。<br>4、时钟门控：clock_gate 技术可以用于实现时钟门控（Clock Gating），即根据特定的逻辑条件控制时钟信号的传递。这可以提高电路的能效和性能，并减少功耗。<br>总的来说，clock_gate 技术通过控制时钟信号的传递，实现功耗优化、时钟域划分、动态电源管理和时钟门控等功能<br>10、NOC网络</p><p>11、热插拔<br>12、大型组网验证方法<br>一个大型SOC进行仿真，因服务器资源、CPU核数等原因，仿真时长不可预估，大都可以使用如下方法进行加速仿真。<br>1）将大型TB进行拆分，分为TB1，TB2，TB3等等，TB1的输出数据存储进文件1，TB2的输入数据为TB1的输出数据，同理TB3的输入数据为TB2的输出数据。<br>2）由于CPU的客观原因，TB1、TB2和TB3的仿真时间不能同步，即TB间传输可能数据出现X态，因此使用一种同步方法，即TB1、TB2和TB3的数据传输需要保证在一个时间内，当某个TBx仿真快时，需要停止对应TBx的仿真，使其等待较慢的TBy，以此来实现TB间的同步。<br>13、静态验证和动态验证的区别<br>1、动态验证方法是在运行设计的情况下对其进行验证的方法。在硬件设计验证中，动态验证通常指的是通过模拟器执行测试程序，检查设计的行为是否符合预期。<br>仿真验证（Simulation Verification）：仿真验证是最常见的动态验证方法之一。通过在仿真器中执行测试程序，驱动输入信号到设计中，并检查输出信号是否符合预期。仿真验证可以帮助验证设计的功能性和时序行为。<br>1）随机测试（Random Testing）：随机测试是一种动态验证方法，通过生成随机输入序列来测试设计的行为。随机测试可以帮助发现设计中的边界条件错误和意外情况。<br>2）约束随机测试（Constrained Random Testing）：约束随机测试是在随机测试的基础上引入约束条件，以确保生成的测试序列覆盖设计的关键功能和场景。约束随机测试可以提高测试覆盖率。<br>3）事务级建模（Transaction-Level Modeling）：事务级建模是一种动态验证方法，通过建模设计的高层事务行为来验证设计的功能性。事务级建模可以帮助简化测试环境的开发和提高仿真效率。<br>4）功能覆盖率分析（Functional Coverage Analysis）：功能覆盖率分析是一种动态验证方法，用于评估测试用例对设计功能的覆盖程度。通过分析功能覆盖率，可以确定测试用例是否足够全面地覆盖了设计的功能。<br>5）时序分析（Timing Analysis）：时序分析是一种动态验证方法，用于验证设计的时序要求是否得到满足。时序分析可以帮助检测时序违例和时序故障。</p><p>2、静态验证是一种在不运行设计的情况下对设计进行验证的方法。它通常涉及对设计本身的分析、检查和验证，以发现设计中的潜在问题和错误。<br>1）代码审查（Code Review）：代码审查是一种静态验证方法，通过审查设计文档、源代码或规范来发现潜在的设计错误、风险和不一致性。代码审查可以由团队成员、同行或专门的审查团队进行。<br>2）静态代码分析（Static Code Analysis）：静态代码分析是使用自动化工具对源代码进行分析，以检测潜在的编程错误、代码质量问题和安全漏洞。这种方法可以帮助发现代码中的潜在问题，如未定义的行为、内存泄漏、未使用的变量等。<br>形式验证（Formal Verification）：形式验证是一种基于数学推理的验证方法，用于验证设计是否满足特定的性质或规范。形式验证可以帮助发现设计中的功能性错误、死锁、活锁等问题。<br>3）模型检查（Model Checking）：模型检查是一种自动化验证技术，用于检查设计模型是否满足特定的性质。模型检查通常用于有限状态系统的验证，可以帮助发现设计中的状态空间爆炸问题和性质违反。<br>4）静态分析工具（Static Analysis Tools）：静态分析工具是一种自动化工具，用于对设计文档、规范或代码进行静态分析，以发现潜在的问题和错误。这些工具可以帮助提高设计的质量和可靠性。<br>14 、查看代码行数<br>cloc全称：count lines of code，它是一款使用Perl语言开发的开源代码统计工具。<br>使用方法：cloc *.v或者cloc .&#x2F;</p><p>工具位置：&#x2F;ic&#x2F;tools&#x2F;cloc&#x2F;1.64&#x2F;bin&#x2F;cloc<br>15、RR代码思路<br>第一种：固定时隙RR<br>此RR轮询只需要if…else if….else if….else即可满足，且每次记录下一次需要调度的通道即可，另外也可以使用case….endcase的方法，都是类似的，重点是记录下一次调度的通道。<br>伪代码：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(chan == <span class="number">0</span>)<span class="keyword">begin</span></span><br><span class="line">chan = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">if</span>(chan == <span class="number">1</span>)<span class="keyword">begin</span></span><br><span class="line">chan = <span class="number">2</span>;</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">if</span>……</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>第二种：RR轮询<br>此RR轮询每拍需要调度一个有效通道，因此可以按如下步骤进行编码：<br>1）先判断哪些通道有效（可以与&amp;&amp;上反压等情况）。</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(chan1 || chan2 || chan3 ||…..)</span><br></pre></td></tr></table></figure><p>2）若存在有效通道，则进入while(1)循环，语句块内可以case….endcase来循环有效通道，找到可输出的有效通道后，记录下一次调度的通道，退出while循环。<br>&#x2F;&#x2F;while(1) case 找到有效通道，记录下一次通道，break循环。endcase</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(<span class="number">1</span>)<span class="keyword">begin</span></span><br><span class="line"><span class="keyword">case</span>(chan)</span><br><span class="line">chan1:<span class="keyword">if</span>(chan1…) chan = <span class="number">2</span>; <span class="keyword">break</span>; <span class="keyword">else</span>….</span><br><span class="line">chan2:<span class="keyword">if</span>(chan2…) chan = <span class="number">3</span>; <span class="keyword">break</span>; <span class="keyword">else</span>….</span><br><span class="line">……….</span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>3）新开始一次。<br>16、WRR代码思路<br>以项目的WRR代码来阐述，步骤如下：<br>1）判断哪些通道有效，哪些通道权重未达到。<br>2）通道有效且通道权重未达到，则优先调度输出，否则依次调度，占用共享权重。同时记录下次调度的通道。<br>3）总权重达标可重置权重<br>以下述代码为例：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//0:权重达到上限,1:权重没达到上限</span></span><br><span class="line">wrr_count_en[<span class="number">0</span>] = (weight_cnt[<span class="number">0</span>] &lt; weight[<span class="number">0</span>]) ? <span class="number">1&#x27;b1</span> : <span class="number">1&#x27;b0</span>; </span><br><span class="line">wrr_count_en[<span class="number">1</span>] = (weight_cnt[<span class="number">1</span>] &lt; weight[<span class="number">1</span>]) ? <span class="number">1&#x27;b1</span> : <span class="number">1&#x27;b0</span>;</span><br><span class="line">wrr_count_en[<span class="number">2</span>] = (weight_cnt[<span class="number">2</span>] &lt; weight[<span class="number">2</span>]) ? <span class="number">1&#x27;b1</span> : <span class="number">1&#x27;b0</span>;</span><br><span class="line">median = ((enable &amp; wrr_count_en) &gt;= <span class="number">1</span>) ? <span class="number">2&#x27;b11</span> : <span class="number">2&#x27;b10</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">3</span>; i++) <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">if</span>(&#123;enable[wrr_last_sel],wrr_count_en[wrr_last_sel]&#125; &gt;= median)<span class="keyword">begin</span></span><br><span class="line">        weight_cnt[wrr_last_sel] = weight_cnt[wrr_last_sel] + <span class="number">1&#x27;b1</span>;</span><br><span class="line">        plane_sel = wrr_last_sel; <span class="comment">//调度的通道</span></span><br><span class="line">        wrr_last_sel = (wrr_last_sel &gt;= <span class="number">2</span>) ? <span class="number">0</span> : wrr_last_sel+ <span class="number">1&#x27;b1</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line">wrr_last_sel = (wrr_last_sel &gt;= <span class="number">2</span>) ? <span class="number">0</span> : wrr_last_sel + <span class="number">1&#x27;b1</span>;</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>17、XML文件<br>XML（可扩展标记语言）是一种用于标记电子文档结构的通用标记语言。它是一种可扩展的标记语言，旨在提高数据的可读性，并且支持数据的结构化描述。XML 主要用于在计算机系统之间传输和存储数据，以及在不同系统之间共享结构化数据。<br>以下是 XML 文件的一些特点：<br>标记性：XML 使用标记来描述数据的结构和含义。标记以尖括号 &lt; &gt; 来表示，并且标记可以嵌套在彼此之内，形成层次结构。<br>可读性：XML 使用文本格式编写，便于人类阅读和创建。XML 文件中的标签和属性通常使用英语单词或自定义标识符，使得数据结构更易于理解。<br>扩展性：XML 具有灵活性，因为它是可扩展的。用户可以定义自己的标记来适应特定的应用程序或数据需求。<br>通用性：XML 不依赖于任何特定的领域或平台，并因此被广泛用于各种领域，如Web开发、数据交换、配置文件等。<br>在软件开发中，XML 文件常用于配置文件、数据交换、Web服务通信等。许多标准的数据交换格式（如RSS、SOAP等）和文档格式（如OpenDocument、SVG等）都使用 XML。<br>18、两数大小判断</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span>[N:<span class="number">0</span>] a,b;</span><br><span class="line"><span class="keyword">bit</span>[N:<span class="number">0</span>] c;</span><br><span class="line">c = a - b;</span><br></pre></td></tr></table></figure><p>若c[N]&#x3D;0，则a&gt;b；反之若c[N]&#x3D;1，则a&lt;b；<br>举例子：a&#x3D;4’b0011，b&#x3D;4’b1101，则a-b&#x3D;4’b0110;<br>（计算方式1：3-13&#x3D;-10—–&gt;11010—-&gt;10101—-&gt;10110——&gt;0110）<br>（计算方式2：通过二进制计算计算）</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">0011</span><br><span class="line">1101</span><br><span class="line">0110 </span><br></pre></td></tr></table></figure><p>第0位：1-1&#x3D;0；<br>第1位：1-0&#x3D;1；<br>第2位：0-1+2（向第3位借位2’b10）&#x3D;1；<br>第3位：0-1-1（被第2位借位）+2（向第4位借位2’b10）&#x3D;0</p><p>19、中断测试<br>1、断言检查；2、特殊用例检查（一定会出现，直接检查）；3、时序模型</p><p>20、Gbps计算<br>1）比特&#x2F;秒（bps）：最基本的单位，表示每秒传输的比特数量。<br>2）千比特&#x2F;秒（kbps）：表示每秒传输的千比特数量，通常用于测量较慢的互联网连接速度。<br>3）兆比特&#x2F;秒（Mbps）：表示每秒传输的百万比特数量，通常用于衡量较快的互联网连接速度。<br>4）千兆比特&#x2F;秒（Gbps）：表示每秒传输的十亿比特数量，通常用于衡量高速互联网连接或局域网（LAN）速度<br>5）太比特&#x2F;秒（Tbps）：表示每秒传输的万亿比特数量，通常用于描述极高速网络连接的速度。</p><p>计算方法：数据量&#x2F;时间<br>eg：12个clk中，发送数据量322B，时钟频率1.2GHz<br>则Gbp的计算公式：（322<em>8）&#x2F;（12</em>0.833）</p><p>常用换算（以每 clk 发送 N 字节为例）：</p><ul><li>时钟周期：<code>Tclk = 1 / Fclk</code></li><li>吞吐（Gbps）：<code>Gbps = N * 8 * Fclk / 1e9</code></li><li>包转发率（pps）：<code>pps = Fclk / 每包消耗clk数</code></li><li>由包转发率得到吞吐：<code>Gbps = pps * 每包字节数 * 8 / 1e9</code></li></ul><p>Mpps 说明：</p><ul><li>pps：packets per second，每秒转发包数</li><li>Mpps：Mega pps，<code>1 Mpps = 1e6 pps</code></li><li>Gpps：Giga pps，<code>1 Gpps = 1e9 pps = 1000 Mpps</code></li><li>从 Mpps 换算吞吐（Gbps）：<code>Gbps = Mpps * 每包字节数 * 8 / 1000</code></li><li>例：<code>500 Mpps</code>、每包 <code>528 B</code>，则 <code>Gbps = 500 * 528 * 8 / 1000 = 2112 Gbps</code></li></ul><p>288B 入口 data bus 计算例子（假设单入口同一时刻只发一个包，不做多包拼接）：</p><ul><li>bus 宽度：<code>W = 288 B/clk</code></li><li>包头：<code>H = 16 B</code></li><li>payload：P 随机 64~512 B</li><li>每包消耗 clk 数：<code>Nclk = ceil((H + P) / W)</code></li><li>总线利用率：<code>Util = (H + P) / (Nclk * W)</code></li><li>总线有效吞吐（含包头，Gbps）：<code>Gbps_total = (H + P) * 8 * Fclk / (Nclk * 1e9)</code></li><li>payload 吞吐（不含包头，Gbps）：<code>Gbps_payload = P * 8 * Fclk / (Nclk * 1e9)</code></li></ul><p>Case A：payload &#x3D; 512B</p><ul><li>每包总字节：<code>H + P = 16 + 512 = 528 B</code></li><li><code>Nclk = ceil(528 / 288) = 2 clk</code></li><li>第 1 拍：发送 288 B（满拍）</li><li>第 2 拍：发送剩余 <code>528 - 288 = 240 B</code>（未填满，空余 <code>288 - 240 = 48 B</code>）</li><li><code>Util = 528 / (2 * 288) = 91.67%</code></li><li><code>pps = Fclk / 2</code>；若 <code>Fclk = 1GHz</code>，则 <code>pps = 500 Mpps</code></li><li>若 <code>Fclk = 1GHz</code>：<code>Gbps_total = 528 * 8 / 2 = 2112 Gbps</code>；<code>Gbps_payload = 512 * 8 / 2 = 2048 Gbps</code></li></ul><p>Case B：payload &#x3D; 64B</p><ul><li>每包总字节：<code>H + P = 16 + 64 = 80 B</code></li><li><code>Nclk = ceil(80 / 288) = 1 clk</code></li><li>1 拍内仅占用 80 B，有 <code>288 - 80 = 208 B</code> 空余</li><li><code>Util = 80 / 288 = 27.78%</code></li><li><code>pps = Fclk / 1 = Fclk</code>；若 <code>Fclk = 1GHz</code>，则 <code>pps = 1000 Mpps</code></li><li>若 <code>Fclk = 1GHz</code>：<code>Gbps_total = 80 * 8 = 640 Gbps</code>；<code>Gbps_payload = 64 * 8 = 512 Gbps</code></li></ul><p>数通芯片常说的“线速 &#x2F; wire speed”：</p><ul><li>线速通常指端口在给定协议开销下，能够在不丢包&#x2F;不阻塞的前提下持续跑满“物理线上的速率”</li><li>需要区分三类速率：<code>line rate(物理层)</code>、<code>throughput(链路层/总线层含开销)</code>、<code>goodput(payload有效负载)</code></li><li>对于串行 SerDes：<code>line_rate = baud_rate * bits_per_symbol * lanes</code></li><li>编码与 FEC 会吃掉有效带宽：<code>goodput ≈ line_rate * coding_eff * fec_eff * protocol_eff</code><ul><li><code>64b/66b</code> 编码效率 <code>coding_eff = 64/66</code></li><li><code>8b/10b</code> 编码效率 <code>coding_eff = 8/10</code></li></ul></li></ul><p>以以太网口为例的“线速转发率（Mpps）”思路：</p><ul><li>以太网 wire 上除了帧本体，还包含 <code>preamble+SFD(8B)</code> 与 <code>IFG(12B)</code></li><li>最小帧长 <code>64B</code>（包含 FCS，不含 preamble&#x2F;IFG），则 wire 上每帧占用 <code>84B</code></li><li>若端口线速为 <code>R bps</code>，最小包线速转发率：<code>pps_wire = R / (84 * 8)</code><ul><li><code>10GbE</code>：<code>pps_wire = 10e9 / (84*8) = 14.88 Mpps</code></li><li><code>100GbE</code>：<code>pps_wire = 100e9 / (84*8) = 148.8 Mpps</code></li></ul></li><li>帧变大（例如 1518B&#x2F;9KB jumbo）时，<code>pps</code> 下降，但 <code>payload goodput</code> 更接近 <code>line rate</code></li></ul><p>IC 验证环境中（UVM）如何处理“线速&#x2F;性能”：</p><ul><li>明确测量口径：<code>Gbps_total(含包头/协议字段)</code>、<code>Gbps_payload(仅payload)</code>、<code>pps/Mpps</code>、<code>Util</code>，统一放到同一张统计表</li><li>激励侧按目标速率发包：<ul><li>接口按 <code>valid/ready</code> 时序驱动时，用 driver 在每个 clk 根据目标 <code>Util/pps</code> 决定是否发起新包</li><li>多流量场景用 virtual sequence 控制包长分布（64~512B）、突发&#x2F;间隔、不同流的比例</li></ul></li><li>监测侧统计速率：<ul><li>monitor 按握手成功计数：<code>beat_bytes</code>、<code>pkt_cnt</code>、<code>cycle_cnt</code>，按窗口（例如每 N 个 clk）或按包结束计算 <code>Gbps/Mpps/Util</code></li><li>若 DUT 有性能计数器（吞吐&#x2F;丢包&#x2F;背压周期），在 scoreboard 对齐“软件计数 vs 硬件计数”</li></ul></li><li>判定“线速”是否达成：<ul><li>在无背压、输入持续有效的条件下，检查 <code>output pps/Gbps</code> 是否达到理论上限的某个阈值（例如 ≥ 99%）</li><li>在有背压&#x2F;拥塞场景下，检查丢包策略、队列深度、ECN&#x2F;mark 等是否符合 spec</li></ul></li></ul><p>UVM 统计计算示例（monitor 内按 cycle 统计）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">longint</span> <span class="keyword">unsigned</span> byte_cnt;</span><br><span class="line"><span class="keyword">longint</span> <span class="keyword">unsigned</span> cycle_cnt;</span><br><span class="line"><span class="keyword">longint</span> <span class="keyword">unsigned</span> pkt_cnt;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> sample_beat(<span class="keyword">int</span> <span class="keyword">unsigned</span> beat_bytes, <span class="keyword">bit</span> eop);</span><br><span class="line">  byte_cnt += beat_bytes;</span><br><span class="line">  <span class="keyword">if</span> (eop) pkt_cnt++;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> sample_cycle();</span><br><span class="line">  cycle_cnt++;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">real</span> calc_gbps_total(<span class="keyword">real</span> fclk_hz);</span><br><span class="line">  <span class="keyword">if</span> (cycle_cnt == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">  <span class="keyword">return</span> (byte_cnt * <span class="number">8</span><span class="variable">.0</span> * fclk_hz) / (cycle_cnt * <span class="number">1</span>e9);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">real</span> calc_mpps(<span class="keyword">real</span> fclk_hz);</span><br><span class="line">  <span class="keyword">if</span> (cycle_cnt == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">  <span class="keyword">return</span> (pkt_cnt * fclk_hz) / (cycle_cnt * <span class="number">1</span>e6);</span><br><span class="line"><span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><p>21、CDC验证<br>1、主要通过正向形式化验证工具进行检查（如spyglass）</p><p>22、命名规则<br>1、字母、数字和下划线组成变量名，数字不能为变量名首。</p><p>23、fanout扇出<br>定义：扇出（Fanout） 是指一个信号驱动的下游负载（loads）数量，即该信号连接到多少个其他逻辑单元或寄存器的输入端。</p><p>扇出影响：</p><ol><li>时序影响：高扇出信号会导致信号延迟增加，因为驱动大负载需要更大的驱动能力。可能造成setup&#x2F;hold违例（violation）。</li><li>功耗影响：高扇出信号会增加开关活动（switching activity），从而增加动态功耗。</li><li>综合与布局布线（P&amp;R）影响：综合工具通常会对高扇出信号插入缓冲器（buffer）或驱动单元（drive cell），以改善驱动能力。<br>其它：<br>（1）反压与跨级反压需注意，反压后数据能否合理吸收进缓存。<br>（2）NoC的全称network on chip，NoC网络中的每一个节点是一个单独的路由器模块； 同一类的路由器节点组成一个路由网络。<br>（3）filelist中，-f是针对文件夹的，若.v则不用-f（否则报错）</li></ol><p>24、UVM&#x2F;SV 在 IC 验证（数通芯片）常见处理<br>1）延时（latency）统计口径</p><ul><li>常见定义：从 ingress（输入口）<code>sop</code> 握手成功到 egress（输出口）<code>sop/eop</code> 握手成功的时间差</li><li>度量单位：cycle 或 time（推荐 cycle，便于跨时钟频率对齐）</li><li>关键点：必须有可匹配的 <code>pkt_id</code>（或 <code>&#123;src_port,dst_port,seq_id&#125;</code> 组合键），否则无法做端到端关联</li></ul><p>2）包转发率（pps&#x2F;Mpps）与吞吐（Gbps）统计口径</p><ul><li><code>pps = pkt_cnt / time_window_s</code></li><li><code>Mpps = pps / 1e6</code></li><li><code>Gbps_total = byte_cnt_total * 8 / time_window_s / 1e9</code></li><li><code>Gbps_payload = byte_cnt_payload * 8 / time_window_s / 1e9</code></li><li>对于 valid&#x2F;ready 总线，建议以“握手成功”为准计数（<code>valid &amp;&amp; ready</code>），避免把 backpressure 期间的无效周期计入吞吐</li></ul><p>3）credit（信用）与背压常见处理</p><ul><li>credit-based flow control 的基本约束：发送端消耗 credit，接收端在释放 buffer 后返还 credit</li><li>检查点：credit 不得为负；返还 credit 不得超过上限；在无异常注入时不应出现 credit 泄漏导致吞吐归零</li><li>常见 bug：包长&#x2F;beat 计算错误导致 credit 扣减不匹配；多 VC&#x2F;多端口 credit 串线；reset&#x2F;flush 时 credit 未对齐</li></ul><p>4）UVM 里常见落地方式（建议）</p><ul><li>monitor：负责组包（beat-&gt;packet）、标注 <code>sop/eop/byte_cnt/pkt_id</code>、通过 analysis_port 广播</li><li>scoreboard&#x2F;perf 组件：做端到端匹配与统计，输出 <code>min/avg/max/p99 latency</code>、<code>Gbps/Mpps/Util</code>，并与 DUT 性能计数器对齐</li><li>virtual sequence：控制包长分布、突发&#x2F;间隔、背压&#x2F;拥塞、不同流比例，形成可重复的性能回归用例</li></ul><p>代码片段写在哪儿（建议）：</p><ul><li><code>perf_win</code>：放在 perf 统计组件（scoreboard 或独立 perf_subscriber）里；monitor 只负责把每个包的 <code>bytes_total/bytes_payload</code> 与 <code>eop</code> 等信息通过 analysis_port 发出来</li><li><code>latency_stat</code>：放在 scoreboard&#x2F;perf 组件里（需要 ingress&#x2F;egress 两边的观测点做匹配）；ingress_monitor&#x2F;egress_monitor 各自上报 <code>pkt_id</code>，在同一组件里做端到端关联</li><li><code>credit_chk</code>：放在“能看到 credit 扣减&#x2F;返还”的那一侧 monitor 或 scoreboard<ul><li>若 credit 是接口级显式信号（credit_valid&#x2F;credit_cnt），放在对应 monitor 里直接做合法性检查</li><li>若 credit 是协议语义（由 buffer&#x2F;ready&#x2F;返还包隐式表达），放在 scoreboard&#x2F;perf 组件里根据观测到的行为推导并检查</li></ul></li><li><code>sample_cycle()</code> 的调用位置：放在对应组件的 <code>run_phase/main_phase</code> 里，每个 <code>posedge clk</code> 调一次（或按你定义的 window 节拍调）</li></ul><p>具体落地做法（推荐工程结构）：</p><ul><li>env 里创建 <code>perf_stat</code> 常驻组件，并把 ingress&#x2F;egress monitor 的 analysis_port 都 connect 进来</li><li>普通功能 case：<code>perf_enable=1</code> 只做统计并 report（不做阈值失败）</li><li>性能 case：<code>perf_enable=1</code> + <code>perf_check_enable=1</code> + 配好目标 <code>expected_gbps/expected_mpps/latency_limit</code>，在窗口或结束时判定达标</li></ul><p>代码骨架：perf&#x2F;stat 组件（放 env 下，接收 monitor 广播，并自己跑时钟 tick）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">`uvm_analysis_imp_decl(_ing)</span><br><span class="line">`uvm_analysis_imp_decl(_egr)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> perf_stat <span class="keyword">extends</span> uvm_component;</span><br><span class="line">  `uvm_component_utils(perf_stat)</span><br><span class="line"></span><br><span class="line">  uvm_analysis_imp_ing<span class="variable">#(my_pkt, perf_stat)</span> ing_imp;</span><br><span class="line">  uvm_analysis_imp_egr<span class="variable">#(my_pkt, perf_stat)</span> egr_imp;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> my_if vif;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">bit</span>  enable;</span><br><span class="line">  <span class="keyword">bit</span>  check_enable;</span><br><span class="line">  <span class="keyword">int</span> <span class="keyword">unsigned</span> window_cycles;</span><br><span class="line">  <span class="keyword">real</span> fclk_hz;</span><br><span class="line">  <span class="keyword">real</span> expected_gbps_min;</span><br><span class="line">  <span class="keyword">real</span> expected_mpps_min;</span><br><span class="line"></span><br><span class="line">  perf_win      win;</span><br><span class="line">  latency_stat  lat;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name, uvm_component parent);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    ing_imp = <span class="keyword">new</span>(<span class="string">&quot;ing_imp&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    egr_imp = <span class="keyword">new</span>(<span class="string">&quot;egr_imp&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(virtual my_if)::get(this, &quot;&quot;, &quot;vif&quot;, vif))</span>;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(bit)::get(this, &quot;&quot;, &quot;perf_enable&quot;, enable))</span>;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(bit)::get(this, &quot;&quot;, &quot;perf_check_enable&quot;, check_enable))</span>;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(int unsigned)::get(this, &quot;&quot;, &quot;perf_window_cycles&quot;, window_cycles))</span>;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(real)::get(this, &quot;&quot;, &quot;perf_fclk_hz&quot;, fclk_hz))</span>;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(real)::get(this, &quot;&quot;, &quot;perf_expected_gbps_min&quot;, expected_gbps_min))</span>;</span><br><span class="line">    <span class="keyword">void</span>&#x27;(uvm_config_db<span class="variable">#(real)::get(this, &quot;&quot;, &quot;perf_expected_mpps_min&quot;, expected_mpps_min))</span>;</span><br><span class="line">    <span class="keyword">if</span> (window_cycles == <span class="number">0</span>) window_cycles = <span class="number">10000</span>;</span><br><span class="line">    <span class="keyword">if</span> (fclk_hz == <span class="number">0</span><span class="variable">.0</span>) fclk_hz = <span class="number">1</span><span class="variable">.0e9</span>;</span><br><span class="line">    win = <span class="keyword">new</span>(fclk_hz);</span><br><span class="line">    lat = <span class="keyword">new</span>();</span><br><span class="line">    win<span class="variable">.reset</span>();</span><br><span class="line">    lat<span class="variable">.reset</span>();</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.run_phase</span>(phase);</span><br><span class="line">    <span class="keyword">if</span> (!enable) <span class="keyword">return</span>;</span><br><span class="line">    <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">      @(<span class="keyword">posedge</span> vif<span class="variable">.clk</span>);</span><br><span class="line">      win<span class="variable">.sample_cycle</span>();</span><br><span class="line">      lat<span class="variable">.sample_cycle</span>();</span><br><span class="line">      <span class="keyword">if</span> (win<span class="variable">.cycle_cnt</span> &gt;= window_cycles) <span class="keyword">begin</span></span><br><span class="line">        report_window();</span><br><span class="line">        win<span class="variable">.reset</span>();</span><br><span class="line">      <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">endtask</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> write_ing(my_pkt pkt);</span><br><span class="line">    lat<span class="variable">.on_ingress</span>(pkt<span class="variable">.pkt_id</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> write_egr(my_pkt pkt);</span><br><span class="line">    win<span class="variable">.sample_pkt</span>(pkt<span class="variable">.bytes_total</span>, pkt<span class="variable">.bytes_payload</span>);</span><br><span class="line">    lat<span class="variable">.on_egress</span>(pkt<span class="variable">.pkt_id</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> report_window();</span><br><span class="line">    <span class="keyword">real</span> gbps;</span><br><span class="line">    <span class="keyword">real</span> mpps;</span><br><span class="line">    gbps = win<span class="variable">.calc_gbps_total</span>();</span><br><span class="line">    mpps = win<span class="variable">.calc_mpps</span>();</span><br><span class="line">    `uvm_info(<span class="string">&quot;PERF&quot;</span>, <span class="built_in">$sformatf</span>(<span class="string">&quot;win: Gbps_total=%.3f Mpps=%.3f avg_lat(cyc)=%.3f&quot;</span>, gbps, mpps, lat<span class="variable">.avg_latency_cyc</span>()), UVM_LOW)</span><br><span class="line">    <span class="keyword">if</span> (check_enable) <span class="keyword">begin</span></span><br><span class="line">      <span class="keyword">if</span> ((expected_gbps_min &gt; <span class="number">0</span><span class="variable">.0</span>) &amp;&amp; (gbps &lt; expected_gbps_min)) `uvm_error(<span class="string">&quot;PERF&quot;</span>, <span class="string">&quot;Gbps below expected&quot;</span>)</span><br><span class="line">      <span class="keyword">if</span> ((expected_mpps_min &gt; <span class="number">0</span><span class="variable">.0</span>) &amp;&amp; (mpps &lt; expected_mpps_min)) `uvm_error(<span class="string">&quot;PERF&quot;</span>, <span class="string">&quot;Mpps below expected&quot;</span>)</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>env 里创建与连接（示意）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> my_env <span class="keyword">extends</span> uvm_env;</span><br><span class="line">  `uvm_component_utils(my_env)</span><br><span class="line">  my_agent  agt;</span><br><span class="line">  perf_stat perf;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    agt  = my_agent::type_id::create(<span class="string">&quot;agt&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    perf = perf_stat::type_id::create(<span class="string">&quot;perf&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> connect_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.connect_phase</span>(phase);</span><br><span class="line">    agt<span class="variable">.ing_mon</span><span class="variable">.ap</span><span class="variable">.connect</span>(perf<span class="variable">.ing_imp</span>);</span><br><span class="line">    agt<span class="variable">.egr_mon</span><span class="variable">.ap</span><span class="variable">.connect</span>(perf<span class="variable">.egr_imp</span>);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>test 里区分“功能 case &#x2F; 性能 case”的配置（示意）</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> perf_test <span class="keyword">extends</span> uvm_test;</span><br><span class="line">  `uvm_component_utils(perf_test)</span><br><span class="line">  my_env env;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    env = my_env::type_id::create(<span class="string">&quot;env&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    uvm_config_db<span class="variable">#(bit)::set(this, &quot;env.perf&quot;, &quot;perf_enable&quot;, 1)</span>;</span><br><span class="line">    uvm_config_db<span class="variable">#(bit)::set(this, &quot;env.perf&quot;, &quot;perf_check_enable&quot;, 0)</span>;</span><br><span class="line">    uvm_config_db<span class="variable">#(int unsigned)::set(this, &quot;env.perf&quot;, &quot;perf_window_cycles&quot;, 10000)</span>;</span><br><span class="line">    uvm_config_db<span class="variable">#(real)::set(this, &quot;env.perf&quot;, &quot;perf_fclk_hz&quot;, 1.0e9)</span>;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> perf_line_rate_test <span class="keyword">extends</span> perf_test;</span><br><span class="line">  `uvm_component_utils(perf_line_rate_test)</span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    uvm_config_db<span class="variable">#(bit)::set(this, &quot;env.perf&quot;, &quot;perf_check_enable&quot;, 1)</span>;</span><br><span class="line">    uvm_config_db<span class="variable">#(real)::set(this, &quot;env.perf&quot;, &quot;perf_expected_gbps_min&quot;, 2000.0)</span>;</span><br><span class="line">    uvm_config_db<span class="variable">#(real)::set(this, &quot;env.perf&quot;, &quot;perf_expected_mpps_min&quot;, 500.0)</span>;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><p>5）代码片段：按 cycle 统计 Gbps&#x2F;Mpps（滑窗&#x2F;区间统计）</p><ul><li>在哪儿调用：<ul><li><code>sample_cycle()</code>：在 perf&#x2F;stat 组件（或某个 monitor）的 <code>run_phase/main_phase</code> 时钟线程里，每拍 <code>@(posedge clk)</code> 调一次</li><li><code>sample_pkt(bytes_total, bytes_payload)</code>：在“看到包完整输出”的地方调用，通常是 egress_monitor 组包完成（<code>eop</code>）后，通过 analysis_port 把 pkt 发给 perf&#x2F;stat，perf&#x2F;stat 的 <code>write_egr(pkt)</code> 内调用<figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> perf_win;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> byte_cnt_total;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> byte_cnt_payload;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> pkt_cnt;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> cycle_cnt;</span><br><span class="line">  <span class="keyword">real</span> fclk_hz;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">real</span> fclk_hz);</span><br><span class="line">    <span class="keyword">this</span><span class="variable">.fclk_hz</span> = fclk_hz;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> reset();</span><br><span class="line">    byte_cnt_total = <span class="number">0</span>;</span><br><span class="line">    byte_cnt_payload = <span class="number">0</span>;</span><br><span class="line">    pkt_cnt = <span class="number">0</span>;</span><br><span class="line">    cycle_cnt = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> sample_cycle();</span><br><span class="line">    cycle_cnt++;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> sample_pkt(<span class="keyword">int</span> <span class="keyword">unsigned</span> bytes_total, <span class="keyword">int</span> <span class="keyword">unsigned</span> bytes_payload);</span><br><span class="line">    pkt_cnt++;</span><br><span class="line">    byte_cnt_total += bytes_total;</span><br><span class="line">    byte_cnt_payload += bytes_payload;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">real</span> calc_mpps();</span><br><span class="line">    <span class="keyword">if</span> (cycle_cnt == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">    <span class="keyword">return</span> (pkt_cnt * fclk_hz) / (cycle_cnt * <span class="number">1</span>e6);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">real</span> calc_gbps_total();</span><br><span class="line">    <span class="keyword">if</span> (cycle_cnt == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">    <span class="keyword">return</span> (byte_cnt_total * <span class="number">8</span><span class="variable">.0</span> * fclk_hz) / (cycle_cnt * <span class="number">1</span>e9);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">real</span> calc_gbps_payload();</span><br><span class="line">    <span class="keyword">if</span> (cycle_cnt == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">    <span class="keyword">return</span> (byte_cnt_payload * <span class="number">8</span><span class="variable">.0</span> * fclk_hz) / (cycle_cnt * <span class="number">1</span>e9);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure></li></ul></li></ul><p>6）代码片段：端到端 latency（cycle）统计（基于 pkt_id 关联）</p><ul><li>在哪儿调用：<ul><li><code>sample_cycle()</code>：同上，在 perf&#x2F;stat 组件的时钟线程里每拍调用</li><li><code>on_ingress(pkt_id)</code>：在 ingress_monitor 观测到 <code>sop</code> 握手成功并解析出 <code>pkt_id</code> 时上报；perf&#x2F;stat 的 <code>write_ing(pkt)</code> 内调用</li><li><code>on_egress(pkt_id)</code>：在 egress_monitor 观测到同一包 <code>sop</code> 或 <code>eop</code> 握手成功时上报（按你的 latency 定义选择 sop&#x2F;eop）；perf&#x2F;stat 的 <code>write_egr(pkt)</code> 内调用<figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> latency_stat;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> cyc;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> lat_min;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> lat_max;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> lat_sum;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> lat_cnt;</span><br><span class="line">  <span class="keyword">longint</span> <span class="keyword">unsigned</span> t_in_by_id[<span class="keyword">longint</span> <span class="keyword">unsigned</span>];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> reset();</span><br><span class="line">    cyc = <span class="number">0</span>;</span><br><span class="line">    lat_min = &#x27;<span class="number">1</span>;</span><br><span class="line">    lat_max = <span class="number">0</span>;</span><br><span class="line">    lat_sum = <span class="number">0</span>;</span><br><span class="line">    lat_cnt = <span class="number">0</span>;</span><br><span class="line">    t_in_by_id<span class="variable">.delete</span>();</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> sample_cycle();</span><br><span class="line">    cyc++;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> on_ingress(<span class="keyword">longint</span> <span class="keyword">unsigned</span> pkt_id);</span><br><span class="line">    t_in_by_id[pkt_id] = cyc;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> on_egress(<span class="keyword">longint</span> <span class="keyword">unsigned</span> pkt_id);</span><br><span class="line">    <span class="keyword">longint</span> <span class="keyword">unsigned</span> t0;</span><br><span class="line">    <span class="keyword">longint</span> <span class="keyword">unsigned</span> d;</span><br><span class="line">    <span class="keyword">if</span> (!t_in_by_id<span class="variable">.exists</span>(pkt_id)) <span class="keyword">return</span>;</span><br><span class="line">    t0 = t_in_by_id[pkt_id];</span><br><span class="line">    d = (cyc &gt;= t0) ? (cyc - t0) : <span class="number">0</span>;</span><br><span class="line">    lat_cnt++;</span><br><span class="line">    lat_sum += d;</span><br><span class="line">    <span class="keyword">if</span> (d &lt; lat_min) lat_min = d;</span><br><span class="line">    <span class="keyword">if</span> (d &gt; lat_max) lat_max = d;</span><br><span class="line">    t_in_by_id<span class="variable">.delete</span>(pkt_id);</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">real</span> avg_latency_cyc();</span><br><span class="line">    <span class="keyword">if</span> (lat_cnt == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span><span class="variable">.0</span>;</span><br><span class="line">    <span class="keyword">return</span> lat_sum * <span class="number">1</span><span class="variable">.0</span> / lat_cnt;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure></li></ul></li></ul><p>7）代码片段：credit 计数与合法性检查（按 VC）</p><ul><li>在哪儿调用：<ul><li><code>init_vc(vc, maxc)</code>：在 build_phase&#x2F;end_of_elaboration 或 reset 释放后初始化（从 spec&#x2F;寄存器&#x2F;参数拿到每个 VC 的 credit 上限）</li><li><code>consume(vc, n)</code>：在“发送端握手成功并实际占用 buffer&#x2F;发送 beat&#x2F;发送 flit”的时刻调用（例如 <code>valid &amp;&amp; ready</code> 的 beat 事件）</li><li><code>giveback(vc, n)</code>：在“接收端释放 buffer 并返回 credit”的时刻调用（例如观测到 <code>credit_valid</code>，或观测到 credit-return 通道上的 token&#x2F;报文）<figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> credit_chk;</span><br><span class="line">  <span class="keyword">int</span> <span class="keyword">unsigned</span> credit_max[<span class="keyword">int</span> <span class="keyword">unsigned</span>];</span><br><span class="line">  <span class="keyword">int</span> <span class="keyword">signed</span>   credit_cur[<span class="keyword">int</span> <span class="keyword">unsigned</span>];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> init_vc(<span class="keyword">int</span> <span class="keyword">unsigned</span> vc, <span class="keyword">int</span> <span class="keyword">unsigned</span> maxc);</span><br><span class="line">    credit_max[vc] = maxc;</span><br><span class="line">    credit_cur[vc] = maxc;</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> consume(<span class="keyword">int</span> <span class="keyword">unsigned</span> vc, <span class="keyword">int</span> <span class="keyword">unsigned</span> n = <span class="number">1</span>);</span><br><span class="line">    credit_cur[vc] -= n;</span><br><span class="line">    <span class="keyword">if</span> (credit_cur[vc] &lt; <span class="number">0</span>) `uvm_fatal(<span class="string">&quot;CREDIT&quot;</span>, <span class="string">&quot;credit underflow&quot;</span>)</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="keyword">void</span> giveback(<span class="keyword">int</span> <span class="keyword">unsigned</span> vc, <span class="keyword">int</span> <span class="keyword">unsigned</span> n = <span class="number">1</span>);</span><br><span class="line">    credit_cur[vc] += n;</span><br><span class="line">    <span class="keyword">if</span> (credit_cur[vc] &gt; <span class="keyword">int</span>&#x27;(credit_max[vc])) `uvm_fatal(<span class="string">&quot;CREDIT&quot;</span>, <span class="string">&quot;credit overflow&quot;</span>)</span><br><span class="line">  <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure></li></ul></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;一、UVM验证&quot;&gt;&lt;a href=&quot;#一、UVM验证&quot; class=&quot;headerlink&quot; title=&quot;一、UVM验证&quot;&gt;&lt;/a&gt;一、UVM验证&lt;/h1&gt;&lt;h2 id=&quot;1-常见组件&quot;&gt;&lt;a href=&quot;#1-常见组件&quot; class=&quot;headerlink&quot; </summary>
      
    
    
    
    <category term="笔记" scheme="https://sqlmaps.com/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="笔记" scheme="https://sqlmaps.com/tags/%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>测试点分解</title>
    <link href="https://sqlmaps.com/2026/08/01/%E6%B5%8B%E8%AF%95%E7%82%B9%E5%88%86%E8%A7%A3/"/>
    <id>https://sqlmaps.com/2026/08/01/%E6%B5%8B%E8%AF%95%E7%82%B9%E5%88%86%E8%A7%A3/</id>
    <published>2026-08-01T14:10:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h1 id="测试点分解：验证与确认过程的关键环节"><a href="#测试点分解：验证与确认过程的关键环节" class="headerlink" title="测试点分解：验证与确认过程的关键环节"></a>测试点分解：验证与确认过程的关键环节</h1><h2 id="0-引言：验证-Verification-vs-确认-Validation"><a href="#0-引言：验证-Verification-vs-确认-Validation" class="headerlink" title="0. 引言：验证 (Verification) vs. 确认 (Validation)"></a>0. 引言：验证 (Verification) vs. 确认 (Validation)</h2><p>在深入测试点分解之前，理解验证（Verification）和确认（Validation）的区别至关重要：</p><ul><li><strong>验证 (Verification)<strong>：关注于“我们是否正确地构建了产品？”（Did we build the product right?）。它确保设计符合其规范和技术要求。</strong>测试点分解主要服务于验证过程</strong>，通过将规范细化为可衡量的测试项，来检查设计实现的正确性。</li><li>**确认 (Validation)**：关注于“我们是否构建了正确的产品？”（Did we build the right product?）。它确保最终产品满足用户的需求和预期用途。虽然测试点分解直接服务于验证，但其基础是来自用户需求和系统规范，因此也间接支持了确认过程，确保了构建的功能是用户所需要的。</li></ul><p>测试点分解是连接高级需求（可能涉及确认）与低级设计实现检查（验证）的桥梁。</p><h2 id="1-测试点分解概述"><a href="#1-测试点分解概述" class="headerlink" title="1. 测试点分解概述"></a>1. 测试点分解概述</h2><p>测试点分解是将设计规范（Specification）中的高级需求转化为具体、可衡量的验证目标（测试点）的过程。它是连接设计意图与验证实现的关键桥梁，旨在确保验证的系统性和全面性，从而提高发现设计缺陷的效率。</p><h3 id="1-1-目的与重要性"><a href="#1-1-目的与重要性" class="headerlink" title="1.1 目的与重要性"></a>1.1 目的与重要性</h3><ul><li><strong>确保覆盖</strong>：系统性地识别所有需要验证的功能、性能和接口。<strong>高质量、清晰明确的需求是实现全面覆盖的基础。</strong></li><li><strong>指导测试</strong>：为测试用例设计和覆盖模型开发提供明确输入。</li><li><strong>量化进度</strong>：通过跟踪测试点的覆盖情况来衡量验证进度。</li><li><strong>提高效率</strong>：避免冗余测试，集中资源于关键和复杂区域。</li><li><strong>可追溯性 (Traceability)<strong>：建立从</strong>用户需求&#x2F;系统需求</strong> -&gt; <strong>设计规范</strong> -&gt; 测试点 -&gt; 测试用例 -&gt; 覆盖率 -&gt; 测试结果 的清晰链接，这是 V&amp;V 的核心要求。</li></ul><h2 id="2-从规范到测试计划-Specification-to-Test-Plan"><a href="#2-从规范到测试计划-Specification-to-Test-Plan" class="headerlink" title="2. 从规范到测试计划 (Specification to Test Plan)"></a>2. 从规范到测试计划 (Specification to Test Plan)</h2><p>这个阶段的核心目标是将（理想情况下）高质量的设计规范转化为一份可执行、可衡量的验证蓝图——测试计划。</p><h3 id="2-1-流程-Refined-Flow"><a href="#2-1-流程-Refined-Flow" class="headerlink" title="2.1 流程 (Refined Flow)"></a>2.1 流程 (Refined Flow)</h3><pre><code class="highlight mermaid">flowchart TD    A[设计规范/需求文档] --&gt; B[需求分析与理解]    B --&gt;|识别关键字/约束| C[提取主要特性]    C --&gt;|按类别组织| D[特性列表]    D --&gt; E[对每个特性进行分解]    E --&gt;|识别参数/状态/场景| F[定义具体测试点]    F --&gt;|包含验证目标/方法/预期结果| G[测试点列表]    G --&gt; H[构建结构化测试计划]    H --&gt;|包含范围/策略/环境/覆盖/资源等| I[测试计划文档]    I --&gt; J[评审与确认]</code></pre><p><em>说明：此流程强调从规范到特性，再从特性到具体测试点的分解过程，最终汇集成测试计划文档。</em></p><h3 id="2-2-关键步骤"><a href="#2-2-关键步骤" class="headerlink" title="2.2 关键步骤"></a>2.2 关键步骤</h3><ol><li>**需求理解 (Requirement Understanding)**：<ul><li><strong>主动阅读</strong>: 不仅是阅读，更是分析。标记关键词（如 “must”, “shall”, “should”），识别名词（对象）、动词（操作）和形容词&#x2F;副词（约束）。</li><li><strong>澄清歧义</strong>: 任何不清晰或可能产生多种解释的地方，都需要与设计或系统工程师沟通确认。<strong>这是避免后续验证方向错误的关键。</strong></li><li><strong>识别依赖与约束</strong>: 理解不同需求之间的关系和设计必须遵守的限制条件。</li><li><strong>评估可测性</strong>: 初步判断每个需求是否可以通过合理的验证手段进行测试。</li></ul></li><li>**特性提取 (Feature Extraction)**：<ul><li><strong>系统性梳理</strong>: 遍历规范，将相关的功能点组织成逻辑上的“特性”。一个特性可能跨越规范的多个章节。</li><li><strong>分类</strong>: 使用预定义的类别（如数据通路、控制通路、配置、接口、错误处理、性能、低功耗、安全等）来组织特性，确保覆盖的系统性。</li><li><strong>列表化</strong>: 创建一个明确的特性列表，作为后续分解的基础。</li></ul></li><li><strong>维度识别</strong>: 对<strong>每个特性</strong>应用不同的测试思维维度（功能性、配置组合、边界条件、异常注入、性能压力、并发交互等），以确保考虑周全。</li><li>**功能点&#x2F;测试项分解 (Defining Test Items&#x2F;Points)**：<ul><li><strong>从特性到测试点</strong>: 针对特性列表中的每一个特性，问“为了验证这个特性，我需要检查哪些具体的行为、状态或输出？”。</li><li><strong>明确验证意图</strong>: 每个测试点都应有一个清晰的验证目标。例如，不是笼统地说“测试写操作”，而是具体到“验证在地址对齐、AWBURST&#x3D;INCR、AWLEN&#x3D;4 条件下的写操作数据通路和响应”。</li><li><strong>定义检查点</strong>: 明确如何判断测试点是否通过（预期的数据、状态、波形、协议行为）。</li><li><strong>考虑覆盖</strong>: 初步思考这个测试点对应哪些功能覆盖项（为第 3 节做准备）。</li><li><strong>可追溯性</strong>: 确保每个测试点都能链接回至少一个特性，并最终链接回规范原文。</li></ul></li><li><strong>参数与场景识别</strong>:<ul><li>**等价类划分 (Equivalence Class Partitioning)**：将输入域（如地址范围、数据值、配置参数）或状态空间划分为若干子集（等价类），假设每个等价类中的数据在揭示错误方面具有相同的效果。为每个等价类设计测试用例，覆盖有效等价类（符合规范的输入）和无效等价类（不符合规范的输入）。例如，对于 FIFO 深度为 0-15，有效等价类是 [0, 15]，无效等价类可以是 &lt;0 或 &gt;15。</li><li>**边界值分析 (Boundary Value Analysis)**：经验表明错误常常发生在输入域或输出域的边界上。此方法着重测试等价类边界及其紧邻的值。例如，对于 FIFO 深度 [0, 15]，边界值测试点应包括 0, 1, 14, 15，以及无效边界 -1 和 16。</li><li>**状态迁移分析 (State Transition Analysis)**：特别适用于具有明确状态转换逻辑的设计（如状态机）。识别所有可能的状态、触发状态转换的事件（输入）以及转换后的动作（输出）。设计测试用例以覆盖所有（或关键的）状态以及所有（或关键的）状态转换路径。绘制状态图有助于分析。</li><li>**因果图&#x2F;判定表 (Cause-Effect Graphing &#x2F; Decision Table)**：当输出或行为取决于多个输入条件（原因）的复杂组合时使用。因果图可视化输入条件与输出结果之间的逻辑关系，判定表则将所有可能的条件组合及其对应的预期动作&#x2F;结果以表格形式列出。为判定表中的每一条规则（或关键规则组合）设计测试用例。例如，中断的产生可能依赖于多个状态标志位和使能位的组合。</li><li>**错误猜测 (Error Guessing)**：基于验证工程师的经验、直觉和对设计实现的理解，推测设计中最可能出错的部分或场景，并专门设计测试用例进行验证。这通常涉及一些特殊情况，如：空&#x2F;满状态处理、并发访问冲突、异常序列注入、复位&#x2F;上电时的特殊行为、特定时序的竞争条件等。</li></ul></li><li><strong>测试点定义</strong>:<ul><li><strong>SMART 原则</strong>: 确保测试点是具体的、可衡量的、可实现的、相关的。</li><li><strong>格式统一</strong>: 使用统一的模板或表格来记录测试点，包含 ID、描述、特性关联、规范来源、优先级、验证方法建议、预期结果等字段。</li></ul></li><li><strong>测试计划制定</strong>:<ul><li><strong>结构化文档</strong>: 将所有测试点和其他相关信息（如引言、范围、策略、环境、覆盖目标、回归、资源、风险等）组织成一份正式的测试计划文档。</li><li><strong>核心是测试点列表</strong>: 测试计划的核心内容是经过分解和定义的测试点列表。</li><li><strong>明确验证策略</strong>: 针对不同类型的测试点，可能需要不同的验证策略（如随机测试、定向测试、形式验证）。</li><li><strong>定义覆盖目标</strong>: 基于测试点明确需要达到的代码覆盖率和功能覆盖率目标。</li></ul></li></ol><h3 id="2-3-测试计划要素示例表"><a href="#2-3-测试计划要素示例表" class="headerlink" title="2.3 测试计划要素示例表"></a>2.3 测试计划要素示例表</h3><table><thead><tr><th>测试计划章节</th><th>内容描述</th><th>来源依据</th></tr></thead><tbody><tr><td><strong>引言</strong></td><td>项目背景、验证目标、文档范围</td><td>项目需求</td></tr><tr><td><strong>验证范围</strong></td><td>明确哪些功能&#x2F;模块&#x2F;特性在本次验证范围内，哪些不在</td><td>规范文档、项目计划</td></tr><tr><td><strong>参考文档</strong></td><td>设计规范、接口文档、架构文档等</td><td>相关文档列表</td></tr><tr><td><strong>验证策略</strong></td><td>采用的方法（如UVM、形式验证）、主要技术（随机化、覆盖驱动）</td><td>验证方法学</td></tr><tr><td><strong>验证环境</strong></td><td>测试平台架构、使用的VIP、仿真器、工具链</td><td>团队标准、项目需求</td></tr><tr><td><strong>功能测试点列表</strong></td><td>详细列出从规范分解出的所有功能测试点，包含ID、描述、优先级</td><td>规范分解结果</td></tr><tr><td><strong>性能测试点列表</strong></td><td>需要验证的性能指标（如带宽、延迟、功耗）及其目标值</td><td>规范性能章节</td></tr><tr><td><strong>覆盖策略</strong></td><td>定义代码覆盖率和功能覆盖率目标，描述覆盖模型计划</td><td>验证目标</td></tr><tr><td><strong>回归策略</strong></td><td>定义回归测试的触发条件、范围和通过标准</td><td>质量要求</td></tr><tr><td><strong>资源与进度</strong></td><td>人员安排、工具许可、计划时间表</td><td>项目管理</td></tr></tbody></table><h3 id="2-4-测试计划最佳实践"><a href="#2-4-测试计划最佳实践" class="headerlink" title="2.4 测试计划最佳实践"></a>2.4 测试计划最佳实践</h3><ul><li><strong>结构化</strong>：采用标准模板，保持一致性。</li><li><strong>可执行性</strong>：计划应切实可行，避免过于理想化。</li><li><strong>可维护性</strong>：易于更新以反映设计或需求的变更。</li><li><strong>评审</strong>：由设计、验证和系统工程师共同评审，确保全面性和准确性。</li><li><strong>基线化</strong>：在关键阶段对测试计划进行基线化管理。</li></ul><h2 id="3-从测试计划到功能覆盖-Test-Plan-to-Functional-Coverage"><a href="#3-从测试计划到功能覆盖-Test-Plan-to-Functional-Coverage" class="headerlink" title="3. 从测试计划到功能覆盖 (Test Plan to Functional Coverage)"></a>3. 从测试计划到功能覆盖 (Test Plan to Functional Coverage)</h2><h3 id="3-1-流程与关键概念"><a href="#3-1-流程与关键概念" class="headerlink" title="3.1 流程与关键概念"></a>3.1 流程与关键概念</h3><p>功能覆盖（Functional Coverage）是验证过程中量化验证完整性的关键指标。根据Verification Academy的实践指南，有效的功能覆盖应具备以下特征：</p><ol><li><strong>规范驱动</strong>：覆盖点必须直接映射到设计规范中的功能点</li><li><strong>可测量</strong>：每个覆盖点应有明确的通过&#x2F;失败标准</li><li><strong>可追溯</strong>：能够追溯到原始需求和测试计划</li><li><strong>分层结构</strong>：从高层次功能到低层次实现细节的完整覆盖</li></ol><pre><code class="highlight mermaid">flowchart TD    A[设计规范] --&gt; B[功能分解]    B --&gt; C[测试计划]    C --&gt; D[覆盖模型]    D --&gt; E[覆盖点实现]    E --&gt; F[覆盖数据分析]    F --&gt; G[覆盖达标?]    H[验证完成]</code></pre><h3 id="3-1-详细流程"><a href="#3-1-详细流程" class="headerlink" title="3.1 详细流程"></a>3.1 详细流程</h3><pre><code class="highlight mermaid">flowchart TD    A[测试计划/测试点] --&gt; B[识别覆盖事件]    B --&gt; C[定义覆盖点 Coverpoint]    C --&gt; D[定义覆盖组 Covergroup]    D --&gt; E[需要交叉覆盖?]    F[定义交叉覆盖 Cross] --&gt; G[实现覆盖模型 Code]    G --&gt; H[集成到验证环境]    H --&gt; I[运行测试并收集覆盖率]    I --&gt; J[分析覆盖报告]    J --&gt; K[覆盖目标达成?]    L[分析覆盖空洞/调整测试/评审] --&gt; I    M[验证完成]</code></pre><h3 id="3-2-关键步骤与最佳实践"><a href="#3-2-关键步骤与最佳实践" class="headerlink" title="3.2 关键步骤与最佳实践"></a>3.2 关键步骤与最佳实践</h3><p>根据Spec Innovations的验证指南，构建高质量覆盖模型应遵循以下步骤：</p><ol><li><p><strong>需求分析阶段</strong>：</p><ul><li>识别所有功能需求和非功能需求</li><li>对每个需求评估其可测性</li><li>标记需要特殊验证技术的复杂需求</li></ul></li><li><p><strong>测试点定义</strong>：</p><ul><li>为每个需求定义1个或多个测试点</li><li>使用SMART原则（具体、可测、可实现、相关、有时限）</li><li>优先级分类（P0-关键功能，P1-重要功能，P2-边缘情况）</li></ul></li><li><p><strong>覆盖模型设计</strong>：</p><ul><li>确定需要量化的功能维度</li><li>设计覆盖点结构（coverpoint&#x2F;cross）</li><li>定义合理的bins划分策略</li></ul></li><li><p><strong>实现与集成</strong>：</p><ul><li>使用SystemVerilog实现覆盖组</li><li>在验证环境中集成覆盖采样</li><li>建立自动化覆盖收集机制</li></ul></li><li><p><strong>分析与收敛</strong>：</p><ul><li>定期生成覆盖报告</li><li>识别覆盖空洞</li><li>实施覆盖提升策略</li></ul></li></ol><pre><code class="highlight mermaid">flowchart TD    A[需求文档] --&gt; B[测试计划]    B --&gt; C[覆盖模型设计]    C --&gt; D[覆盖点实现]    D --&gt; E[测试执行]    E --&gt; F[覆盖分析]    F --&gt; G[覆盖达标?]    H[验证完成]    I[调整测试/模型] --&gt; E</code></pre><ol><li>**识别覆盖事件&#x2F;项 (Items to be Covered)**：根据测试计划中的测试点，识别需要量化验证的具体项。这些通常包括：<ul><li>**事务属性 (Transaction Attributes)**：如 AXI 事务的地址、长度、大小、突发类型、响应状态等。</li><li>**配置空间 (Configuration Space)**：DUT 的各种配置寄存器设置及其组合。</li><li>**状态空间 (State Space)**：关键状态机的状态及其转换。</li><li>**操作序列 (Sequences of Operations)**：特定的操作流程或事件顺序，如背靠背读写、错误注入后的恢复流程等。</li><li>**错误条件 (Error Conditions)**：各种错误场景的触发和处理。</li><li>**接口信号时序 (Interface Signal Timing)**：虽然常由断言覆盖，但某些关键时序关系也可纳入功能覆盖。</li></ul></li><li><strong>定义Coverpoint</strong>：为每个关键变量或事件定义覆盖点。<ul><li>**命名清晰 (Meaningful Names)**：Coverpoint 和 bins 的名称应清晰反映其意图。</li><li>**合理分箱 (Binning Strategy)**：<ul><li>使用 <code>bins</code> 关键字定义关心的取值或范围。</li><li>为范围定义有意义的名称，如 <code>bins low = &#123;[0:10]&#125;;</code>。</li><li>使用 <code>with</code> 子句定义基于表达式的 bins。</li><li>考虑 <code>default</code> bin 捕获未明确定义的取值。</li><li>使用 <code>auto_bin_max</code> 适度自动分箱，但对关键变量建议手动定义。</li></ul></li></ul></li><li><strong>定义Covergroup</strong>：将相关的 Coverpoints 组织到 Covergroup 中。通常一个 Covergroup 对应测试计划中的一个功能区域或接口。</li><li><strong>定义Cross Coverage</strong>：识别需要同时覆盖的多个变量组合。<ul><li>**识别有意义的交叉 (Meaningful Crosses)**：仅交叉那些确实存在交互关系或需要组合验证的变量，避免不必要的交叉导致覆盖空间爆炸。</li><li>**排除无效组合 (Excluding Bins)**：使用 <code>ignore_bins</code> 排除不关心或不可能的组合，使用 <code>illegal_bins</code> 标记非法组合。</li><li>**精简交叉 (Refining Crosses)**：有时不需要交叉所有 bins，可以使用 <code>binsof()</code> 和 <code>intersect</code> 选择特定的 bins 进行交叉。</li></ul></li><li><strong>实现覆盖模型</strong>：使用 SystemVerilog 编写覆盖代码。<ul><li>**参数化 (Parameterization)**：对地址宽度、数据宽度等使用参数，提高复用性。</li><li>**条件采样 (Conditional Sampling - <code>iff</code>)**：确保在正确的时机采样。</li><li>**权重与目标 (Weights and Goals)**：根据重要性设置权重 (<code>option.weight</code>) 和目标 (<code>option.goal</code>)。</li></ul></li><li>**集成覆盖模型 (Integrating the Coverage Model)**：将 Covergroup 实例集成到验证环境中合适的组件中。常见位置包括：<ul><li><strong>Monitor</strong>：通常是收集功能覆盖信息的最佳位置，因为它观察接口活动并提取事务。可以在 Monitor 中实例化 Covergroup，并在事务发生或完成时调用 <code>sample()</code> 方法。</li><li><strong>Scoreboard</strong>：有时用于覆盖端到端的数据检查相关的场景。</li><li><strong>Sequence&#x2F;Sequencer</strong>：可以覆盖与特定激励生成策略相关的方面。</li><li><strong>Checker</strong>：独立的检查器模块也可以包含覆盖组。</li></ul></li><li>**分析与迭代 (Coverage Closure)**：这是一个持续的过程，涉及运行测试、分析报告、识别空洞、调整测试或覆盖模型，直到达到签收标准。需要区分是测试不足、设计问题、覆盖模型问题还是冗余设计。</li></ol><h3 id="3-3-功能覆盖类型与高级技术"><a href="#3-3-功能覆盖类型与高级技术" class="headerlink" title="3.3 功能覆盖类型与高级技术"></a>3.3 功能覆盖类型与高级技术</h3><h4 id="3-3-1-基础覆盖类型"><a href="#3-3-1-基础覆盖类型" class="headerlink" title="3.3.1 基础覆盖类型"></a>3.3.1 基础覆盖类型</h4><table><thead><tr><th>覆盖类型</th><th>描述</th><th>适用场景</th><th>实现示例</th></tr></thead><tbody><tr><td><strong>值覆盖</strong></td><td>检查变量取值</td><td>配置寄存器、状态变量</td><td><code>coverpoint mode &#123; bins low=&#123;0&#125;; bins high=&#123;1&#125;; &#125;</code></td></tr><tr><td><strong>转换覆盖</strong></td><td>检查状态转换</td><td>状态机验证</td><td><code>coverpoint state &#123; bins s1_to_s2 = (S1 =&gt; S2); &#125;</code></td></tr><tr><td><strong>交叉覆盖</strong></td><td>检查变量组合</td><td>配置参数组合</td><td><code>cross mode, speed</code></td></tr></tbody></table><h4 id="3-3-2-高级覆盖技术（来自Verification-Academy）"><a href="#3-3-2-高级覆盖技术（来自Verification-Academy）" class="headerlink" title="3.3.2 高级覆盖技术（来自Verification Academy）"></a>3.3.2 高级覆盖技术（来自Verification Academy）</h4><ol><li><p><strong>参数化覆盖组</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> addr_coverage (<span class="keyword">int</span> lo, hi) @(<span class="keyword">posedge</span> clk);</span><br><span class="line">    <span class="keyword">coverpoint</span> addr &#123;</span><br><span class="line">        <span class="keyword">bins</span> low  = &#123;[lo:hi]&#125;;</span><br><span class="line">        <span class="keyword">bins</span> high = &#123;[hi+<span class="number">1</span>:hi*<span class="number">2</span>]&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li><li><p><strong>条件采样</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> trans_cg @(<span class="keyword">posedge</span> clk);</span><br><span class="line">    <span class="keyword">coverpoint</span> trans_type <span class="keyword">iff</span> (resetn &amp;&amp; enable);</span><br><span class="line">    <span class="keyword">coverpoint</span> data_len <span class="keyword">iff</span> (trans_type == WRITE);</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li><li><p><strong>动态bins调整</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> dynamic_cg;</span><br><span class="line">    <span class="keyword">coverpoint</span> addr &#123;</span><br><span class="line">        <span class="keyword">bins</span> ranges[] = dynamic_bins_array;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li><li><p><strong>覆盖选项控制</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> cg <span class="keyword">with</span> <span class="keyword">function</span> sample(<span class="keyword">bit</span> en);</span><br><span class="line">    option<span class="variable">.per_instance</span> = <span class="number">1</span>;</span><br><span class="line">    option<span class="variable">.weight</span> = (en) ? <span class="number">1</span> : <span class="number">0</span>;</span><br><span class="line">    ...</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="3-3-3-覆盖模型优化策略"><a href="#3-3-3-覆盖模型优化策略" class="headerlink" title="3.3.3 覆盖模型优化策略"></a>3.3.3 覆盖模型优化策略</h4><ol><li><p><strong>分层覆盖</strong>：</p><ul><li>模块级：验证内部实现细节</li><li>接口级：验证协议合规性  </li><li>系统级：验证端到端功能</li></ul></li><li><p><strong>智能bins划分</strong>：</p><ul><li>对关键变量使用手动bins</li><li>对次要变量使用auto_bin_max</li><li>使用ignore_bins排除无效组合</li></ul></li><li><p><strong>覆盖权重分配</strong>：</p><ul><li>关键功能设置高权重</li><li>次要功能设置低权重</li><li>冗余功能设置零权重</li></ul></li></ol><table><thead><tr><th>覆盖类型</th><th>描述</th><th>SystemVerilog 示例 (概念性)</th></tr></thead><tbody><tr><td><strong>值覆盖</strong></td><td>检查变量是否取到了所有关心的值</td><td><code>cp_addr : coverpoint addr &#123; bins low = &#123;[0:10]&#125;; bins high = &#123;[100:110]&#125;; &#125;</code></td></tr><tr><td><strong>状态覆盖</strong></td><td>检查状态机是否经历了所有关心的状态</td><td><code>cp_state : coverpoint current_state &#123; bins idle= &#123;S_IDLE&#125;; bins active = &#123;S_ACTIVE&#125;; &#125;</code></td></tr><tr><td><strong>转换覆盖</strong></td><td>检查状态机是否经历了所有关心的状态转换</td><td><code>cp_trans : coverpoint current_state iff (rst==0) &#123; bins idle_to_active = (S_IDLE =&gt; S_ACTIVE); &#125;</code></td></tr><tr><td><strong>交叉覆盖</strong></td><td>检查多个变量&#x2F;事件的组合是否发生</td><td><code>cross cp_addr, cp_cmd;</code></td></tr><tr><td><strong>条件覆盖</strong></td><td>检查某个条件表达式的不同逻辑组合是否满足</td><td>&#96;cp_cond : coverpoint (A &amp;&amp; B</td></tr><tr><td><strong>序列覆盖</strong></td><td>检查特定的事件序列是否按预期发生 (常用于断言)</td><td><code>assert property (@(posedge clk) seq_prop);</code></td></tr></tbody></table><h3 id="3-4-覆盖模型实现与验证环境集成"><a href="#3-4-覆盖模型实现与验证环境集成" class="headerlink" title="3.4 覆盖模型实现与验证环境集成"></a>3.4 覆盖模型实现与验证环境集成</h3><h4 id="3-4-1-实现模式比较"><a href="#3-4-1-实现模式比较" class="headerlink" title="3.4.1 实现模式比较"></a>3.4.1 实现模式比较</h4><table><thead><tr><th>实现方式</th><th>优点</th><th>缺点</th><th>适用场景</th></tr></thead><tbody><tr><td><strong>内联实现</strong></td><td>简单直接，与DUT紧密耦合</td><td>复用性差，维护困难</td><td>小型模块验证</td></tr><tr><td><strong>独立覆盖组件</strong></td><td>高复用性，接口清晰</td><td>需要额外集成工作</td><td>复杂IP验证</td></tr><tr><td><strong>基于VIP的覆盖</strong></td><td>协议合规性保障</td><td>定制灵活性低</td><td>标准接口验证</td></tr></tbody></table><h4 id="3-4-2-验证环境集成指南"><a href="#3-4-2-验证环境集成指南" class="headerlink" title="3.4.2 验证环境集成指南"></a>3.4.2 验证环境集成指南</h4><ol><li><p><strong>Monitor集成</strong>（推荐）：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> axi_monitor;</span><br><span class="line">    axi_cg cg = <span class="keyword">new</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">task</span> run();</span><br><span class="line">        <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">            @(<span class="keyword">posedge</span> clk);</span><br><span class="line">            <span class="keyword">if</span> (trans_complete) <span class="keyword">begin</span></span><br><span class="line">                cg<span class="variable">.sample</span>(trans);</span><br><span class="line">            <span class="keyword">end</span></span><br><span class="line">        <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">endtask</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure></li><li><p><strong>Scoreboard集成</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> scoreboard;</span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">void</span> check_trans(axi_trans t);</span><br><span class="line">        <span class="comment">// 数据检查逻辑</span></span><br><span class="line">        cov_model<span class="variable">.sample</span>(t);</span><br><span class="line">    <span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure></li><li><p><strong>Sequence控制</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">    axi_trans t;</span><br><span class="line">    <span class="keyword">repeat</span>(<span class="number">100</span>) <span class="keyword">begin</span></span><br><span class="line">        `uvm_do_with(t, &#123;t<span class="variable">.addr</span> <span class="keyword">inside</span> &#123;[<span class="number">0</span>:<span class="number">100</span>]&#125;;&#125;)</span><br><span class="line">        cov_model<span class="variable">.sample</span>(t);</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endtask</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="3-4-3-覆盖数据管理"><a href="#3-4-3-覆盖数据管理" class="headerlink" title="3.4.3 覆盖数据管理"></a>3.4.3 覆盖数据管理</h4><ol><li><p><strong>数据库选择</strong>：</p><ul><li>文件存储（CSV&#x2F;XML）</li><li>专业数据库（SQLite&#x2F;MongoDB）</li><li>企业级解决方案（vManager&#x2F;Verdi)</li></ul></li><li><p><strong>合并策略</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    <span class="comment">// 合并多个测试的覆盖数据</span></span><br><span class="line">    <span class="built_in">$coverage_merge</span>(<span class="string">&quot;test1.cov&quot;</span>, <span class="string">&quot;test2.cov&quot;</span>, <span class="string">&quot;regression.cov&quot;</span>);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure></li><li><p><strong>报告生成</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="keyword">begin</span></span><br><span class="line">    <span class="built_in">$coverage_save</span>(<span class="string">&quot;final.cov&quot;</span>);</span><br><span class="line">    $coverage_report(<span class="string">&quot;report.html&quot;</span>);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure></li></ol><ul><li>**采样条件 (iff)**：<code>coverpoint cp_name iff (condition)</code> 仅在 <code>condition</code> 为真时才对 <code>cp_name</code> 进行采样，用于精确控制采样时刻。</li><li>**忽略与非法区间 (ignore_bins, illegal_bins)**：<ul><li><code>ignore_bins</code>: 定义不关心或不影响功能的取值或组合，这些 bins 不计入覆盖率计算的分母。</li><li><code>illegal_bins</code>: 定义非法的取值或组合，如果仿真中覆盖到 <code>illegal_bins</code>，应报错。</li></ul></li><li>**覆盖选项 (options)**：<ul><li><code>option.per_instance = 1</code>: 每个 covergroup 实例单独计算覆盖率。</li><li><code>type_option.weight = N</code>: 设置 covergroup 或 coverpoint 的权重，影响总体覆盖率计算。</li><li><code>option.goal = N</code>: 设置覆盖目标百分比（默认100%）。</li><li><code>option.comment = &quot;...&quot;</code>: 添加注释，便于理解覆盖点意图。</li></ul></li></ul><h3 id="3-5-覆盖采样策略与性能优化"><a href="#3-5-覆盖采样策略与性能优化" class="headerlink" title="3.5 覆盖采样策略与性能优化"></a>3.5 覆盖采样策略与性能优化</h3><h4 id="3-5-1-采样时机选择"><a href="#3-5-1-采样时机选择" class="headerlink" title="3.5.1 采样时机选择"></a>3.5.1 采样时机选择</h4><table><thead><tr><th>采样点</th><th>优点</th><th>缺点</th><th>适用场景</th></tr></thead><tbody><tr><td><strong>时钟边沿</strong></td><td>简单直接</td><td>可能采样冗余数据</td><td>同步设计</td></tr><tr><td><strong>事务完成</strong></td><td>数据稳定</td><td>需要额外检测逻辑</td><td>事务级验证</td></tr><tr><td><strong>特定事件</strong></td><td>精确控制</td><td>事件定义复杂</td><td>关键场景验证</td></tr></tbody></table><h4 id="3-5-2-性能优化技术"><a href="#3-5-2-性能优化技术" class="headerlink" title="3.5.2 性能优化技术"></a>3.5.2 性能优化技术</h4><ol><li><p><strong>选择性采样</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> perf_cg @(<span class="keyword">posedge</span> clk);</span><br><span class="line">    option<span class="variable">.per_instance</span> = <span class="number">0</span>; <span class="comment">// 减少实例数量</span></span><br><span class="line">    <span class="keyword">coverpoint</span> addr <span class="keyword">iff</span> (addr_valid);</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li><li><p><strong>采样频率控制</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bit</span> sample_enable = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">covergroup</span> throttled_cg @(<span class="keyword">posedge</span> clk);</span><br><span class="line">    <span class="keyword">coverpoint</span> data <span class="keyword">iff</span> (sample_enable);</span><br><span class="line"><span class="keyword">endgroup</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 控制采样频率</span></span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">        #<span class="number">100</span>ns sample_enable = <span class="number">1</span>;</span><br><span class="line">        #<span class="number">10</span>ns sample_enable = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure></li><li><p><strong>分层采样</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> base_cg; <span class="comment">// 基础覆盖</span></span><br><span class="line">    <span class="keyword">coverpoint</span> cmd;</span><br><span class="line"><span class="keyword">endgroup</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">covergroup</span> detail_cg; <span class="comment">// 详细覆盖</span></span><br><span class="line">    <span class="keyword">coverpoint</span> data <span class="keyword">iff</span> (detailed_mode);</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="3-5-3-调试技巧"><a href="#3-5-3-调试技巧" class="headerlink" title="3.5.3 调试技巧"></a>3.5.3 调试技巧</h4><ol><li><p><strong>覆盖点标记</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> debug_cg;</span><br><span class="line">    option<span class="variable">.comment</span> = <span class="string">&quot;AXI Write Channel Coverage&quot;</span>;</span><br><span class="line">    <span class="keyword">coverpoint</span> awsize &#123;</span><br><span class="line">        <span class="keyword">bins</span> sizes[] = &#123;[<span class="number">0</span>:<span class="number">7</span>]&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">endgroup</span></span><br></pre></td></tr></table></figure></li><li><p><strong>覆盖追踪</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    $coverage_trace(<span class="string">&quot;coverage.log&quot;</span>);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure></li><li><p><strong>交互式控制</strong>：</p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 动态启用/禁用覆盖组</span></span><br><span class="line">cov_model<span class="variable">.cg</span><span class="variable">.option</span><span class="variable">.weight</span> = debug_mode ? <span class="number">1</span> : <span class="number">0</span>;</span><br></pre></td></tr></table></figure></li></ol><p>覆盖采样通常在验证环境的关键时间点触发，例如：</p><ul><li><strong>事件触发</strong>：使用 <code>@(event)</code> 或 <code>wait(event.triggered)</code>。</li><li><strong>时钟边沿</strong>：在时钟边沿采样信号值。</li><li><strong>方法调用</strong>：在 monitor 或 checker 中显式调用 covergroup 的 <code>sample()</code> 方法。</li><li><strong>断言触发</strong>：在断言成功或失败时采样相关状态。</li></ul><p>选择合适的采样时机对于确保覆盖数据的准确性至关重要。</p><h3 id="3-6-覆盖率分析与收敛策略"><a href="#3-6-覆盖率分析与收敛策略" class="headerlink" title="3.6 覆盖率分析与收敛策略"></a>3.6 覆盖率分析与收敛策略</h3><h4 id="3-6-1-覆盖空洞分析框架"><a href="#3-6-1-覆盖空洞分析框架" class="headerlink" title="3.6.1 覆盖空洞分析框架"></a>3.6.1 覆盖空洞分析框架</h4><pre><code class="highlight mermaid">flowchart TD    A[覆盖空洞] --&gt; B[原因分类]    B --&gt; C[测试激励不足]    B --&gt; D[设计实现问题]    B --&gt; E[覆盖模型缺陷]    B --&gt; F[冗余/不可达逻辑]    C --&gt; G[调整约束]    C --&gt; H[增加定向测试]    D --&gt; I[修复设计Bug]    E --&gt; J[修正bins定义]    E --&gt; K[调整采样条件]    F --&gt; L[设计评审]    F --&gt; M[覆盖豁免]</code></pre><h4 id="3-6-2-实用分析技术（来自Spec-Innovations）"><a href="#3-6-2-实用分析技术（来自Spec-Innovations）" class="headerlink" title="3.6.2 实用分析技术（来自Spec Innovations）"></a>3.6.2 实用分析技术（来自Spec Innovations）</h4><ol><li><p><strong>热点分析</strong>：</p><ul><li>识别被过度测试的覆盖点</li><li>优化测试用例减少冗余</li></ul></li><li><p><strong>关联分析</strong>：</p><ul><li>找出相关覆盖点的共同未覆盖区域</li><li>设计针对性测试场景</li></ul></li><li><p><strong>趋势分析</strong>：</p><ul><li>跟踪覆盖率随测试时间的变化</li><li>预测收敛所需资源</li></ul></li><li><p><strong>根本原因分析</strong>：</p><ul><li>使用5Why方法追溯空洞原因</li><li>建立纠正措施跟踪表</li></ul></li></ol><h4 id="3-6-3-覆盖提升策略"><a href="#3-6-3-覆盖提升策略" class="headerlink" title="3.6.3 覆盖提升策略"></a>3.6.3 覆盖提升策略</h4><table><thead><tr><th>策略</th><th>实施方法</th><th>效果评估</th></tr></thead><tbody><tr><td><strong>约束优化</strong></td><td>调整随机约束分布</td><td>检查新生成的测试向量</td></tr><tr><td><strong>种子挖掘</strong></td><td>筛选高覆盖率种子</td><td>回归测试通过率</td></tr><tr><td><strong>定向测试</strong></td><td>针对特定场景设计用例</td><td>目标覆盖点提升</td></tr><tr><td><strong>模型调整</strong></td><td>优化bins定义</td><td>覆盖报告变化</td></tr><tr><td><strong>形式验证</strong></td><td>补充形式分析</td><td>状态空间覆盖</td></tr></tbody></table><h4 id="3-6-4-覆盖收敛指标"><a href="#3-6-4-覆盖收敛指标" class="headerlink" title="3.6.4 覆盖收敛指标"></a>3.6.4 覆盖收敛指标</h4><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 覆盖收敛检查函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">bit</span> is_converged();</span><br><span class="line">    <span class="comment">// 功能覆盖率达标</span></span><br><span class="line">    <span class="keyword">if</span> (functional_coverage &lt; <span class="number">95</span>%) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 代码覆盖率达标</span></span><br><span class="line">    <span class="keyword">if</span> (line_coverage &lt; <span class="number">90</span>%) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (branch_coverage &lt; <span class="number">80</span>%) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 关键覆盖点100%</span></span><br><span class="line">    <span class="keyword">foreach</span> (critical_cps[i]) <span class="keyword">begin</span></span><br><span class="line">        <span class="keyword">if</span> (critical_cps[i]<span class="variable">.coverage</span> &lt; <span class="number">100</span>%) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"><span class="keyword">endfunction</span></span><br></pre></td></tr></table></figure><p>覆盖率收敛是一个迭代过程：</p><ol><li><strong>运行回归测试</strong>：执行测试用例集，收集覆盖率数据。</li><li><strong>生成覆盖报告</strong>：使用工具生成详细的覆盖率报告。</li><li><strong>识别覆盖空洞</strong>：找出未达到100%覆盖的 coverpoints 和 crosses。</li><li><strong>分析空洞原因</strong>：<ul><li><strong>测试激励不足</strong>：随机约束不够完善或缺少定向测试。</li><li><strong>设计Bug</strong>：代码错误导致某些状态或路径无法到达。</li><li><strong>覆盖模型问题</strong>：覆盖点定义错误、冗余或采样条件不当。</li><li><strong>冗余&#x2F;不可达设计</strong>：设计中存在永远不会被激活的逻辑（需要设计确认）。</li><li><strong>规范问题</strong>：需求本身存在矛盾或未定义的情况。</li></ul></li><li><strong>制定解决策略</strong>：<ul><li><strong>增强测试</strong>：调整约束、增加随机种子、编写定向测试。</li><li><strong>修正设计&#x2F;验证环境</strong>：修复Bug。</li><li><strong>修正覆盖模型</strong>：调整bins、iff条件、使用ignore&#x2F;illegal bins。</li><li>**申请豁免 (Waiver)**：对于确认无法达到或无须达到的覆盖点，在评审后进行豁免，并记录原因。</li></ul></li><li><strong>重复迭代</strong>：执行修改后的测试，重新收集和分析覆盖率，直至满足收敛目标。</li></ol><pre><code class="highlight mermaid">flowchart TD    A[运行回归测试] --&gt; B[收集覆盖数据]    B --&gt; C[生成覆盖报告]    C --&gt; D[覆盖率达标?]    E[完成/签署]    F[分析覆盖空洞] --&gt; G[空洞原因?]    H[调整约束/定向测试]    I[修复代码]    J[修正覆盖模型]    K[评审/Waiver]</code></pre><h3 id="3-7-综合覆盖策略与指标关联"><a href="#3-7-综合覆盖策略与指标关联" class="headerlink" title="3.7 综合覆盖策略与指标关联"></a>3.7 综合覆盖策略与指标关联</h3><h4 id="3-7-1-三维覆盖评估模型"><a href="#3-7-1-三维覆盖评估模型" class="headerlink" title="3.7.1 三维覆盖评估模型"></a>3.7.1 三维覆盖评估模型</h4><table><thead><tr><th>类别</th><th>占比</th></tr></thead><tbody><tr><td>功能覆盖</td><td>45</td></tr><tr><td>代码覆盖</td><td>35</td></tr><tr><td>断言覆盖</td><td>20</td></tr></tbody></table><h4 id="3-7-2-覆盖类型关联矩阵"><a href="#3-7-2-覆盖类型关联矩阵" class="headerlink" title="3.7.2 覆盖类型关联矩阵"></a>3.7.2 覆盖类型关联矩阵</h4><table><thead><tr><th>指标关联</th><th>功能覆盖</th><th>代码覆盖</th><th>断言覆盖</th></tr></thead><tbody><tr><td><strong>功能覆盖</strong></td><td>-</td><td>高功能覆盖应导致高代码覆盖</td><td>断言可验证功能覆盖点</td></tr><tr><td><strong>代码覆盖</strong></td><td>未覆盖代码可能缺少功能点</td><td>-</td><td>断言可检查代码路径</td></tr><tr><td><strong>断言覆盖</strong></td><td>断言可量化功能覆盖</td><td>断言验证特定代码行为</td><td>-</td></tr></tbody></table><h4 id="3-7-3-综合评估标准"><a href="#3-7-3-综合评估标准" class="headerlink" title="3.7.3 综合评估标准"></a>3.7.3 综合评估标准</h4><ol><li><p><strong>基础标准</strong>：</p><ul><li>功能覆盖率 ≥ 95%</li><li>代码行覆盖率 ≥ 90% </li><li>分支覆盖率 ≥ 80%</li><li>断言覆盖率 ≥ 95%</li></ul></li><li><p><strong>高级标准</strong>：</p><ul><li>关键功能覆盖点100%</li><li>高风险代码100%覆盖</li><li>所有断言100%触发</li></ul></li><li><p><strong>豁免流程</strong>：</p><ul><li>提交豁免申请</li><li>技术委员会评审</li><li>更新验证计划</li></ul></li></ol><h4 id="3-7-4-覆盖驱动验证流程"><a href="#3-7-4-覆盖驱动验证流程" class="headerlink" title="3.7.4 覆盖驱动验证流程"></a>3.7.4 覆盖驱动验证流程</h4><pre><code class="highlight mermaid">sequenceDiagram    participant TM as Test Manager    participant VE as Verification Engineer    participant DE as Design Engineer    TM-&gt;&gt;VE: 定义覆盖目标    VE-&gt;&gt;DE: 评审覆盖模型    DE--&gt;&gt;VE: 反馈调整建议    VE-&gt;&gt;VE: 实施验证环境    VE-&gt;&gt;VE: 运行测试    VE-&gt;&gt;VE: 分析报告    VE-&gt;&gt;DE: 咨询设计意图    DE--&gt;&gt;VE: 澄清设计行为    VE-&gt;&gt;VE: 调整测试/模型    VE-&gt;&gt;TM: 提交覆盖报告</code></pre><table><thead><tr><th>覆盖率类型</th><th>衡量什么?</th><th>优点</th><th>缺点</th><th>关系与作用</th></tr></thead><tbody><tr><td><strong>代码覆盖率</strong></td><td>设计代码的执行程度 (行、分支、条件、FSM等)</td><td>易于自动生成和测量，发现未执行代码</td><td>不能保证功能正确性，可能存在未测试的功能场景</td><td>基础性覆盖，确保代码被走到，是功能覆盖的基础</td></tr><tr><td><strong>功能覆盖率</strong></td><td>设计意图&#x2F;规范的实现程度</td><td>直接关联设计规范，衡量功能点是否被测试</td><td>需要手动定义，可能遗漏覆盖点，定义复杂</td><td>核心覆盖，确保设计按预期工作，弥补代码覆盖率的不足</td></tr><tr><td><strong>断言覆盖率</strong></td><td>断言属性被触发和验证的程度</td><td>验证时序行为和协议规则，发现潜在动态错误</td><td>需要编写高质量断言，可能与功能覆盖有重叠</td><td>补充覆盖，专注于检查关键时序和协议，增强功能覆盖和代码覆盖</td></tr></tbody></table><p><strong>理想状态</strong>：三种覆盖率相互补充，共同达到高水平，以最大程度确保设计质量。高代码覆盖率 + 高功能覆盖率 + 高断言覆盖率 ⇒ 更高的验证置信度。</p><h3 id="3-8-不同设计风格的功能覆盖策略示例"><a href="#3-8-不同设计风格的功能覆盖策略示例" class="headerlink" title="3.8 不同设计风格的功能覆盖策略示例"></a>3.8 不同设计风格的功能覆盖策略示例</h3><p>功能覆盖模型的具体实现方式很大程度上取决于被测设计（DUT）的类型。以下是一些常见设计风格及其对应的覆盖策略重点：</p><ol><li><p><strong>总线协议接口 (Bus Protocol Interface, e.g., APB, AXI)</strong></p><ul><li><strong>重点</strong>: 协议规则遵循性、事务属性组合、时序关系、错误响应。</li><li><strong>覆盖项示例 (参考 APB)</strong>:<ul><li><code>coverpoint psel</code>: 确保所有合法的 <code>psel</code> 都被选中。</li><li><code>coverpoint paddr</code>: 地址空间覆盖（关键地址、边界地址、对齐方式）。</li><li><code>coverpoint pwrite</code>: 读写操作覆盖。</li><li><code>coverpoint pprot</code>: 保护类型覆盖。</li><li><code>cross paddr, pwrite</code>: 特定地址的读写操作组合。</li><li><code>coverpoint pslverr</code>: 错误响应覆盖。</li><li><strong>时序关系</strong>: (通常更适合用断言覆盖，但也可部分纳入功能覆盖) 如 <code>pready</code> 的延迟周期。</li></ul></li><li><strong>参考</strong>: Verification Academy - Bus Protocol Coverage (apb_protocol_monitor.tgz)</li></ul></li><li><p><strong>外设类型设计 (Peripheral Style Design, e.g., UART)</strong></p><ul><li><strong>重点</strong>: 控制&#x2F;状态寄存器的配置组合及其对行为的影响、数据通路操作（发送&#x2F;接收）、中断生成。</li><li><strong>覆盖项示例 (参考 UART)</strong>:<ul><li><strong>配置寄存器覆盖</strong>:<ul><li><code>coverpoint baud_rate_divisor</code>: 波特率设置覆盖。</li><li><code>coverpoint parity_enable</code>: 奇偶校验使能&#x2F;禁用。</li><li><code>coverpoint data_bits</code>: 数据位长度 (5, 6, 7, 8)。</li><li><code>coverpoint stop_bits</code>: 停止位长度 (1, 1.5, 2)。</li><li><code>cross parity_enable, data_bits, stop_bits</code>: 关键配置参数的组合。</li></ul></li><li><strong>操作模式覆盖</strong>:<ul><li><code>coverpoint tx_fifo_level</code>: 发送 FIFO 水位触发中断。</li><li><code>coverpoint rx_fifo_level</code>: 接收 FIFO 水位触发中断。</li><li><code>coverpoint loopback_mode</code>: 环回模式使能&#x2F;禁用。</li></ul></li><li><strong>错误条件覆盖</strong>:<ul><li><code>coverpoint parity_error</code>: 奇偶校验错误。</li><li><code>coverpoint framing_error</code>: 帧错误。</li><li><code>coverpoint overrun_error</code>: 接收覆盖错误。</li></ul></li></ul></li><li><strong>参考</strong>: Verification Academy - UART Example Covergroups (uart_example.tgz)</li></ul></li><li><p><strong>DSP 数据通路设计 (DSP Datapath Style Design, e.g., Filter)</strong></p><ul><li><strong>重点</strong>: 算法参数（”旋钮”）的配置、数据输入的特征（如范围、类型）、边界条件。功能覆盖主要确保算法在不同参数配置和输入数据下的行为被充分测试。</li><li><strong>覆盖项示例 (参考 Biquad IIR Filter)</strong>:<ul><li><code>coverpoint filter_coefficients</code>: 滤波器系数的关键值或范围。</li><li><code>coverpoint input_data_range</code>: 输入数据的幅度范围（最小值、最大值、零值、典型值）。</li><li><code>coverpoint saturation_mode</code>: 饱和模式使能&#x2F;禁用。</li><li><code>coverpoint rounding_mode</code>: 舍入模式配置。</li><li><code>cross filter_coefficients, input_data_range</code>: 特定系数下处理不同范围的数据。</li></ul></li><li><strong>参考</strong>: Verification Academy - Biquad IIR Filter (biquad_example.tgz)</li></ul></li><li><p><strong>聚合器&#x2F;控制器类型 (Aggregator&#x2F;Controller Style, e.g., Memory Controller)</strong></p><ul><li><strong>重点</strong>: 多端口输入的抽象激励组合、配置寄存器覆盖、目标协议（如 DDR）的关键特性覆盖、性能相关场景。</li><li><strong>覆盖项示例</strong>:<ul><li><code>coverpoint num_active_ports</code>: 同时活动的端口数量。</li><li><code>coverpoint request_type_mix</code>: 不同端口请求类型（读&#x2F;写&#x2F;刷新）的组合。</li><li><code>coverpoint arbitration_scenarios</code>: 仲裁逻辑的不同场景。</li><li><code>coverpoint ddr_mode_registers</code>: DDR 模式寄存器的关键配置。</li><li><code>coverpoint timing_parameters</code>: 关键时序参数（tCAS, tRP, tRCD等）的配置范围。</li><li><code>cross num_active_ports, request_type_mix</code>: 不同负载和请求组合下的行为。</li></ul></li></ul></li><li><p><strong>SoC 系统级 (SoC with Vertical Reuse)</strong></p><ul><li><strong>重点</strong>: 用例驱动 (Use Case Driven) 的场景覆盖、跨模块交互、系统级配置、中断路由、电源管理模式。通常难以直接重用所有模块级覆盖，需要定义更高层级的抽象覆盖。</li><li><strong>覆盖项示例</strong>:<ul><li><code>coverpoint boot_sequence</code>: 不同的启动流程。</li><li><code>coverpoint power_mode_transitions</code>: 系统级电源模式转换。</li><li><code>coverpoint end_to_end_data_flow</code>: 关键数据流路径（如 CPU -&gt; Memory -&gt; Peripheral）。</li><li><code>coverpoint interrupt_handling</code>: 特定中断源到特定处理器的路由和处理。</li><li><code>coverpoint concurrent_bus_access</code>: 多个总线主设备并发访问共享资源。</li></ul></li><li><strong>策略</strong>: 侧重于验证系统级规范和用例，选择性地重用或映射低级别的覆盖信息。</li></ul></li></ol><p>选择合适的覆盖策略需要深入理解设计规范和架构，并结合具体的验证目标。</p><h2 id="4-测试点分解实例与模式库"><a href="#4-测试点分解实例与模式库" class="headerlink" title="4. 测试点分解实例与模式库"></a>4. 测试点分解实例与模式库</h2><h3 id="4-1-通用测试点模式库"><a href="#4-1-通用测试点模式库" class="headerlink" title="4.1 通用测试点模式库"></a>4.1 通用测试点模式库</h3><h4 id="4-1-1-寄存器测试模式"><a href="#4-1-1-寄存器测试模式" class="headerlink" title="4.1.1 寄存器测试模式"></a>4.1.1 寄存器测试模式</h4><pre><code class="highlight mermaid">classDiagram    class RegisterTest &#123;        +reset_value_test()        +read_write_test()        +bit_field_test()        +access_right_test()        +reset_test()        +volatile_test()    &#125;</code></pre><h4 id="4-1-2-状态机测试模式"><a href="#4-1-2-状态机测试模式" class="headerlink" title="4.1.2 状态机测试模式"></a>4.1.2 状态机测试模式</h4><table><thead><tr><th>测试模式</th><th>验证要点</th><th>覆盖指标</th></tr></thead><tbody><tr><td>状态覆盖</td><td>所有定义状态</td><td>100%状态覆盖</td></tr><tr><td>转换覆盖</td><td>合法状态转换</td><td>100%转换覆盖</td></tr><tr><td>非法转换</td><td>错误处理能力</td><td>异常处理覆盖</td></tr><tr><td>并发触发</td><td>多事件竞争</td><td>竞争条件覆盖</td></tr></tbody></table><h4 id="4-1-3-数据通路测试模式"><a href="#4-1-3-数据通路测试模式" class="headerlink" title="4.1.3 数据通路测试模式"></a>4.1.3 数据通路测试模式</h4><ol><li><p><strong>数据完整性</strong>：</p><ul><li>端到端数据校验</li><li>错误注入与恢复</li><li>边界条件测试</li></ul></li><li><p><strong>性能指标</strong>：</p><ul><li>吞吐量测量</li><li>延迟分布</li><li>资源利用率</li></ul></li></ol><h3 id="4-2-AXI总线接口测试点分解"><a href="#4-2-AXI总线接口测试点分解" class="headerlink" title="4.2 AXI总线接口测试点分解"></a>4.2 AXI总线接口测试点分解</h3><h4 id="4-2-1-增强型功能分解"><a href="#4-2-1-增强型功能分解" class="headerlink" title="4.2.1 增强型功能分解"></a>4.2.1 增强型功能分解</h4><h3 id="4-2-2-功能点分解与覆盖映射"><a href="#4-2-2-功能点分解与覆盖映射" class="headerlink" title="4.2.2 功能点分解与覆盖映射"></a>4.2.2 功能点分解与覆盖映射</h3><pre><code class="highlight mermaid">mindmap  root((AXI4 Coverage))    Channel Independence      Write/Read channel并发      Out-of-order完成    Protocol Compliance      握手时序      信号依赖关系      错误响应    Performance      吞吐量测量      延迟分布      Backpressure场景    Corner Cases      极端地址      最大突发长度      最小/最大数据宽度    Power Management      时钟门控      电源状态转换</code></pre><pre><code class="highlight mermaid">mindmap  root((AXI Interface))    Write Channel      Address Phase        AWVALID/AWREADY handshake        AWADDR alignment        AWLEN (burst length)        AWSIZE (transfer size)        AWBURST (burst type: FIXED, INCR, WRAP)        AWCACHE/AWPROT/AWQOS/AWREGION        AWLOCK        AWID      Data Phase        WVALID/WREADY handshake        WDATA alignment (based on AWSIZE)        WSTRB (byte strobes)        WLAST signal timing        WID matching AWID      Response Phase        BVALID/BREADY handshake        BRESP (OKAY, EXOKAY, SLVERR, DECERR)        BID matching AWID    Read Channel      Address Phase        ARVALID/ARREADY handshake        ARADDR alignment        ARLEN (burst length)        ARSIZE (transfer size)        ARBURST (burst type: FIXED, INCR, WRAP)        ARCACHE/ARPROT/ARQOS/ARREGION        ARLOCK        ARID      Data Phase        RVALID/RREADY handshake        RDATA alignment (based on ARSIZE)        RLAST signal timing        RRESP (OKAY, EXOKAY, SLVERR, DECERR)        RID matching ARID    Inter-channel Timing      Address-Data relationship      Address-Response relationship      Data-Response relationship (Read)    Low Power Interface      CSYSREQ/CSYSACK      CACTIVE    Ordering      Write data reordering      Read data reordering      Interleaved Read/Write    Error Conditions      Slave Error (SLVERR)      Decode Error (DECERR)      Timeout scenarios</code></pre><h3 id="4-2-3-测试点与覆盖点增强映射"><a href="#4-2-3-测试点与覆盖点增强映射" class="headerlink" title="4.2.3 测试点与覆盖点增强映射"></a>4.2.3 测试点与覆盖点增强映射</h3><table><thead><tr><th>测试点 ID</th><th>描述</th><th>覆盖模型</th><th>验证方法</th></tr></thead><tbody><tr><td>TP-AXI-001</td><td>写地址通道基本握手</td><td><code>cross awvalid, awready</code></td><td>随机测试</td></tr><tr><td>TP-AXI-002</td><td>突发传输地址计算</td><td><code>coverpoint addr_incr</code></td><td>定向测试</td></tr><tr><td>TP-AXI-003</td><td>跨通道依赖关系</td><td><code>cross write_addr, read_data</code></td><td>形式验证</td></tr><tr><td>TP-AXI-004</td><td>低功耗接口时序</td><td><code>coverpoint cactive</code></td><td>功耗验证</td></tr><tr><td>TP-AXI-005</td><td>最大负载性能</td><td><code>coverpoint throughput</code></td><td>性能测试</td></tr></tbody></table><h4 id="4-2-4-AXI覆盖组参考实现"><a href="#4-2-4-AXI覆盖组参考实现" class="headerlink" title="4.2.4 AXI覆盖组参考实现"></a>4.2.4 AXI覆盖组参考实现</h4><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">covergroup</span> axi4_coverage;</span><br><span class="line">    <span class="comment">// 地址通道</span></span><br><span class="line">    cp_awburst: <span class="keyword">coverpoint</span> awburst &#123;</span><br><span class="line">        <span class="keyword">bins</span> fix = &#123;AXI_FIXED&#125;;</span><br><span class="line">        <span class="keyword">bins</span> incr = &#123;AXI_INCR&#125;;</span><br><span class="line">        <span class="keyword">bins</span> wrap = &#123;AXI_WRAP&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    cp_awsize: <span class="keyword">coverpoint</span> awsize &#123;</span><br><span class="line">        <span class="keyword">bins</span> bytes1 = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">        <span class="keyword">bins</span> bytes2 = &#123;<span class="number">1</span>&#125;;</span><br><span class="line">        <span class="comment">// ...其他大小</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 数据通道</span></span><br><span class="line">    cp_wlast: <span class="keyword">coverpoint</span> wlast &#123;</span><br><span class="line">        <span class="keyword">bins</span> last = &#123;<span class="number">1</span>&#125;;</span><br><span class="line">        <span class="keyword">bins</span> not_last = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 交叉覆盖</span></span><br></pre></td></tr></table></figure><pre><code class="highlight mermaid">mindmap  root((AXI Interface))    Write Channel      Address Phase        AWVALID/AWREADY handshake        AWADDR alignment        AWLEN (burst length)        AWSIZE (transfer size)        AWBURST (burst type: FIXED, INCR, WRAP)        AWCACHE/AWPROT/AWQOS/AWREGION        AWLOCK        AWID      Data Phase        WVALID/WREADY handshake        WDATA alignment (based on AWSIZE)        WSTRB (byte strobes)        WLAST signal timing        WID matching AWID      Response Phase        BVALID/BREADY handshake        BRESP (OKAY, EXOKAY, SLVERR, DECERR)        BID matching AWID    Read Channel      Address Phase        ARVALID/ARREADY handshake        ARADDR alignment        ARLEN (burst length)        ARSIZE (transfer size)        ARBURST (burst type: FIXED, INCR, WRAP)        ARCACHE/ARPROT/ARQOS/ARREGION        ARLOCK        ARID      Data Phase        RVALID/RREADY handshake        RDATA alignment (based on ARSIZE)        RLAST signal timing        RRESP (OKAY, EXOKAY, SLVERR, DECERR)        RID matching ARID    Inter-channel Timing      Address-Data relationship      Address-Response relationship      Data-Response relationship (Read)    Low Power Interface      CSYSREQ/CSYSACK      CACTIVE    Ordering      Write data reordering      Read data reordering      Interleaved Read/Write    Error Conditions      Slave Error (SLVERR)      Decode Error (DECERR)      Timeout scenarios</code></pre><h3 id="4-2-测试点与覆盖点映射示例-部分"><a href="#4-2-测试点与覆盖点映射示例-部分" class="headerlink" title="4.2 测试点与覆盖点映射示例 (部分)"></a>4.2 测试点与覆盖点映射示例 (部分)</h3><table><thead><tr><th>测试点 ID</th><th>测试点描述</th><th>优先级</th><th>关键变量&#x2F;事件</th><th>覆盖点&#x2F;交叉覆盖 (概念)</th></tr></thead><tbody><tr><td>TP-W-001</td><td>验证写地址通道握手 (AWVALID&#x2F;AWREADY)</td><td>高</td><td>AWVALID, AWREADY</td><td><code>cp_awvalid : coverpoint awvalid; cp_awready : coverpoint awready; cross cp_awvalid, cp_awready;</code></td></tr><tr><td>TP-W-002</td><td>验证所有合法的 AWBURST 类型 (INCR, FIXED, WRAP)</td><td>高</td><td>AWBURST</td><td><code>cp_awburst : coverpoint awburst &#123; bins incr=&#123;INCR&#125;; bins fixed=&#123;FIXED&#125;; bins wrap=&#123;WRAP&#125;; &#125;</code></td></tr><tr><td>TP-W-003</td><td>验证不同 AWSIZE 和 AWLEN 的组合</td><td>中</td><td>AWSIZE, AWLEN</td><td><code>cp_awsize : coverpoint awsize; cp_awlen : coverpoint awlen; cross cp_awsize, cp_awlen;</code></td></tr><tr><td>TP-W-004</td><td>验证写数据通道 WLAST 信号在突发结束时拉高</td><td>高</td><td>WLAST, burst_end</td><td><code>cp_wlast_end : coverpoint wlast iff (burst_end);</code></td></tr><tr><td>TP-W-005</td><td>验证写响应 BRESP 的所有可能值</td><td>高</td><td>BRESP</td><td><code>cp_bresp : coverpoint bresp &#123; bins okay=&#123;OKAY&#125;; bins slverr=&#123;SLVERR&#125;; ... &#125;;</code></td></tr><tr><td>TP-R-001</td><td>验证读地址通道 ARBURST&#x3D;INCR 时的地址递增</td><td>高</td><td>ARBURST, ARADDR</td><td><code>cp_araddr_incr : coverpoint araddr iff (arburst==INCR &amp;&amp; arvalid &amp;&amp; arready);</code></td></tr><tr><td>TP-ERR-01</td><td>验证 SLVERR 响应</td><td>高</td><td>BRESP &#x2F; RRESP</td><td>(包含在 cp_bresp &#x2F; cp_rresp 中)</td></tr><tr><td>TP-ORD-01</td><td>验证不同 ID 的写事务可以乱序完成</td><td>中</td><td>AWID, BID, write_comp</td><td><code>cp_write_ooo : coverpoint ...</code> (需要更复杂的覆盖结构或断言)</td></tr></tbody></table><h2 id="6-测试点管理与工具"><a href="#6-测试点管理与工具" class="headerlink" title="6. 测试点管理与工具"></a>6. 测试点管理与工具</h2><p>随着设计复杂度的增加，测试点的数量可能非常庞大，有效的管理至关重要。</p><ul><li><strong>测试点数据库&#x2F;表格</strong>：使用 Excel、数据库或专业的需求&#x2F;测试管理工具来存储、分类、跟踪测试点。应包含 ID、描述、来源（规范章节）、优先级、状态（已定义、已实现、已覆盖）、负责人等信息。</li><li><strong>可追溯性链接</strong>：建立从<strong>原始需求 (Validation)</strong> -&gt; <strong>设计规范</strong> -&gt; 测试点 (Verification) -&gt; 测试用例 -&gt; 覆盖模型 -&gt; 测试结果 的双向追溯链接。这有助于评估需求覆盖情况、分析测试失败原因以及进行影响分析，<strong>连接验证与确认活动</strong>。</li><li><strong>版本控制</strong>：将测试点文档纳入版本控制系统（如 Git），管理变更历史。</li><li><strong>评审流程</strong>：建立正式的测试点评审流程，确保其准确性、完整性和可测性。</li><li><strong>自动化报告</strong>：利用脚本或工具自动生成测试点覆盖状态报告，监控验证进度。</li><li><strong>集成化平台</strong>：一些先进的验证管理平台（如 Cadence vManager, Synopsys Verdi）提供了更强大的测试计划、测试点管理和覆盖率整合分析功能。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;测试点分解：验证与确认过程的关键环节&quot;&gt;&lt;a href=&quot;#测试点分解：验证与确认过程的关键环节&quot; class=&quot;headerlink&quot; title=&quot;测试点分解：验证与确认过程的关键环节&quot;&gt;&lt;/a&gt;测试点分解：验证与确认过程的关键环节&lt;/h1&gt;&lt;h2 id=&quot;0</summary>
      
    
    
    
    <category term="验证方法" scheme="https://sqlmaps.com/categories/%E9%AA%8C%E8%AF%81%E6%96%B9%E6%B3%95/"/>
    
    
    <category term="验证方法" scheme="https://sqlmaps.com/tags/%E9%AA%8C%E8%AF%81%E6%96%B9%E6%B3%95/"/>
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
  </entry>
  
  <entry>
    <title>gvim 热键图</title>
    <link href="https://sqlmaps.com/2026/07/08/gvim-%E7%83%AD%E9%94%AE%E5%9B%BE/"/>
    <id>https://sqlmaps.com/2026/07/08/gvim-%E7%83%AD%E9%94%AE%E5%9B%BE/</id>
    <published>2026-07-08T14:21:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h1 id="热键图1"><a href="#热键图1" class="headerlink" title="热键图1"></a>热键图1</h1><p><img src="/img/gvim1.jpg" alt="image"></p><h1 id="热键图2"><a href="#热键图2" class="headerlink" title="热键图2"></a>热键图2</h1><p><img src="/img/gvim2.jpg" alt="image"></p><h1 id="热键图3"><a href="#热键图3" class="headerlink" title="热键图3"></a>热键图3</h1><p><img src="/img/gvim3.jpg" alt="image"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;热键图1&quot;&gt;&lt;a href=&quot;#热键图1&quot; class=&quot;headerlink&quot; title=&quot;热键图1&quot;&gt;&lt;/a&gt;热键图1&lt;/h1&gt;&lt;p&gt;&lt;img src=&quot;/img/gvim1.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;热键图2&quot;&gt;&lt;a hr</summary>
      
    
    
    
    <category term="工具" scheme="https://sqlmaps.com/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://sqlmaps.com/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="开发环境" scheme="https://sqlmaps.com/tags/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/"/>
    
  </entry>
  
  <entry>
    <title>gvim UVM Snippets</title>
    <link href="https://sqlmaps.com/2026/07/08/gvim-UVM-snippets/"/>
    <id>https://sqlmaps.com/2026/07/08/gvim-UVM-snippets/</id>
    <published>2026-07-08T14:20:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<details><summary>点击查看代码</summary><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br><span class="line">754</span><br><span class="line">755</span><br><span class="line">756</span><br><span class="line">757</span><br><span class="line">758</span><br><span class="line">759</span><br><span class="line">760</span><br><span class="line">761</span><br><span class="line">762</span><br><span class="line">763</span><br><span class="line">764</span><br><span class="line">765</span><br><span class="line">766</span><br><span class="line">767</span><br><span class="line">768</span><br><span class="line">769</span><br><span class="line">770</span><br><span class="line">771</span><br><span class="line">772</span><br><span class="line">773</span><br><span class="line">774</span><br><span class="line">775</span><br><span class="line">776</span><br><span class="line">777</span><br><span class="line">778</span><br><span class="line">779</span><br><span class="line">780</span><br><span class="line">781</span><br><span class="line">782</span><br><span class="line">783</span><br><span class="line">784</span><br><span class="line">785</span><br><span class="line">786</span><br><span class="line">787</span><br><span class="line">788</span><br><span class="line">789</span><br><span class="line">790</span><br><span class="line">791</span><br><span class="line">792</span><br><span class="line">793</span><br><span class="line">794</span><br><span class="line">795</span><br><span class="line">796</span><br><span class="line">797</span><br><span class="line">798</span><br><span class="line">799</span><br><span class="line">800</span><br><span class="line">801</span><br><span class="line">802</span><br><span class="line">803</span><br><span class="line">804</span><br><span class="line">805</span><br><span class="line">806</span><br><span class="line">807</span><br><span class="line">808</span><br><span class="line">809</span><br><span class="line">810</span><br><span class="line">811</span><br><span class="line">812</span><br><span class="line">813</span><br><span class="line">814</span><br><span class="line">815</span><br><span class="line">816</span><br><span class="line">817</span><br><span class="line">818</span><br><span class="line">819</span><br><span class="line">820</span><br><span class="line">821</span><br><span class="line">822</span><br><span class="line">823</span><br><span class="line">824</span><br><span class="line">825</span><br><span class="line">826</span><br><span class="line">827</span><br><span class="line">828</span><br><span class="line">829</span><br><span class="line">830</span><br><span class="line">831</span><br><span class="line">832</span><br><span class="line">833</span><br><span class="line">834</span><br><span class="line">835</span><br><span class="line">836</span><br><span class="line">837</span><br><span class="line">838</span><br><span class="line">839</span><br><span class="line">840</span><br><span class="line">841</span><br><span class="line">842</span><br><span class="line">843</span><br><span class="line">844</span><br><span class="line">845</span><br><span class="line">846</span><br><span class="line">847</span><br><span class="line">848</span><br><span class="line">849</span><br><span class="line">850</span><br><span class="line">851</span><br><span class="line">852</span><br><span class="line">853</span><br><span class="line">854</span><br><span class="line">855</span><br><span class="line">856</span><br><span class="line">857</span><br><span class="line">858</span><br><span class="line">859</span><br><span class="line">860</span><br><span class="line">861</span><br><span class="line">862</span><br><span class="line">863</span><br><span class="line">864</span><br><span class="line">865</span><br><span class="line">866</span><br><span class="line">867</span><br><span class="line">868</span><br><span class="line">869</span><br><span class="line">870</span><br><span class="line">871</span><br><span class="line">872</span><br><span class="line">873</span><br><span class="line">874</span><br><span class="line">875</span><br><span class="line">876</span><br><span class="line">877</span><br><span class="line">878</span><br><span class="line">879</span><br><span class="line">880</span><br><span class="line">881</span><br><span class="line">882</span><br><span class="line">883</span><br><span class="line">884</span><br><span class="line">885</span><br><span class="line">886</span><br><span class="line">887</span><br><span class="line">888</span><br><span class="line">889</span><br><span class="line">890</span><br><span class="line">891</span><br><span class="line">892</span><br><span class="line">893</span><br><span class="line">894</span><br><span class="line">895</span><br><span class="line">896</span><br><span class="line">897</span><br><span class="line">898</span><br><span class="line">899</span><br><span class="line">900</span><br><span class="line">901</span><br><span class="line">902</span><br><span class="line">903</span><br><span class="line">904</span><br><span class="line">905</span><br><span class="line">906</span><br><span class="line">907</span><br><span class="line">908</span><br><span class="line">909</span><br><span class="line">910</span><br><span class="line">911</span><br><span class="line">912</span><br><span class="line">913</span><br><span class="line">914</span><br><span class="line">915</span><br><span class="line">916</span><br><span class="line">917</span><br><span class="line">918</span><br><span class="line">919</span><br><span class="line">920</span><br><span class="line">921</span><br><span class="line">922</span><br><span class="line">923</span><br><span class="line">924</span><br><span class="line">925</span><br><span class="line">926</span><br><span class="line">927</span><br><span class="line">928</span><br><span class="line">929</span><br><span class="line">930</span><br><span class="line">931</span><br><span class="line">932</span><br><span class="line">933</span><br><span class="line">934</span><br><span class="line">935</span><br><span class="line">936</span><br><span class="line">937</span><br><span class="line">938</span><br><span class="line">939</span><br><span class="line">940</span><br><span class="line">941</span><br><span class="line">942</span><br><span class="line">943</span><br><span class="line">944</span><br><span class="line">945</span><br><span class="line">946</span><br><span class="line">947</span><br><span class="line">948</span><br><span class="line">949</span><br><span class="line">950</span><br><span class="line">951</span><br><span class="line">952</span><br><span class="line">953</span><br><span class="line">954</span><br><span class="line">955</span><br><span class="line">956</span><br><span class="line">957</span><br><span class="line">958</span><br><span class="line">959</span><br><span class="line">960</span><br><span class="line">961</span><br><span class="line">962</span><br><span class="line">963</span><br><span class="line">964</span><br><span class="line">965</span><br><span class="line">966</span><br><span class="line">967</span><br><span class="line">968</span><br><span class="line">969</span><br><span class="line">970</span><br><span class="line">971</span><br><span class="line">972</span><br><span class="line">973</span><br><span class="line">974</span><br><span class="line">975</span><br><span class="line">976</span><br><span class="line">977</span><br><span class="line">978</span><br><span class="line">979</span><br><span class="line">980</span><br><span class="line">981</span><br><span class="line">982</span><br><span class="line">983</span><br><span class="line">984</span><br><span class="line">985</span><br><span class="line">986</span><br><span class="line">987</span><br><span class="line">988</span><br><span class="line">989</span><br><span class="line">990</span><br><span class="line">991</span><br><span class="line">992</span><br><span class="line">993</span><br><span class="line">994</span><br><span class="line">995</span><br><span class="line">996</span><br><span class="line">997</span><br><span class="line">998</span><br><span class="line">999</span><br><span class="line">1000</span><br><span class="line">1001</span><br><span class="line">1002</span><br><span class="line">1003</span><br><span class="line">1004</span><br><span class="line">1005</span><br><span class="line">1006</span><br><span class="line">1007</span><br><span class="line">1008</span><br><span class="line">1009</span><br><span class="line">1010</span><br><span class="line">1011</span><br><span class="line">1012</span><br><span class="line">1013</span><br><span class="line">1014</span><br><span class="line">1015</span><br><span class="line">1016</span><br><span class="line">1017</span><br><span class="line">1018</span><br><span class="line">1019</span><br><span class="line">1020</span><br><span class="line">1021</span><br><span class="line">1022</span><br><span class="line">1023</span><br><span class="line">1024</span><br><span class="line">1025</span><br><span class="line">1026</span><br><span class="line">1027</span><br><span class="line">1028</span><br><span class="line">1029</span><br><span class="line">1030</span><br><span class="line">1031</span><br><span class="line">1032</span><br><span class="line">1033</span><br><span class="line">1034</span><br><span class="line">1035</span><br><span class="line">1036</span><br><span class="line">1037</span><br><span class="line">1038</span><br><span class="line">1039</span><br><span class="line">1040</span><br><span class="line">1041</span><br><span class="line">1042</span><br><span class="line">1043</span><br><span class="line">1044</span><br><span class="line">1045</span><br><span class="line">1046</span><br><span class="line">1047</span><br><span class="line">1048</span><br><span class="line">1049</span><br><span class="line">1050</span><br><span class="line">1051</span><br><span class="line">1052</span><br><span class="line">1053</span><br><span class="line">1054</span><br><span class="line">1055</span><br><span class="line">1056</span><br><span class="line">1057</span><br><span class="line">1058</span><br><span class="line">1059</span><br><span class="line">1060</span><br><span class="line">1061</span><br><span class="line">1062</span><br><span class="line">1063</span><br><span class="line">1064</span><br><span class="line">1065</span><br><span class="line">1066</span><br><span class="line">1067</span><br><span class="line">1068</span><br><span class="line">1069</span><br><span class="line">1070</span><br><span class="line">1071</span><br><span class="line">1072</span><br><span class="line">1073</span><br><span class="line">1074</span><br><span class="line">1075</span><br><span class="line">1076</span><br><span class="line">1077</span><br><span class="line">1078</span><br><span class="line">1079</span><br><span class="line">1080</span><br><span class="line">1081</span><br><span class="line">1082</span><br><span class="line">1083</span><br><span class="line">1084</span><br><span class="line">1085</span><br><span class="line">1086</span><br><span class="line">1087</span><br><span class="line">1088</span><br><span class="line">1089</span><br><span class="line">1090</span><br><span class="line">1091</span><br><span class="line">1092</span><br><span class="line">1093</span><br><span class="line">1094</span><br><span class="line">1095</span><br><span class="line">1096</span><br><span class="line">1097</span><br><span class="line">1098</span><br><span class="line">1099</span><br><span class="line">1100</span><br><span class="line">1101</span><br><span class="line">1102</span><br><span class="line">1103</span><br><span class="line">1104</span><br><span class="line">1105</span><br><span class="line">1106</span><br><span class="line">1107</span><br><span class="line">1108</span><br><span class="line">1109</span><br><span class="line">1110</span><br><span class="line">1111</span><br><span class="line">1112</span><br><span class="line">1113</span><br><span class="line">1114</span><br><span class="line">1115</span><br><span class="line">1116</span><br><span class="line">1117</span><br><span class="line">1118</span><br><span class="line">1119</span><br><span class="line">1120</span><br><span class="line">1121</span><br><span class="line">1122</span><br><span class="line">1123</span><br><span class="line">1124</span><br><span class="line">1125</span><br><span class="line">1126</span><br><span class="line">1127</span><br><span class="line">1128</span><br><span class="line">1129</span><br><span class="line">1130</span><br><span class="line">1131</span><br><span class="line">1132</span><br><span class="line">1133</span><br><span class="line">1134</span><br><span class="line">1135</span><br><span class="line">1136</span><br><span class="line">1137</span><br><span class="line">1138</span><br><span class="line">1139</span><br><span class="line">1140</span><br><span class="line">1141</span><br><span class="line">1142</span><br><span class="line">1143</span><br><span class="line">1144</span><br><span class="line">1145</span><br><span class="line">1146</span><br><span class="line">1147</span><br><span class="line">1148</span><br><span class="line">1149</span><br><span class="line">1150</span><br><span class="line">1151</span><br><span class="line">1152</span><br><span class="line">1153</span><br><span class="line">1154</span><br><span class="line">1155</span><br><span class="line">1156</span><br><span class="line">1157</span><br><span class="line">1158</span><br><span class="line">1159</span><br><span class="line">1160</span><br><span class="line">1161</span><br><span class="line">1162</span><br><span class="line">1163</span><br><span class="line">1164</span><br><span class="line">1165</span><br><span class="line">1166</span><br><span class="line">1167</span><br><span class="line">1168</span><br><span class="line">1169</span><br><span class="line">1170</span><br><span class="line">1171</span><br><span class="line">1172</span><br><span class="line">1173</span><br><span class="line">1174</span><br><span class="line">1175</span><br><span class="line">1176</span><br><span class="line">1177</span><br><span class="line">1178</span><br><span class="line">1179</span><br><span class="line">1180</span><br><span class="line">1181</span><br><span class="line">1182</span><br><span class="line">1183</span><br><span class="line">1184</span><br><span class="line">1185</span><br><span class="line">1186</span><br><span class="line">1187</span><br><span class="line">1188</span><br><span class="line">1189</span><br><span class="line">1190</span><br><span class="line">1191</span><br><span class="line">1192</span><br><span class="line">1193</span><br><span class="line">1194</span><br><span class="line">1195</span><br><span class="line">1196</span><br><span class="line">1197</span><br><span class="line">1198</span><br><span class="line">1199</span><br><span class="line">1200</span><br><span class="line">1201</span><br><span class="line">1202</span><br><span class="line">1203</span><br><span class="line">1204</span><br><span class="line">1205</span><br><span class="line">1206</span><br><span class="line">1207</span><br><span class="line">1208</span><br><span class="line">1209</span><br><span class="line">1210</span><br><span class="line">1211</span><br><span class="line">1212</span><br><span class="line">1213</span><br><span class="line">1214</span><br><span class="line">1215</span><br><span class="line">1216</span><br><span class="line">1217</span><br><span class="line">1218</span><br><span class="line">1219</span><br><span class="line">1220</span><br><span class="line">1221</span><br><span class="line">1222</span><br><span class="line">1223</span><br><span class="line">1224</span><br><span class="line">1225</span><br><span class="line">1226</span><br><span class="line">1227</span><br><span class="line">1228</span><br><span class="line">1229</span><br><span class="line">1230</span><br><span class="line">1231</span><br><span class="line">1232</span><br><span class="line">1233</span><br><span class="line">1234</span><br><span class="line">1235</span><br><span class="line">1236</span><br><span class="line">1237</span><br><span class="line">1238</span><br><span class="line">1239</span><br><span class="line">1240</span><br><span class="line">1241</span><br><span class="line">1242</span><br><span class="line">1243</span><br><span class="line">1244</span><br><span class="line">1245</span><br><span class="line">1246</span><br><span class="line">1247</span><br><span class="line">1248</span><br><span class="line">1249</span><br><span class="line">1250</span><br><span class="line">1251</span><br><span class="line">1252</span><br><span class="line">1253</span><br><span class="line">1254</span><br><span class="line">1255</span><br><span class="line">1256</span><br><span class="line">1257</span><br><span class="line">1258</span><br><span class="line">1259</span><br><span class="line">1260</span><br><span class="line">1261</span><br><span class="line">1262</span><br><span class="line">1263</span><br><span class="line">1264</span><br><span class="line">1265</span><br><span class="line">1266</span><br><span class="line">1267</span><br><span class="line">1268</span><br><span class="line">1269</span><br><span class="line">1270</span><br><span class="line">1271</span><br><span class="line">1272</span><br><span class="line">1273</span><br><span class="line">1274</span><br><span class="line">1275</span><br><span class="line">1276</span><br><span class="line">1277</span><br><span class="line">1278</span><br><span class="line">1279</span><br><span class="line">1280</span><br><span class="line">1281</span><br><span class="line">1282</span><br><span class="line">1283</span><br><span class="line">1284</span><br><span class="line">1285</span><br><span class="line">1286</span><br><span class="line">1287</span><br><span class="line">1288</span><br><span class="line">1289</span><br><span class="line">1290</span><br><span class="line">1291</span><br><span class="line">1292</span><br><span class="line">1293</span><br><span class="line">1294</span><br><span class="line">1295</span><br><span class="line">1296</span><br><span class="line">1297</span><br><span class="line">1298</span><br><span class="line">1299</span><br><span class="line">1300</span><br><span class="line">1301</span><br><span class="line">1302</span><br><span class="line">1303</span><br><span class="line">1304</span><br><span class="line">1305</span><br><span class="line">1306</span><br><span class="line">1307</span><br><span class="line">1308</span><br><span class="line">1309</span><br><span class="line">1310</span><br><span class="line">1311</span><br><span class="line">1312</span><br><span class="line">1313</span><br><span class="line">1314</span><br><span class="line">1315</span><br><span class="line">1316</span><br><span class="line">1317</span><br><span class="line">1318</span><br><span class="line">1319</span><br><span class="line">1320</span><br><span class="line">1321</span><br><span class="line">1322</span><br><span class="line">1323</span><br><span class="line">1324</span><br><span class="line">1325</span><br><span class="line">1326</span><br><span class="line">1327</span><br><span class="line">1328</span><br><span class="line">1329</span><br><span class="line">1330</span><br><span class="line">1331</span><br><span class="line">1332</span><br><span class="line">1333</span><br><span class="line">1334</span><br><span class="line">1335</span><br><span class="line">1336</span><br><span class="line">1337</span><br><span class="line">1338</span><br><span class="line">1339</span><br><span class="line">1340</span><br><span class="line">1341</span><br><span class="line">1342</span><br><span class="line">1343</span><br><span class="line">1344</span><br><span class="line">1345</span><br><span class="line">1346</span><br><span class="line">1347</span><br><span class="line">1348</span><br><span class="line">1349</span><br><span class="line">1350</span><br><span class="line">1351</span><br><span class="line">1352</span><br><span class="line">1353</span><br><span class="line">1354</span><br><span class="line">1355</span><br><span class="line">1356</span><br><span class="line">1357</span><br><span class="line">1358</span><br><span class="line">1359</span><br><span class="line">1360</span><br><span class="line">1361</span><br><span class="line">1362</span><br><span class="line">1363</span><br><span class="line">1364</span><br><span class="line">1365</span><br><span class="line">1366</span><br><span class="line">1367</span><br><span class="line">1368</span><br><span class="line">1369</span><br><span class="line">1370</span><br><span class="line">1371</span><br><span class="line">1372</span><br><span class="line">1373</span><br><span class="line">1374</span><br><span class="line">1375</span><br><span class="line">1376</span><br><span class="line">1377</span><br><span class="line">1378</span><br><span class="line">1379</span><br><span class="line">1380</span><br><span class="line">1381</span><br><span class="line">1382</span><br><span class="line">1383</span><br><span class="line">1384</span><br><span class="line">1385</span><br><span class="line">1386</span><br><span class="line">1387</span><br><span class="line">1388</span><br><span class="line">1389</span><br><span class="line">1390</span><br><span class="line">1391</span><br><span class="line">1392</span><br><span class="line">1393</span><br><span class="line">1394</span><br><span class="line">1395</span><br><span class="line">1396</span><br><span class="line">1397</span><br><span class="line">1398</span><br><span class="line">1399</span><br><span class="line">1400</span><br><span class="line">1401</span><br><span class="line">1402</span><br><span class="line">1403</span><br><span class="line">1404</span><br><span class="line">1405</span><br><span class="line">1406</span><br><span class="line">1407</span><br><span class="line">1408</span><br><span class="line">1409</span><br><span class="line">1410</span><br><span class="line">1411</span><br><span class="line">1412</span><br><span class="line">1413</span><br><span class="line">1414</span><br><span class="line">1415</span><br><span class="line">1416</span><br><span class="line">1417</span><br><span class="line">1418</span><br><span class="line">1419</span><br><span class="line">1420</span><br><span class="line">1421</span><br><span class="line">1422</span><br><span class="line">1423</span><br><span class="line">1424</span><br><span class="line">1425</span><br><span class="line">1426</span><br><span class="line">1427</span><br><span class="line">1428</span><br><span class="line">1429</span><br><span class="line">1430</span><br><span class="line">1431</span><br><span class="line">1432</span><br><span class="line">1433</span><br><span class="line">1434</span><br><span class="line">1435</span><br><span class="line">1436</span><br><span class="line">1437</span><br><span class="line">1438</span><br><span class="line">1439</span><br><span class="line">1440</span><br><span class="line">1441</span><br><span class="line">1442</span><br><span class="line">1443</span><br><span class="line">1444</span><br><span class="line">1445</span><br><span class="line">1446</span><br><span class="line">1447</span><br><span class="line">1448</span><br><span class="line">1449</span><br><span class="line">1450</span><br><span class="line">1451</span><br><span class="line">1452</span><br><span class="line">1453</span><br><span class="line">1454</span><br><span class="line">1455</span><br><span class="line">1456</span><br><span class="line">1457</span><br><span class="line">1458</span><br><span class="line">1459</span><br><span class="line">1460</span><br><span class="line">1461</span><br><span class="line">1462</span><br><span class="line">1463</span><br><span class="line">1464</span><br><span class="line">1465</span><br><span class="line">1466</span><br><span class="line">1467</span><br><span class="line">1468</span><br><span class="line">1469</span><br><span class="line">1470</span><br><span class="line">1471</span><br><span class="line">1472</span><br><span class="line">1473</span><br><span class="line">1474</span><br><span class="line">1475</span><br><span class="line">1476</span><br><span class="line">1477</span><br><span class="line">1478</span><br><span class="line">1479</span><br><span class="line">1480</span><br><span class="line">1481</span><br><span class="line">1482</span><br><span class="line">1483</span><br><span class="line">1484</span><br><span class="line">1485</span><br><span class="line">1486</span><br><span class="line">1487</span><br><span class="line">1488</span><br><span class="line">1489</span><br><span class="line">1490</span><br><span class="line">1491</span><br><span class="line">1492</span><br><span class="line">1493</span><br><span class="line">1494</span><br><span class="line">1495</span><br><span class="line">1496</span><br><span class="line">1497</span><br><span class="line">1498</span><br><span class="line">1499</span><br><span class="line">1500</span><br><span class="line">1501</span><br><span class="line">1502</span><br><span class="line">1503</span><br><span class="line">1504</span><br><span class="line">1505</span><br><span class="line">1506</span><br><span class="line">1507</span><br><span class="line">1508</span><br><span class="line">1509</span><br><span class="line">1510</span><br><span class="line">1511</span><br><span class="line">1512</span><br><span class="line">1513</span><br><span class="line">1514</span><br><span class="line">1515</span><br><span class="line">1516</span><br><span class="line">1517</span><br><span class="line">1518</span><br><span class="line">1519</span><br><span class="line">1520</span><br><span class="line">1521</span><br><span class="line">1522</span><br><span class="line">1523</span><br><span class="line">1524</span><br><span class="line">1525</span><br><span class="line">1526</span><br><span class="line">1527</span><br><span class="line">1528</span><br><span class="line">1529</span><br><span class="line">1530</span><br><span class="line">1531</span><br><span class="line">1532</span><br><span class="line">1533</span><br><span class="line">1534</span><br><span class="line">1535</span><br><span class="line">1536</span><br><span class="line">1537</span><br><span class="line">1538</span><br><span class="line">1539</span><br><span class="line">1540</span><br><span class="line">1541</span><br><span class="line">1542</span><br><span class="line">1543</span><br><span class="line">1544</span><br><span class="line">1545</span><br><span class="line">1546</span><br><span class="line">1547</span><br><span class="line">1548</span><br><span class="line">1549</span><br><span class="line">1550</span><br><span class="line">1551</span><br><span class="line">1552</span><br><span class="line">1553</span><br><span class="line">1554</span><br><span class="line">1555</span><br><span class="line">1556</span><br><span class="line">1557</span><br><span class="line">1558</span><br><span class="line">1559</span><br><span class="line">1560</span><br><span class="line">1561</span><br><span class="line">1562</span><br><span class="line">1563</span><br><span class="line">1564</span><br><span class="line">1565</span><br><span class="line">1566</span><br><span class="line">1567</span><br><span class="line">1568</span><br><span class="line">1569</span><br><span class="line">1570</span><br><span class="line">1571</span><br><span class="line">1572</span><br><span class="line">1573</span><br><span class="line">1574</span><br><span class="line">1575</span><br><span class="line">1576</span><br><span class="line">1577</span><br><span class="line">1578</span><br><span class="line">1579</span><br><span class="line">1580</span><br><span class="line">1581</span><br><span class="line">1582</span><br><span class="line">1583</span><br><span class="line">1584</span><br><span class="line">1585</span><br><span class="line">1586</span><br><span class="line">1587</span><br><span class="line">1588</span><br><span class="line">1589</span><br><span class="line">1590</span><br><span class="line">1591</span><br><span class="line">1592</span><br><span class="line">1593</span><br><span class="line">1594</span><br><span class="line">1595</span><br><span class="line">1596</span><br><span class="line">1597</span><br><span class="line">1598</span><br><span class="line">1599</span><br><span class="line">1600</span><br><span class="line">1601</span><br><span class="line">1602</span><br><span class="line">1603</span><br><span class="line">1604</span><br><span class="line">1605</span><br><span class="line">1606</span><br><span class="line">1607</span><br><span class="line">1608</span><br><span class="line">1609</span><br><span class="line">1610</span><br><span class="line">1611</span><br><span class="line">1612</span><br><span class="line">1613</span><br><span class="line">1614</span><br><span class="line">1615</span><br><span class="line">1616</span><br><span class="line">1617</span><br><span class="line">1618</span><br><span class="line">1619</span><br><span class="line">1620</span><br><span class="line">1621</span><br><span class="line">1622</span><br><span class="line">1623</span><br><span class="line">1624</span><br><span class="line">1625</span><br><span class="line">1626</span><br><span class="line">1627</span><br><span class="line">1628</span><br><span class="line">1629</span><br><span class="line">1630</span><br><span class="line">1631</span><br><span class="line">1632</span><br><span class="line">1633</span><br><span class="line">1634</span><br><span class="line">1635</span><br><span class="line">1636</span><br><span class="line">1637</span><br><span class="line">1638</span><br><span class="line">1639</span><br><span class="line">1640</span><br><span class="line">1641</span><br><span class="line">1642</span><br><span class="line">1643</span><br><span class="line">1644</span><br><span class="line">1645</span><br><span class="line">1646</span><br><span class="line">1647</span><br><span class="line">1648</span><br><span class="line">1649</span><br><span class="line">1650</span><br><span class="line">1651</span><br><span class="line">1652</span><br><span class="line">1653</span><br><span class="line">1654</span><br><span class="line">1655</span><br><span class="line">1656</span><br><span class="line">1657</span><br><span class="line">1658</span><br><span class="line">1659</span><br><span class="line">1660</span><br><span class="line">1661</span><br><span class="line">1662</span><br><span class="line">1663</span><br><span class="line">1664</span><br><span class="line">1665</span><br><span class="line">1666</span><br><span class="line">1667</span><br><span class="line">1668</span><br><span class="line">1669</span><br><span class="line">1670</span><br><span class="line">1671</span><br><span class="line">1672</span><br><span class="line">1673</span><br><span class="line">1674</span><br><span class="line">1675</span><br><span class="line">1676</span><br><span class="line">1677</span><br><span class="line">1678</span><br><span class="line">1679</span><br><span class="line">1680</span><br><span class="line">1681</span><br><span class="line">1682</span><br><span class="line">1683</span><br><span class="line">1684</span><br><span class="line">1685</span><br><span class="line">1686</span><br><span class="line">1687</span><br><span class="line">1688</span><br><span class="line">1689</span><br><span class="line">1690</span><br><span class="line">1691</span><br><span class="line">1692</span><br><span class="line">1693</span><br><span class="line">1694</span><br><span class="line">1695</span><br><span class="line">1696</span><br><span class="line">1697</span><br><span class="line">1698</span><br><span class="line">1699</span><br><span class="line">1700</span><br><span class="line">1701</span><br><span class="line">1702</span><br><span class="line">1703</span><br><span class="line">1704</span><br><span class="line">1705</span><br><span class="line">1706</span><br><span class="line">1707</span><br><span class="line">1708</span><br><span class="line">1709</span><br><span class="line">1710</span><br><span class="line">1711</span><br><span class="line">1712</span><br><span class="line">1713</span><br><span class="line">1714</span><br><span class="line">1715</span><br><span class="line">1716</span><br><span class="line">1717</span><br><span class="line">1718</span><br><span class="line">1719</span><br><span class="line">1720</span><br><span class="line">1721</span><br><span class="line">1722</span><br><span class="line">1723</span><br><span class="line">1724</span><br><span class="line">1725</span><br><span class="line">1726</span><br><span class="line">1727</span><br><span class="line">1728</span><br><span class="line">1729</span><br><span class="line">1730</span><br><span class="line">1731</span><br><span class="line">1732</span><br><span class="line">1733</span><br><span class="line">1734</span><br><span class="line">1735</span><br><span class="line">1736</span><br><span class="line">1737</span><br><span class="line">1738</span><br><span class="line">1739</span><br><span class="line">1740</span><br><span class="line">1741</span><br><span class="line">1742</span><br><span class="line">1743</span><br><span class="line">1744</span><br><span class="line">1745</span><br><span class="line">1746</span><br><span class="line">1747</span><br><span class="line">1748</span><br><span class="line">1749</span><br><span class="line">1750</span><br><span class="line">1751</span><br><span class="line">1752</span><br><span class="line">1753</span><br><span class="line">1754</span><br><span class="line">1755</span><br><span class="line">1756</span><br><span class="line">1757</span><br><span class="line">1758</span><br><span class="line">1759</span><br><span class="line">1760</span><br><span class="line">1761</span><br><span class="line">1762</span><br><span class="line">1763</span><br><span class="line">1764</span><br><span class="line">1765</span><br><span class="line">1766</span><br><span class="line">1767</span><br><span class="line">1768</span><br><span class="line">1769</span><br><span class="line">1770</span><br><span class="line">1771</span><br><span class="line">1772</span><br><span class="line">1773</span><br><span class="line">1774</span><br><span class="line">1775</span><br><span class="line">1776</span><br><span class="line">1777</span><br><span class="line">1778</span><br><span class="line">1779</span><br><span class="line">1780</span><br><span class="line">1781</span><br><span class="line">1782</span><br><span class="line">1783</span><br><span class="line">1784</span><br><span class="line">1785</span><br><span class="line">1786</span><br><span class="line">1787</span><br><span class="line">1788</span><br><span class="line">1789</span><br><span class="line">1790</span><br><span class="line">1791</span><br><span class="line">1792</span><br><span class="line">1793</span><br><span class="line">1794</span><br><span class="line">1795</span><br><span class="line">1796</span><br><span class="line">1797</span><br><span class="line">1798</span><br><span class="line">1799</span><br><span class="line">1800</span><br><span class="line">1801</span><br><span class="line">1802</span><br><span class="line">1803</span><br><span class="line">1804</span><br><span class="line">1805</span><br><span class="line">1806</span><br><span class="line">1807</span><br><span class="line">1808</span><br><span class="line">1809</span><br><span class="line">1810</span><br><span class="line">1811</span><br><span class="line">1812</span><br><span class="line">1813</span><br><span class="line">1814</span><br><span class="line">1815</span><br><span class="line">1816</span><br><span class="line">1817</span><br><span class="line">1818</span><br><span class="line">1819</span><br><span class="line">1820</span><br><span class="line">1821</span><br><span class="line">1822</span><br><span class="line">1823</span><br><span class="line">1824</span><br><span class="line">1825</span><br><span class="line">1826</span><br><span class="line">1827</span><br><span class="line">1828</span><br><span class="line">1829</span><br><span class="line">1830</span><br><span class="line">1831</span><br><span class="line">1832</span><br><span class="line">1833</span><br><span class="line">1834</span><br><span class="line">1835</span><br><span class="line">1836</span><br><span class="line">1837</span><br><span class="line">1838</span><br><span class="line">1839</span><br><span class="line">1840</span><br><span class="line">1841</span><br><span class="line">1842</span><br><span class="line">1843</span><br><span class="line">1844</span><br><span class="line">1845</span><br><span class="line">1846</span><br><span class="line">1847</span><br><span class="line">1848</span><br><span class="line">1849</span><br><span class="line">1850</span><br><span class="line">1851</span><br><span class="line">1852</span><br><span class="line">1853</span><br><span class="line">1854</span><br><span class="line">1855</span><br><span class="line">1856</span><br><span class="line">1857</span><br><span class="line">1858</span><br><span class="line">1859</span><br><span class="line">1860</span><br><span class="line">1861</span><br><span class="line">1862</span><br><span class="line">1863</span><br><span class="line">1864</span><br><span class="line">1865</span><br><span class="line">1866</span><br><span class="line">1867</span><br><span class="line">1868</span><br><span class="line">1869</span><br><span class="line">1870</span><br><span class="line">1871</span><br><span class="line">1872</span><br><span class="line">1873</span><br><span class="line">1874</span><br><span class="line">1875</span><br><span class="line">1876</span><br><span class="line">1877</span><br><span class="line">1878</span><br><span class="line">1879</span><br><span class="line">1880</span><br><span class="line">1881</span><br><span class="line">1882</span><br><span class="line">1883</span><br><span class="line">1884</span><br><span class="line">1885</span><br><span class="line">1886</span><br><span class="line">1887</span><br><span class="line">1888</span><br><span class="line">1889</span><br><span class="line">1890</span><br><span class="line">1891</span><br><span class="line">1892</span><br><span class="line">1893</span><br><span class="line">1894</span><br><span class="line">1895</span><br><span class="line">1896</span><br><span class="line">1897</span><br><span class="line">1898</span><br><span class="line">1899</span><br><span class="line">1900</span><br><span class="line">1901</span><br><span class="line">1902</span><br><span class="line">1903</span><br><span class="line">1904</span><br><span class="line">1905</span><br><span class="line">1906</span><br><span class="line">1907</span><br><span class="line">1908</span><br><span class="line">1909</span><br><span class="line">1910</span><br><span class="line">1911</span><br><span class="line">1912</span><br><span class="line">1913</span><br><span class="line">1914</span><br><span class="line">1915</span><br><span class="line">1916</span><br><span class="line">1917</span><br><span class="line">1918</span><br><span class="line">1919</span><br><span class="line">1920</span><br><span class="line">1921</span><br><span class="line">1922</span><br><span class="line">1923</span><br><span class="line">1924</span><br><span class="line">1925</span><br><span class="line">1926</span><br><span class="line">1927</span><br><span class="line">1928</span><br><span class="line">1929</span><br><span class="line">1930</span><br><span class="line">1931</span><br><span class="line">1932</span><br><span class="line">1933</span><br><span class="line">1934</span><br><span class="line">1935</span><br><span class="line">1936</span><br><span class="line">1937</span><br><span class="line">1938</span><br><span class="line">1939</span><br><span class="line">1940</span><br><span class="line">1941</span><br><span class="line">1942</span><br><span class="line">1943</span><br><span class="line">1944</span><br><span class="line">1945</span><br><span class="line">1946</span><br><span class="line">1947</span><br><span class="line">1948</span><br><span class="line">1949</span><br><span class="line">1950</span><br><span class="line">1951</span><br><span class="line">1952</span><br><span class="line">1953</span><br><span class="line">1954</span><br><span class="line">1955</span><br><span class="line">1956</span><br><span class="line">1957</span><br><span class="line">1958</span><br><span class="line">1959</span><br><span class="line">1960</span><br><span class="line">1961</span><br><span class="line">1962</span><br><span class="line">1963</span><br><span class="line">1964</span><br><span class="line">1965</span><br><span class="line">1966</span><br><span class="line">1967</span><br><span class="line">1968</span><br><span class="line">1969</span><br><span class="line">1970</span><br><span class="line">1971</span><br><span class="line">1972</span><br><span class="line">1973</span><br><span class="line">1974</span><br><span class="line">1975</span><br><span class="line">1976</span><br><span class="line">1977</span><br><span class="line">1978</span><br><span class="line">1979</span><br><span class="line">1980</span><br><span class="line">1981</span><br><span class="line">1982</span><br><span class="line">1983</span><br><span class="line">1984</span><br><span class="line">1985</span><br><span class="line">1986</span><br><span class="line">1987</span><br><span class="line">1988</span><br><span class="line">1989</span><br><span class="line">1990</span><br><span class="line">1991</span><br><span class="line">1992</span><br><span class="line">1993</span><br><span class="line">1994</span><br><span class="line">1995</span><br><span class="line">1996</span><br><span class="line">1997</span><br><span class="line">1998</span><br><span class="line">1999</span><br><span class="line">2000</span><br><span class="line">2001</span><br><span class="line">2002</span><br><span class="line">2003</span><br><span class="line">2004</span><br><span class="line">2005</span><br><span class="line">2006</span><br><span class="line">2007</span><br><span class="line">2008</span><br><span class="line">2009</span><br><span class="line">2010</span><br><span class="line">2011</span><br><span class="line">2012</span><br><span class="line">2013</span><br><span class="line">2014</span><br><span class="line">2015</span><br><span class="line">2016</span><br><span class="line">2017</span><br><span class="line">2018</span><br><span class="line">2019</span><br><span class="line">2020</span><br><span class="line">2021</span><br><span class="line">2022</span><br><span class="line">2023</span><br><span class="line">2024</span><br><span class="line">2025</span><br><span class="line">2026</span><br><span class="line">2027</span><br><span class="line">2028</span><br><span class="line">2029</span><br><span class="line">2030</span><br><span class="line">2031</span><br><span class="line">2032</span><br><span class="line">2033</span><br><span class="line">2034</span><br><span class="line">2035</span><br><span class="line">2036</span><br><span class="line">2037</span><br><span class="line">2038</span><br><span class="line">2039</span><br><span class="line">2040</span><br><span class="line">2041</span><br><span class="line">2042</span><br><span class="line">2043</span><br><span class="line">2044</span><br><span class="line">2045</span><br><span class="line">2046</span><br><span class="line">2047</span><br><span class="line">2048</span><br><span class="line">2049</span><br><span class="line">2050</span><br><span class="line">2051</span><br><span class="line">2052</span><br><span class="line">2053</span><br><span class="line">2054</span><br><span class="line">2055</span><br><span class="line">2056</span><br><span class="line">2057</span><br><span class="line">2058</span><br><span class="line">2059</span><br><span class="line">2060</span><br><span class="line">2061</span><br><span class="line">2062</span><br><span class="line">2063</span><br><span class="line">2064</span><br><span class="line">2065</span><br><span class="line">2066</span><br><span class="line">2067</span><br><span class="line">2068</span><br><span class="line">2069</span><br><span class="line">2070</span><br><span class="line">2071</span><br><span class="line">2072</span><br><span class="line">2073</span><br><span class="line">2074</span><br><span class="line">2075</span><br><span class="line">2076</span><br><span class="line">2077</span><br><span class="line">2078</span><br><span class="line">2079</span><br><span class="line">2080</span><br><span class="line">2081</span><br><span class="line">2082</span><br><span class="line">2083</span><br><span class="line">2084</span><br><span class="line">2085</span><br><span class="line">2086</span><br><span class="line">2087</span><br><span class="line">2088</span><br><span class="line">2089</span><br><span class="line">2090</span><br><span class="line">2091</span><br><span class="line">2092</span><br><span class="line">2093</span><br><span class="line">2094</span><br><span class="line">2095</span><br><span class="line">2096</span><br><span class="line">2097</span><br><span class="line">2098</span><br><span class="line">2099</span><br><span class="line">2100</span><br><span class="line">2101</span><br><span class="line">2102</span><br><span class="line">2103</span><br><span class="line">2104</span><br><span class="line">2105</span><br><span class="line">2106</span><br><span class="line">2107</span><br><span class="line">2108</span><br><span class="line">2109</span><br><span class="line">2110</span><br><span class="line">2111</span><br><span class="line">2112</span><br><span class="line">2113</span><br><span class="line">2114</span><br><span class="line">2115</span><br><span class="line">2116</span><br><span class="line">2117</span><br><span class="line">2118</span><br><span class="line">2119</span><br><span class="line">2120</span><br><span class="line">2121</span><br><span class="line">2122</span><br><span class="line">2123</span><br><span class="line">2124</span><br><span class="line">2125</span><br><span class="line">2126</span><br><span class="line">2127</span><br><span class="line">2128</span><br><span class="line">2129</span><br><span class="line">2130</span><br><span class="line">2131</span><br><span class="line">2132</span><br><span class="line">2133</span><br><span class="line">2134</span><br><span class="line">2135</span><br><span class="line">2136</span><br><span class="line">2137</span><br><span class="line">2138</span><br><span class="line">2139</span><br><span class="line">2140</span><br><span class="line">2141</span><br><span class="line">2142</span><br><span class="line">2143</span><br><span class="line">2144</span><br><span class="line">2145</span><br><span class="line">2146</span><br><span class="line">2147</span><br><span class="line">2148</span><br><span class="line">2149</span><br><span class="line">2150</span><br><span class="line">2151</span><br><span class="line">2152</span><br><span class="line">2153</span><br><span class="line">2154</span><br><span class="line">2155</span><br><span class="line">2156</span><br><span class="line">2157</span><br><span class="line">2158</span><br><span class="line">2159</span><br><span class="line">2160</span><br><span class="line">2161</span><br><span class="line">2162</span><br><span class="line">2163</span><br><span class="line">2164</span><br><span class="line">2165</span><br><span class="line">2166</span><br><span class="line">2167</span><br><span class="line">2168</span><br><span class="line">2169</span><br><span class="line">2170</span><br><span class="line">2171</span><br><span class="line">2172</span><br><span class="line">2173</span><br><span class="line">2174</span><br><span class="line">2175</span><br><span class="line">2176</span><br><span class="line">2177</span><br><span class="line">2178</span><br><span class="line">2179</span><br><span class="line">2180</span><br><span class="line">2181</span><br><span class="line">2182</span><br><span class="line">2183</span><br><span class="line">2184</span><br><span class="line">2185</span><br><span class="line">2186</span><br><span class="line">2187</span><br><span class="line">2188</span><br><span class="line">2189</span><br><span class="line">2190</span><br><span class="line">2191</span><br><span class="line">2192</span><br><span class="line">2193</span><br><span class="line">2194</span><br><span class="line">2195</span><br><span class="line">2196</span><br><span class="line">2197</span><br><span class="line">2198</span><br><span class="line">2199</span><br><span class="line">2200</span><br><span class="line">2201</span><br><span class="line">2202</span><br><span class="line">2203</span><br><span class="line">2204</span><br><span class="line">2205</span><br><span class="line">2206</span><br><span class="line">2207</span><br><span class="line">2208</span><br><span class="line">2209</span><br><span class="line">2210</span><br><span class="line">2211</span><br><span class="line">2212</span><br><span class="line">2213</span><br><span class="line">2214</span><br><span class="line">2215</span><br><span class="line">2216</span><br><span class="line">2217</span><br><span class="line">2218</span><br><span class="line">2219</span><br><span class="line">2220</span><br><span class="line">2221</span><br><span class="line">2222</span><br><span class="line">2223</span><br><span class="line">2224</span><br><span class="line">2225</span><br><span class="line">2226</span><br><span class="line">2227</span><br><span class="line">2228</span><br><span class="line">2229</span><br><span class="line">2230</span><br><span class="line">2231</span><br><span class="line">2232</span><br><span class="line">2233</span><br><span class="line">2234</span><br><span class="line">2235</span><br><span class="line">2236</span><br><span class="line">2237</span><br><span class="line">2238</span><br><span class="line">2239</span><br><span class="line">2240</span><br><span class="line">2241</span><br><span class="line">2242</span><br><span class="line">2243</span><br><span class="line">2244</span><br><span class="line">2245</span><br><span class="line">2246</span><br><span class="line">2247</span><br><span class="line">2248</span><br><span class="line">2249</span><br><span class="line">2250</span><br><span class="line">2251</span><br><span class="line">2252</span><br><span class="line">2253</span><br><span class="line">2254</span><br><span class="line">2255</span><br><span class="line">2256</span><br><span class="line">2257</span><br><span class="line">2258</span><br><span class="line">2259</span><br><span class="line">2260</span><br><span class="line">2261</span><br><span class="line">2262</span><br><span class="line">2263</span><br><span class="line">2264</span><br><span class="line">2265</span><br><span class="line">2266</span><br><span class="line">2267</span><br><span class="line">2268</span><br><span class="line">2269</span><br><span class="line">2270</span><br><span class="line">2271</span><br><span class="line">2272</span><br><span class="line">2273</span><br><span class="line">2274</span><br><span class="line">2275</span><br><span class="line">2276</span><br><span class="line">2277</span><br><span class="line">2278</span><br><span class="line">2279</span><br><span class="line">2280</span><br><span class="line">2281</span><br><span class="line">2282</span><br><span class="line">2283</span><br><span class="line">2284</span><br><span class="line">2285</span><br><span class="line">2286</span><br><span class="line">2287</span><br><span class="line">2288</span><br><span class="line">2289</span><br><span class="line">2290</span><br><span class="line">2291</span><br><span class="line">2292</span><br><span class="line">2293</span><br><span class="line">2294</span><br><span class="line">2295</span><br><span class="line">2296</span><br><span class="line">2297</span><br><span class="line">2298</span><br><span class="line">2299</span><br><span class="line">2300</span><br><span class="line">2301</span><br><span class="line">2302</span><br><span class="line">2303</span><br><span class="line">2304</span><br><span class="line">2305</span><br><span class="line">2306</span><br><span class="line">2307</span><br><span class="line">2308</span><br><span class="line">2309</span><br><span class="line">2310</span><br><span class="line">2311</span><br><span class="line">2312</span><br><span class="line">2313</span><br><span class="line">2314</span><br><span class="line">2315</span><br><span class="line">2316</span><br><span class="line">2317</span><br><span class="line">2318</span><br><span class="line">2319</span><br><span class="line">2320</span><br><span class="line">2321</span><br><span class="line">2322</span><br><span class="line">2323</span><br><span class="line">2324</span><br><span class="line">2325</span><br><span class="line">2326</span><br><span class="line">2327</span><br><span class="line">2328</span><br><span class="line">2329</span><br><span class="line">2330</span><br><span class="line">2331</span><br><span class="line">2332</span><br><span class="line">2333</span><br><span class="line">2334</span><br><span class="line">2335</span><br><span class="line">2336</span><br><span class="line">2337</span><br><span class="line">2338</span><br><span class="line">2339</span><br><span class="line">2340</span><br><span class="line">2341</span><br><span class="line">2342</span><br><span class="line">2343</span><br><span class="line">2344</span><br><span class="line">2345</span><br><span class="line">2346</span><br><span class="line">2347</span><br><span class="line">2348</span><br><span class="line">2349</span><br><span class="line">2350</span><br><span class="line">2351</span><br><span class="line">2352</span><br><span class="line">2353</span><br><span class="line">2354</span><br><span class="line">2355</span><br><span class="line">2356</span><br><span class="line">2357</span><br><span class="line">2358</span><br><span class="line">2359</span><br><span class="line">2360</span><br><span class="line">2361</span><br><span class="line">2362</span><br><span class="line">2363</span><br><span class="line">2364</span><br><span class="line">2365</span><br><span class="line">2366</span><br><span class="line">2367</span><br><span class="line">2368</span><br><span class="line">2369</span><br><span class="line">2370</span><br><span class="line">2371</span><br><span class="line">2372</span><br><span class="line">2373</span><br><span class="line">2374</span><br><span class="line">2375</span><br><span class="line">2376</span><br><span class="line">2377</span><br><span class="line">2378</span><br><span class="line">2379</span><br><span class="line">2380</span><br><span class="line">2381</span><br><span class="line">2382</span><br><span class="line">2383</span><br><span class="line">2384</span><br><span class="line">2385</span><br><span class="line">2386</span><br><span class="line">2387</span><br><span class="line">2388</span><br><span class="line">2389</span><br><span class="line">2390</span><br><span class="line">2391</span><br><span class="line">2392</span><br><span class="line">2393</span><br><span class="line">2394</span><br><span class="line">2395</span><br><span class="line">2396</span><br><span class="line">2397</span><br><span class="line">2398</span><br><span class="line">2399</span><br><span class="line">2400</span><br><span class="line">2401</span><br><span class="line">2402</span><br><span class="line">2403</span><br><span class="line">2404</span><br><span class="line">2405</span><br><span class="line">2406</span><br><span class="line">2407</span><br><span class="line">2408</span><br><span class="line">2409</span><br><span class="line">2410</span><br><span class="line">2411</span><br><span class="line">2412</span><br><span class="line">2413</span><br><span class="line">2414</span><br><span class="line">2415</span><br><span class="line">2416</span><br><span class="line">2417</span><br><span class="line">2418</span><br><span class="line">2419</span><br><span class="line">2420</span><br><span class="line">2421</span><br><span class="line">2422</span><br><span class="line">2423</span><br><span class="line">2424</span><br><span class="line">2425</span><br><span class="line">2426</span><br><span class="line">2427</span><br><span class="line">2428</span><br><span class="line">2429</span><br><span class="line">2430</span><br><span class="line">2431</span><br><span class="line">2432</span><br><span class="line">2433</span><br><span class="line">2434</span><br><span class="line">2435</span><br><span class="line">2436</span><br><span class="line">2437</span><br><span class="line">2438</span><br><span class="line">2439</span><br><span class="line">2440</span><br><span class="line">2441</span><br><span class="line">2442</span><br><span class="line">2443</span><br><span class="line">2444</span><br><span class="line">2445</span><br><span class="line">2446</span><br><span class="line">2447</span><br><span class="line">2448</span><br><span class="line">2449</span><br><span class="line">2450</span><br><span class="line">2451</span><br><span class="line">2452</span><br><span class="line">2453</span><br><span class="line">2454</span><br><span class="line">2455</span><br><span class="line">2456</span><br><span class="line">2457</span><br><span class="line">2458</span><br><span class="line">2459</span><br><span class="line">2460</span><br><span class="line">2461</span><br><span class="line">2462</span><br><span class="line">2463</span><br><span class="line">2464</span><br><span class="line">2465</span><br><span class="line">2466</span><br><span class="line">2467</span><br><span class="line">2468</span><br><span class="line">2469</span><br><span class="line">2470</span><br><span class="line">2471</span><br><span class="line">2472</span><br><span class="line">2473</span><br><span class="line">2474</span><br><span class="line">2475</span><br><span class="line">2476</span><br><span class="line">2477</span><br><span class="line">2478</span><br><span class="line">2479</span><br><span class="line">2480</span><br><span class="line">2481</span><br><span class="line">2482</span><br><span class="line">2483</span><br><span class="line">2484</span><br><span class="line">2485</span><br><span class="line">2486</span><br><span class="line">2487</span><br><span class="line">2488</span><br><span class="line">2489</span><br><span class="line">2490</span><br><span class="line">2491</span><br><span class="line">2492</span><br><span class="line">2493</span><br><span class="line">2494</span><br><span class="line">2495</span><br><span class="line">2496</span><br><span class="line">2497</span><br><span class="line">2498</span><br><span class="line">2499</span><br><span class="line">2500</span><br><span class="line">2501</span><br><span class="line">2502</span><br><span class="line">2503</span><br><span class="line">2504</span><br><span class="line">2505</span><br><span class="line">2506</span><br><span class="line">2507</span><br><span class="line">2508</span><br><span class="line">2509</span><br><span class="line">2510</span><br><span class="line">2511</span><br><span class="line">2512</span><br><span class="line">2513</span><br><span class="line">2514</span><br><span class="line">2515</span><br><span class="line">2516</span><br><span class="line">2517</span><br><span class="line">2518</span><br><span class="line">2519</span><br><span class="line">2520</span><br><span class="line">2521</span><br><span class="line">2522</span><br><span class="line">2523</span><br><span class="line">2524</span><br><span class="line">2525</span><br><span class="line">2526</span><br><span class="line">2527</span><br><span class="line">2528</span><br><span class="line">2529</span><br><span class="line">2530</span><br><span class="line">2531</span><br><span class="line">2532</span><br><span class="line">2533</span><br><span class="line">2534</span><br><span class="line">2535</span><br><span class="line">2536</span><br><span class="line">2537</span><br><span class="line">2538</span><br><span class="line">2539</span><br><span class="line">2540</span><br><span class="line">2541</span><br><span class="line">2542</span><br><span class="line">2543</span><br><span class="line">2544</span><br><span class="line">2545</span><br><span class="line">2546</span><br><span class="line">2547</span><br><span class="line">2548</span><br><span class="line">2549</span><br><span class="line">2550</span><br><span class="line">2551</span><br><span class="line">2552</span><br><span class="line">2553</span><br><span class="line">2554</span><br><span class="line">2555</span><br><span class="line">2556</span><br><span class="line">2557</span><br><span class="line">2558</span><br><span class="line">2559</span><br><span class="line">2560</span><br><span class="line">2561</span><br><span class="line">2562</span><br><span class="line">2563</span><br><span class="line">2564</span><br><span class="line">2565</span><br><span class="line">2566</span><br><span class="line">2567</span><br><span class="line">2568</span><br><span class="line">2569</span><br><span class="line">2570</span><br><span class="line">2571</span><br><span class="line">2572</span><br><span class="line">2573</span><br><span class="line">2574</span><br><span class="line">2575</span><br><span class="line">2576</span><br><span class="line">2577</span><br><span class="line">2578</span><br><span class="line">2579</span><br><span class="line">2580</span><br><span class="line">2581</span><br><span class="line">2582</span><br><span class="line">2583</span><br><span class="line">2584</span><br><span class="line">2585</span><br><span class="line">2586</span><br><span class="line">2587</span><br><span class="line">2588</span><br><span class="line">2589</span><br><span class="line">2590</span><br><span class="line">2591</span><br><span class="line">2592</span><br><span class="line">2593</span><br><span class="line">2594</span><br><span class="line">2595</span><br><span class="line">2596</span><br><span class="line">2597</span><br><span class="line">2598</span><br><span class="line">2599</span><br><span class="line">2600</span><br><span class="line">2601</span><br><span class="line">2602</span><br><span class="line">2603</span><br><span class="line">2604</span><br><span class="line">2605</span><br><span class="line">2606</span><br><span class="line">2607</span><br><span class="line">2608</span><br><span class="line">2609</span><br><span class="line">2610</span><br><span class="line">2611</span><br><span class="line">2612</span><br><span class="line">2613</span><br><span class="line">2614</span><br><span class="line">2615</span><br><span class="line">2616</span><br><span class="line">2617</span><br><span class="line">2618</span><br><span class="line">2619</span><br><span class="line">2620</span><br><span class="line">2621</span><br><span class="line">2622</span><br><span class="line">2623</span><br><span class="line">2624</span><br><span class="line">2625</span><br><span class="line">2626</span><br><span class="line">2627</span><br><span class="line">2628</span><br><span class="line">2629</span><br><span class="line">2630</span><br><span class="line">2631</span><br><span class="line">2632</span><br><span class="line">2633</span><br><span class="line">2634</span><br><span class="line">2635</span><br><span class="line">2636</span><br><span class="line">2637</span><br><span class="line">2638</span><br><span class="line">2639</span><br><span class="line">2640</span><br><span class="line">2641</span><br><span class="line">2642</span><br><span class="line">2643</span><br><span class="line">2644</span><br><span class="line">2645</span><br><span class="line">2646</span><br><span class="line">2647</span><br><span class="line">2648</span><br><span class="line">2649</span><br><span class="line">2650</span><br><span class="line">2651</span><br><span class="line">2652</span><br><span class="line">2653</span><br><span class="line">2654</span><br><span class="line">2655</span><br><span class="line">2656</span><br><span class="line">2657</span><br><span class="line">2658</span><br><span class="line">2659</span><br><span class="line">2660</span><br><span class="line">2661</span><br><span class="line">2662</span><br><span class="line">2663</span><br><span class="line">2664</span><br><span class="line">2665</span><br><span class="line">2666</span><br><span class="line">2667</span><br><span class="line">2668</span><br><span class="line">2669</span><br><span class="line">2670</span><br><span class="line">2671</span><br><span class="line">2672</span><br><span class="line">2673</span><br><span class="line">2674</span><br><span class="line">2675</span><br><span class="line">2676</span><br><span class="line">2677</span><br><span class="line">2678</span><br><span class="line">2679</span><br><span class="line">2680</span><br><span class="line">2681</span><br><span class="line">2682</span><br><span class="line">2683</span><br><span class="line">2684</span><br><span class="line">2685</span><br><span class="line">2686</span><br><span class="line">2687</span><br><span class="line">2688</span><br><span class="line">2689</span><br><span class="line">2690</span><br><span class="line">2691</span><br><span class="line">2692</span><br><span class="line">2693</span><br><span class="line">2694</span><br><span class="line">2695</span><br><span class="line">2696</span><br><span class="line">2697</span><br><span class="line">2698</span><br><span class="line">2699</span><br><span class="line">2700</span><br><span class="line">2701</span><br><span class="line">2702</span><br><span class="line">2703</span><br><span class="line">2704</span><br><span class="line">2705</span><br><span class="line">2706</span><br><span class="line">2707</span><br><span class="line">2708</span><br><span class="line">2709</span><br><span class="line">2710</span><br><span class="line">2711</span><br><span class="line">2712</span><br><span class="line">2713</span><br><span class="line">2714</span><br><span class="line">2715</span><br><span class="line">2716</span><br><span class="line">2717</span><br><span class="line">2718</span><br><span class="line">2719</span><br><span class="line">2720</span><br><span class="line">2721</span><br><span class="line">2722</span><br><span class="line">2723</span><br><span class="line">2724</span><br><span class="line">2725</span><br><span class="line">2726</span><br><span class="line">2727</span><br><span class="line">2728</span><br><span class="line">2729</span><br><span class="line">2730</span><br><span class="line">2731</span><br><span class="line">2732</span><br><span class="line">2733</span><br><span class="line">2734</span><br><span class="line">2735</span><br><span class="line">2736</span><br><span class="line">2737</span><br><span class="line">2738</span><br><span class="line">2739</span><br><span class="line">2740</span><br><span class="line">2741</span><br><span class="line">2742</span><br><span class="line">2743</span><br><span class="line">2744</span><br><span class="line">2745</span><br><span class="line">2746</span><br><span class="line">2747</span><br><span class="line">2748</span><br><span class="line">2749</span><br><span class="line">2750</span><br><span class="line">2751</span><br><span class="line">2752</span><br><span class="line">2753</span><br><span class="line">2754</span><br><span class="line">2755</span><br><span class="line">2756</span><br><span class="line">2757</span><br><span class="line">2758</span><br><span class="line">2759</span><br><span class="line">2760</span><br><span class="line">2761</span><br><span class="line">2762</span><br><span class="line">2763</span><br><span class="line">2764</span><br><span class="line">2765</span><br><span class="line">2766</span><br><span class="line">2767</span><br><span class="line">2768</span><br><span class="line">2769</span><br><span class="line">2770</span><br><span class="line">2771</span><br><span class="line">2772</span><br><span class="line">2773</span><br><span class="line">2774</span><br><span class="line">2775</span><br><span class="line">2776</span><br><span class="line">2777</span><br><span class="line">2778</span><br><span class="line">2779</span><br><span class="line">2780</span><br><span class="line">2781</span><br><span class="line">2782</span><br><span class="line">2783</span><br><span class="line">2784</span><br><span class="line">2785</span><br><span class="line">2786</span><br><span class="line">2787</span><br><span class="line">2788</span><br><span class="line">2789</span><br><span class="line">2790</span><br><span class="line">2791</span><br><span class="line">2792</span><br><span class="line">2793</span><br><span class="line">2794</span><br><span class="line">2795</span><br><span class="line">2796</span><br><span class="line">2797</span><br><span class="line">2798</span><br><span class="line">2799</span><br><span class="line">2800</span><br><span class="line">2801</span><br><span class="line">2802</span><br><span class="line">2803</span><br><span class="line">2804</span><br><span class="line">2805</span><br><span class="line">2806</span><br><span class="line">2807</span><br><span class="line">2808</span><br><span class="line">2809</span><br><span class="line">2810</span><br><span class="line">2811</span><br><span class="line">2812</span><br><span class="line">2813</span><br><span class="line">2814</span><br><span class="line">2815</span><br><span class="line">2816</span><br><span class="line">2817</span><br><span class="line">2818</span><br><span class="line">2819</span><br><span class="line">2820</span><br><span class="line">2821</span><br><span class="line">2822</span><br><span class="line">2823</span><br><span class="line">2824</span><br><span class="line">2825</span><br><span class="line">2826</span><br><span class="line">2827</span><br><span class="line">2828</span><br><span class="line">2829</span><br><span class="line">2830</span><br><span class="line">2831</span><br><span class="line">2832</span><br><span class="line">2833</span><br><span class="line">2834</span><br><span class="line">2835</span><br><span class="line">2836</span><br><span class="line">2837</span><br><span class="line">2838</span><br><span class="line">2839</span><br><span class="line">2840</span><br><span class="line">2841</span><br><span class="line">2842</span><br><span class="line">2843</span><br><span class="line">2844</span><br><span class="line">2845</span><br><span class="line">2846</span><br><span class="line">2847</span><br><span class="line">2848</span><br><span class="line">2849</span><br><span class="line">2850</span><br><span class="line">2851</span><br><span class="line">2852</span><br><span class="line">2853</span><br><span class="line">2854</span><br><span class="line">2855</span><br><span class="line">2856</span><br><span class="line">2857</span><br><span class="line">2858</span><br><span class="line">2859</span><br><span class="line">2860</span><br><span class="line">2861</span><br><span class="line">2862</span><br><span class="line">2863</span><br><span class="line">2864</span><br><span class="line">2865</span><br><span class="line">2866</span><br><span class="line">2867</span><br><span class="line">2868</span><br><span class="line">2869</span><br><span class="line">2870</span><br><span class="line">2871</span><br><span class="line">2872</span><br><span class="line">2873</span><br><span class="line">2874</span><br><span class="line">2875</span><br><span class="line">2876</span><br><span class="line">2877</span><br><span class="line">2878</span><br><span class="line">2879</span><br><span class="line">2880</span><br><span class="line">2881</span><br><span class="line">2882</span><br><span class="line">2883</span><br><span class="line">2884</span><br><span class="line">2885</span><br><span class="line">2886</span><br><span class="line">2887</span><br><span class="line">2888</span><br><span class="line">2889</span><br><span class="line">2890</span><br><span class="line">2891</span><br><span class="line">2892</span><br><span class="line">2893</span><br><span class="line">2894</span><br><span class="line">2895</span><br><span class="line">2896</span><br><span class="line">2897</span><br><span class="line">2898</span><br><span class="line">2899</span><br><span class="line">2900</span><br><span class="line">2901</span><br><span class="line">2902</span><br><span class="line">2903</span><br><span class="line">2904</span><br><span class="line">2905</span><br><span class="line">2906</span><br><span class="line">2907</span><br><span class="line">2908</span><br><span class="line">2909</span><br><span class="line">2910</span><br><span class="line">2911</span><br><span class="line">2912</span><br><span class="line">2913</span><br><span class="line">2914</span><br><span class="line">2915</span><br><span class="line">2916</span><br><span class="line">2917</span><br><span class="line">2918</span><br><span class="line">2919</span><br><span class="line">2920</span><br><span class="line">2921</span><br><span class="line">2922</span><br><span class="line">2923</span><br><span class="line">2924</span><br><span class="line">2925</span><br><span class="line">2926</span><br><span class="line">2927</span><br><span class="line">2928</span><br><span class="line">2929</span><br><span class="line">2930</span><br><span class="line">2931</span><br><span class="line">2932</span><br><span class="line">2933</span><br><span class="line">2934</span><br><span class="line">2935</span><br><span class="line">2936</span><br><span class="line">2937</span><br><span class="line">2938</span><br><span class="line">2939</span><br><span class="line">2940</span><br><span class="line">2941</span><br><span class="line">2942</span><br><span class="line">2943</span><br><span class="line">2944</span><br><span class="line">2945</span><br><span class="line">2946</span><br><span class="line">2947</span><br><span class="line">2948</span><br><span class="line">2949</span><br><span class="line">2950</span><br><span class="line">2951</span><br><span class="line">2952</span><br><span class="line">2953</span><br><span class="line">2954</span><br><span class="line">2955</span><br><span class="line">2956</span><br><span class="line">2957</span><br><span class="line">2958</span><br><span class="line">2959</span><br><span class="line">2960</span><br><span class="line">2961</span><br><span class="line">2962</span><br><span class="line">2963</span><br><span class="line">2964</span><br><span class="line">2965</span><br><span class="line">2966</span><br><span class="line">2967</span><br><span class="line">2968</span><br><span class="line">2969</span><br><span class="line">2970</span><br><span class="line">2971</span><br><span class="line">2972</span><br><span class="line">2973</span><br><span class="line">2974</span><br><span class="line">2975</span><br><span class="line">2976</span><br><span class="line">2977</span><br><span class="line">2978</span><br><span class="line">2979</span><br><span class="line">2980</span><br><span class="line">2981</span><br><span class="line">2982</span><br><span class="line">2983</span><br><span class="line">2984</span><br><span class="line">2985</span><br><span class="line">2986</span><br><span class="line">2987</span><br><span class="line">2988</span><br><span class="line">2989</span><br><span class="line">2990</span><br><span class="line">2991</span><br><span class="line">2992</span><br><span class="line">2993</span><br><span class="line">2994</span><br><span class="line">2995</span><br><span class="line">2996</span><br><span class="line">2997</span><br><span class="line">2998</span><br><span class="line">2999</span><br><span class="line">3000</span><br><span class="line">3001</span><br><span class="line">3002</span><br><span class="line">3003</span><br><span class="line">3004</span><br><span class="line">3005</span><br><span class="line">3006</span><br><span class="line">3007</span><br><span class="line">3008</span><br><span class="line">3009</span><br><span class="line">3010</span><br><span class="line">3011</span><br><span class="line">3012</span><br><span class="line">3013</span><br><span class="line">3014</span><br><span class="line">3015</span><br><span class="line">3016</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># SystemVerilog/Verilog Snippets - Organized by Category</span><br><span class="line"># Author: Auto-generated</span><br><span class="line"># Description: Comprehensive SystemVerilog, Verilog <span class="keyword">and</span> UVM snippets</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># COMMONLY USED SNIPPETS (Top Priority)</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet sv_header</span><br><span class="line"><span class="comment">//==============================================================================</span></span><br><span class="line"><span class="comment">// File        : $&#123;1:`expand(&#x27;%:t&#x27;)`&#125;</span></span><br><span class="line"><span class="comment">// Project     : $&#123;2:Project Name&#125;</span></span><br><span class="line"><span class="comment">// Module      : $&#123;3:`expand(&#x27;%:t:r&#x27;)`&#125;</span></span><br><span class="line"><span class="comment">// Author      : $&#123;4:$USER&#125;</span></span><br><span class="line"><span class="comment">// Created     : $&#123;5:`strftime(&quot;%Y-%m-%d&quot;)`&#125;</span></span><br><span class="line"><span class="comment">// Modified    : $&#123;6:`strftime(&quot;%Y-%m-%d&quot;)`&#125;</span></span><br><span class="line"><span class="comment">//==============================================================================</span></span><br><span class="line"><span class="comment">// Description:</span></span><br><span class="line"><span class="comment">//   $&#123;7:Brief description&#125;</span></span><br><span class="line"><span class="comment">//==============================================================================</span></span><br><span class="line"></span><br><span class="line">$&#123;<span class="number">0</span>&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">snippet tb</span><br><span class="line">\<span class="meta">`<span class="keyword">timescale</span> 1ns/1ps</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">module</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">localparam</span> <span class="keyword">int</span> PERIOD = $&#123;<span class="number">2</span>:<span class="number">10</span>&#125;;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">logic</span> $&#123;<span class="number">3</span>:clk&#125;;</span><br><span class="line">    <span class="keyword">logic</span> $&#123;<span class="number">4</span>:rst_n&#125;;</span><br><span class="line">    $&#123;<span class="number">5</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Clock generation</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        $<span class="number">3</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">forever</span> <span class="variable">#(PERIOD/2)</span> $<span class="number">3</span> = ~$<span class="number">3</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Reset generation</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        $<span class="number">4</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">repeat</span>(<span class="number">2</span>) @(<span class="keyword">posedge</span> $<span class="number">3</span>);</span><br><span class="line">        $<span class="number">4</span> = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// DUT instantiation</span></span><br><span class="line">    $&#123;<span class="number">6</span>:dut&#125; u_dut (</span><br><span class="line">        <span class="variable">.clk</span>($<span class="number">3</span>),</span><br><span class="line">        <span class="variable">.rst_n</span>($<span class="number">4</span>)$&#123;<span class="number">7</span>&#125;</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Test stimulus</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        @(<span class="keyword">posedge</span> $<span class="number">4</span>);</span><br><span class="line">        $&#123;<span class="number">0</span>&#125;</span><br><span class="line">        #<span class="number">1000</span>;</span><br><span class="line">        \<span class="built_in">$finish</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Waveform dump</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        \<span class="built_in">$dumpfile</span>(<span class="string">&quot;$&#123;8:`expand(&#x27;%:t:r&#x27;)`&#125;\.vcd&quot;</span>);</span><br><span class="line">        \<span class="built_in">$dumpvars</span>(<span class="number">0</span>, $<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">endmodule</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">always_ff</span></span><br><span class="line"><span class="keyword">always_ff</span> @(<span class="keyword">posedge</span> $&#123;<span class="number">1</span>:clk&#125; <span class="keyword">or</span> <span class="keyword">negedge</span> $&#123;<span class="number">2</span>:rst_n&#125;) <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">if</span> (!$<span class="number">2</span>)</span><br><span class="line">        $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">class</span></span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">        $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet sequence_item</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">    \`uvm_object_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Transaction fields</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [$&#123;<span class="number">2</span>:<span class="number">7</span>&#125;:<span class="number">0</span>] $&#123;<span class="number">3</span>:addr&#125;;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [$&#123;<span class="number">4</span>:<span class="number">31</span>&#125;:<span class="number">0</span>] $&#123;<span class="number">5</span>:data&#125;;</span><br><span class="line">    $&#123;<span class="number">6</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Constraints</span></span><br><span class="line">    <span class="keyword">constraint</span> $&#123;<span class="number">7</span>:valid&#125;_c &#123;</span><br><span class="line">        $&#123;<span class="number">8</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">void</span> do_copy(uvm_object rhs);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">bit</span> do_compare(uvm_object rhs, uvm_comparer comparer);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">void</span> do_print(uvm_printer printer);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">string</span> convert2string();</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::do_copy(uvm_object rhs);</span><br><span class="line">    $<span class="number">1</span> rhs_;</span><br><span class="line">    <span class="keyword">if</span> (!\<span class="built_in">$cast</span>(rhs_, rhs))</span><br><span class="line">        \`uvm_fatal(get_type_name(), <span class="string">&quot;Cast failed in do_copy&quot;</span>)</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.do_copy</span>(rhs);</span><br><span class="line">    <span class="keyword">this</span>.$<span class="number">3</span> = rhs_.$<span class="number">3</span>;</span><br><span class="line">    <span class="keyword">this</span>.$<span class="number">5</span> = rhs_.$<span class="number">5</span>;</span><br><span class="line"><span class="keyword">endfunction</span>: do_copy</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">bit</span> $<span class="number">1</span>::do_compare(uvm_object rhs, uvm_comparer comparer);</span><br><span class="line">    $<span class="number">1</span> rhs_;</span><br><span class="line">    <span class="keyword">if</span> (!\<span class="built_in">$cast</span>(rhs_, rhs))</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> (<span class="keyword">super</span><span class="variable">.do_compare</span>(rhs, comparer) &amp;&amp;</span><br><span class="line">            (<span class="keyword">this</span>.$<span class="number">3</span> == rhs_.$<span class="number">3</span>) &amp;&amp;</span><br><span class="line">            (<span class="keyword">this</span>.$<span class="number">5</span> == rhs_.$<span class="number">5</span>));</span><br><span class="line"><span class="keyword">endfunction</span>: do_compare</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::do_print(uvm_printer printer);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.do_print</span>(printer);</span><br><span class="line">    printer<span class="variable">.print_field</span>(<span class="string">&quot;$3&quot;</span>, <span class="keyword">this</span>.$<span class="number">3</span>, $<span class="number">2</span>+<span class="number">1</span>);</span><br><span class="line">    printer<span class="variable">.print_field</span>(<span class="string">&quot;$5&quot;</span>, <span class="keyword">this</span>.$<span class="number">5</span>, $<span class="number">4</span>+<span class="number">1</span>);</span><br><span class="line"><span class="keyword">endfunction</span>: do_print</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">string</span> $<span class="number">1</span>::convert2string();</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">$sformatf</span>(<span class="string">&quot;$3=0x%0h, $5=0x%0h&quot;</span>, $<span class="number">3</span>, $<span class="number">5</span>);</span><br><span class="line"><span class="keyword">endfunction</span>: convert2string</span><br><span class="line"></span><br><span class="line"># moved: <span class="keyword">assert</span> to COMMONLY USED SNIPPETS</span><br><span class="line"><span class="keyword">assert</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">else</span> \<span class="built_in">$error</span>(<span class="string">&quot;$&#123;2:Assertion failed&#125;&quot;</span>);</span><br><span class="line"></span><br><span class="line"># moved: <span class="keyword">property</span> to COMMONLY USED SNIPPETS</span><br><span class="line"><span class="keyword">property</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    @(<span class="keyword">posedge</span> $&#123;<span class="number">2</span>:clk&#125;) $&#123;<span class="number">3</span>:condition&#125;;</span><br><span class="line"><span class="keyword">endproperty</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"># moved: <span class="keyword">sequence</span> to COMMONLY USED SNIPPETS</span><br><span class="line"><span class="keyword">sequence</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">endsequence</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"># moved: implication to COMMONLY USED SNIPPETS</span><br><span class="line">$&#123;<span class="number">1</span>:antecedent&#125; |-&gt; $&#123;<span class="number">2</span>:consequent&#125;</span><br><span class="line"></span><br><span class="line">snippet uvm_agent</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_agent;</span><br><span class="line">    \`uvm_component_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    $&#123;<span class="number">2</span>:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_agent$&#x27;, &#x27;&#x27;, &#x27;&#x27;)`&#125;_sequencer  sqr;</span><br><span class="line">    $<span class="number">2_</span>driver     drv;</span><br><span class="line">    $<span class="number">2_</span>monitor    mon;</span><br><span class="line"></span><br><span class="line">    uvm_active_passive_enum is_active = UVM_ACTIVE;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> connect_phase(uvm_phase phase);</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Get configuration</span></span><br><span class="line">    <span class="keyword">if</span> (!uvm_config_db<span class="variable">#(uvm_active_passive_enum)::get(this, &quot;&quot;, &quot;is_active&quot;, is_active))</span></span><br><span class="line">        \`uvm_info(get_name(), <span class="string">&quot;is_active not configured, using default UVM_ACTIVE&quot;</span>, UVM_MEDIUM)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Always create monitor</span></span><br><span class="line">    mon = $<span class="number">2_</span>monitor::type_id::create(<span class="string">&quot;mon&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Create driver and sequencer only in active mode</span></span><br><span class="line">    <span class="keyword">if</span> (is_active == UVM_ACTIVE) <span class="keyword">begin</span></span><br><span class="line">        sqr = $<span class="number">2_</span>sequencer::type_id::create(<span class="string">&quot;sqr&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">        drv = $<span class="number">2_</span>driver::type_id::create(<span class="string">&quot;drv&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endfunction</span>: build_phase</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::connect_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.connect_phase</span>(phase);</span><br><span class="line">    <span class="keyword">if</span> (is_active == UVM_ACTIVE) <span class="keyword">begin</span></span><br><span class="line">        drv<span class="variable">.seq_item_port</span><span class="variable">.connect</span>(sqr<span class="variable">.seq_item_export</span>);</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endfunction</span>: connect_phase</span><br><span class="line"></span><br><span class="line">snippet uvm_driver</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_driver <span class="variable">#($&#123;2:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_driver$&#x27;, &#x27;_item&#x27;, &#x27;&#x27;)`&#125;)</span>;</span><br><span class="line">    \`uvm_component_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">virtual</span> $&#123;<span class="number">3</span>:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_driver$&#x27;, &#x27;_if&#x27;, &#x27;&#x27;)`&#125; vif;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> drive_item($<span class="number">2</span> item);</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    <span class="keyword">if</span> (!uvm_config_db<span class="variable">#(virtual $3)::get(this, &quot;&quot;, &quot;vif&quot;, vif))</span></span><br><span class="line">        \`uvm_fatal(get_name(), <span class="string">&quot;Virtual interface not found!&quot;</span>)</span><br><span class="line"><span class="keyword">endfunction</span>: build_phase</span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::run_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">        seq_item_port<span class="variable">.get_next_item</span>(req);</span><br><span class="line">        drive_item(req);</span><br><span class="line">        seq_item_port<span class="variable">.item_done</span>();</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endtask</span>: run_phase</span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::drive_item($<span class="number">2</span> item);</span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> Implement protocol-specific driving</span></span><br><span class="line">    <span class="comment">// Example:</span></span><br><span class="line">    <span class="comment">// @(posedge vif.clk);</span></span><br><span class="line">    <span class="comment">// vif.data &lt;= item.data;</span></span><br><span class="line">    $&#123;<span class="number">0</span>&#125;</span><br><span class="line"><span class="keyword">endtask</span>: drive_item</span><br><span class="line"></span><br><span class="line">snippet uvm_monitor</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_monitor;</span><br><span class="line">    \`uvm_component_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    uvm_analysis_port <span class="variable">#($&#123;2:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_monitor$&#x27;, &#x27;_item&#x27;, &#x27;&#x27;)`&#125;)</span> ap;</span><br><span class="line">    <span class="keyword">virtual</span> $&#123;<span class="number">3</span>:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_monitor$&#x27;, &#x27;_if&#x27;, &#x27;&#x27;)`&#125; vif;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> run_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> collect_transaction(<span class="keyword">output</span> $<span class="number">2</span> item);</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::build_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.build_phase</span>(phase);</span><br><span class="line">    ap = <span class="keyword">new</span>(<span class="string">&quot;ap&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">if</span> (!uvm_config_db<span class="variable">#(virtual $3)::get(this, &quot;&quot;, &quot;vif&quot;, vif))</span></span><br><span class="line">        \`uvm_fatal(get_name(), <span class="string">&quot;Virtual interface not found!&quot;</span>)</span><br><span class="line"><span class="keyword">endfunction</span>: build_phase</span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::run_phase(uvm_phase phase);</span><br><span class="line">    <span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">        $<span class="number">2</span> item;</span><br><span class="line">        collect_transaction(item);</span><br><span class="line">        \`uvm_info(get_name(), item<span class="variable">.convert2string</span>(), UVM_HIGH)</span><br><span class="line">        ap<span class="variable">.write</span>(item);</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endtask</span>: run_phase</span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::collect_transaction(<span class="keyword">output</span> $<span class="number">2</span> item);</span><br><span class="line">    item = $<span class="number">2</span>::type_id::create(<span class="string">&quot;item&quot;</span>);</span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> Implement protocol-specific monitoring</span></span><br><span class="line">    <span class="comment">// Example:</span></span><br><span class="line">    <span class="comment">// @(posedge vif.clk);</span></span><br><span class="line">    <span class="comment">// if (vif.valid &amp;&amp; vif.ready) begin</span></span><br><span class="line">    <span class="comment">//   item.data = vif.data;</span></span><br><span class="line">    <span class="comment">// end</span></span><br><span class="line">    $&#123;<span class="number">0</span>&#125;</span><br><span class="line"><span class="keyword">endtask</span>: collect_transaction</span><br><span class="line"></span><br><span class="line">snippet uvm_sequencer</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_sequencer <span class="variable">#($&#123;2:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_sequencer$&#x27;, &#x27;_item&#x27;, &#x27;&#x27;)`&#125;)</span>;</span><br><span class="line">    \`uvm_component_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>, uvm_component parent = <span class="literal">null</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name, parent);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line">snippet uvm_sequence</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_sequence <span class="variable">#($&#123;2:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_\(seq\|sequence\)$&#x27;, &#x27;_item&#x27;, &#x27;&#x27;)`&#125;)</span>;</span><br><span class="line">    \`uvm_object_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Sequence properties</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">int</span> <span class="keyword">unsigned</span> num_trans = $&#123;<span class="number">3</span>:<span class="number">10</span>&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> body();</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> pre_body();</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">virtual</span> <span class="keyword">task</span> post_body();</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::pre_body();</span><br><span class="line">    <span class="comment">// Setup before sequence execution</span></span><br><span class="line">    \`uvm_info(get_type_name(), <span class="built_in">$sformatf</span>(<span class="string">&quot;Starting sequence with %0d transactions&quot;</span>, num_trans), UVM_MEDIUM)</span><br><span class="line"><span class="keyword">endtask</span>: pre_body</span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::body();</span><br><span class="line">    <span class="keyword">repeat</span> (num_trans) <span class="keyword">begin</span></span><br><span class="line">        \`uvm_do(req)</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endtask</span>: body</span><br><span class="line"></span><br><span class="line"><span class="keyword">task</span> $<span class="number">1</span>::post_body();</span><br><span class="line">    <span class="comment">// Cleanup after sequence execution</span></span><br><span class="line">    \`uvm_info(get_type_name(), <span class="string">&quot;Sequence completed&quot;</span>, UVM_MEDIUM)</span><br><span class="line"><span class="keyword">endtask</span>: post_body</span><br><span class="line"></span><br><span class="line"># moved: sequence_item to COMMONLY USED SNIPPETS</span><br><span class="line"><span class="comment">// ============================================================================</span></span><br><span class="line"><span class="comment">// UVM SEQUENCE ITEM - Transaction Object (UVM Cookbook 5.2)</span></span><br><span class="line"><span class="comment">// ============================================================================</span></span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; <span class="keyword">extends</span> uvm_sequence_item;</span><br><span class="line">    \`uvm_object_utils($<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Transaction fields</span></span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [$&#123;<span class="number">2</span>:<span class="number">7</span>&#125;:<span class="number">0</span>] $&#123;<span class="number">3</span>:addr&#125;;</span><br><span class="line">    <span class="keyword">rand</span> <span class="keyword">bit</span> [$&#123;<span class="number">4</span>:<span class="number">31</span>&#125;:<span class="number">0</span>] $&#123;<span class="number">5</span>:data&#125;;</span><br><span class="line">    $&#123;<span class="number">6</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Constraints</span></span><br><span class="line">    <span class="keyword">constraint</span> $&#123;<span class="number">7</span>:valid&#125;_c &#123;</span><br><span class="line">        $&#123;<span class="number">8</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">void</span> do_copy(uvm_object rhs);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">bit</span> do_compare(uvm_object rhs, uvm_comparer comparer);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">void</span> do_print(uvm_printer printer);</span><br><span class="line">    <span class="keyword">extern</span> <span class="keyword">function</span> <span class="keyword">string</span> convert2string();</span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> $<span class="number">1</span>::<span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line"><span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::do_copy(uvm_object rhs);</span><br><span class="line">    $<span class="number">1</span> rhs_;</span><br><span class="line">    <span class="keyword">if</span> (!\<span class="built_in">$cast</span>(rhs_, rhs))</span><br><span class="line">        \`uvm_fatal(get_type_name(), <span class="string">&quot;Cast failed in do_copy&quot;</span>)</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.do_copy</span>(rhs);</span><br><span class="line">    <span class="keyword">this</span>.$<span class="number">3</span> = rhs_.$<span class="number">3</span>;</span><br><span class="line">    <span class="keyword">this</span>.$<span class="number">5</span> = rhs_.$<span class="number">5</span>;</span><br><span class="line"><span class="keyword">endfunction</span>: do_copy</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">bit</span> $<span class="number">1</span>::do_compare(uvm_object rhs, uvm_comparer comparer);</span><br><span class="line">    $<span class="number">1</span> rhs_;</span><br><span class="line">    <span class="keyword">if</span> (!\<span class="built_in">$cast</span>(rhs_, rhs))</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> (<span class="keyword">super</span><span class="variable">.do_compare</span>(rhs, comparer) &amp;&amp;</span><br><span class="line">            (<span class="keyword">this</span>.$<span class="number">3</span> == rhs_.$<span class="number">3</span>) &amp;&amp;</span><br><span class="line">            (<span class="keyword">this</span>.$<span class="number">5</span> == rhs_.$<span class="number">5</span>));</span><br><span class="line"><span class="keyword">endfunction</span>: do_compare</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> $<span class="number">1</span>::do_print(uvm_printer printer);</span><br><span class="line">    <span class="keyword">super</span><span class="variable">.do_print</span>(printer);</span><br><span class="line">    printer<span class="variable">.print_field</span>(<span class="string">&quot;$3&quot;</span>, <span class="keyword">this</span>.$<span class="number">3</span>, $<span class="number">2</span>+<span class="number">1</span>);</span><br><span class="line">    printer<span class="variable">.print_field</span>(<span class="string">&quot;$5&quot;</span>, <span class="keyword">this</span>.$<span class="number">5</span>, $<span class="number">4</span>+<span class="number">1</span>);</span><br><span class="line"><span class="keyword">endfunction</span>: do_print</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">string</span> $<span class="number">1</span>::convert2string();</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">$sformatf</span>(<span class="string">&quot;$3=0x%0h, $5=0x%0h&quot;</span>, $<span class="number">3</span>, $<span class="number">5</span>);</span><br><span class="line"><span class="keyword">endfunction</span>: convert2string</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">assert</span></span><br><span class="line"><span class="keyword">assert</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">else</span> \<span class="built_in">$error</span>(<span class="string">&quot;$&#123;2:Assertion failed&#125;&quot;</span>);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">property</span></span><br><span class="line"><span class="keyword">property</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    @(<span class="keyword">posedge</span> $&#123;<span class="number">2</span>:clk&#125;) $&#123;<span class="number">3</span>:condition&#125;;</span><br><span class="line"><span class="keyword">endproperty</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">sequence</span></span><br><span class="line"><span class="keyword">sequence</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">endsequence</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet implication</span><br><span class="line">$&#123;<span class="number">1</span>:antecedent&#125; |-&gt; $&#123;<span class="number">2</span>:consequent&#125;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># FILE TEMPLATES AND HEADERS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet sv_header</span><br><span class="line"><span class="comment">//==============================================================================</span></span><br><span class="line"><span class="comment">// File        : $&#123;1:`expand(&#x27;%:t&#x27;)`&#125;</span></span><br><span class="line"><span class="comment">// Project     : $&#123;2:Project Name&#125;</span></span><br><span class="line"><span class="comment">// Module      : $&#123;3:`expand(&#x27;%:t:r&#x27;)`&#125;</span></span><br><span class="line"><span class="comment">// Author      : $&#123;4:$USER&#125;</span></span><br><span class="line"><span class="comment">// Created     : $&#123;5:`strftime(&quot;%Y-%m-%d&quot;)`&#125;</span></span><br><span class="line"><span class="comment">// Modified    : $&#123;6:`strftime(&quot;%Y-%m-%d&quot;)`&#125;</span></span><br><span class="line"><span class="comment">//==============================================================================</span></span><br><span class="line"><span class="comment">// Description:</span></span><br><span class="line"><span class="comment">//   $&#123;7:Brief description&#125;</span></span><br><span class="line"><span class="comment">//==============================================================================</span></span><br><span class="line"></span><br><span class="line">$&#123;<span class="number">0</span>&#125;</span><br><span class="line"></span><br><span class="line">snippet header_guard</span><br><span class="line">\<span class="meta">`<span class="keyword">ifndef</span> $&#123;1:`toupper(substitute(expand(&#x27;%:t:r&#x27;), &#x27;[^A-Z0-9]&#x27;, &#x27;_&#x27;, &#x27;g&#x27;))`&#125;_SVH</span></span><br><span class="line">\<span class="meta">`<span class="keyword">define</span> $1_SVH</span></span><br><span class="line"></span><br><span class="line">$&#123;<span class="number">0</span>&#125;</span><br><span class="line"></span><br><span class="line">\<span class="meta">`<span class="keyword">endif</span> </span><span class="comment">// $1_SVH</span></span><br><span class="line"></span><br><span class="line">snippet tb</span><br><span class="line">\<span class="meta">`<span class="keyword">timescale</span> 1ns/1ps</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">module</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">localparam</span> <span class="keyword">int</span> PERIOD = $&#123;<span class="number">2</span>:<span class="number">10</span>&#125;;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">logic</span> $&#123;<span class="number">3</span>:clk&#125;;</span><br><span class="line">    <span class="keyword">logic</span> $&#123;<span class="number">4</span>:rst_n&#125;;</span><br><span class="line">    $&#123;<span class="number">5</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Clock generation</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        $<span class="number">3</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">forever</span> <span class="variable">#(PERIOD/2)</span> $<span class="number">3</span> = ~$<span class="number">3</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Reset generation</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        $<span class="number">4</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">repeat</span>(<span class="number">2</span>) @(<span class="keyword">posedge</span> $<span class="number">3</span>);</span><br><span class="line">        $<span class="number">4</span> = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// DUT instantiation</span></span><br><span class="line">    $&#123;<span class="number">6</span>:dut&#125; u_dut (</span><br><span class="line">        <span class="variable">.clk</span>($<span class="number">3</span>),</span><br><span class="line">        <span class="variable">.rst_n</span>($<span class="number">4</span>)$&#123;<span class="number">7</span>&#125;</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Test stimulus</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        @(<span class="keyword">posedge</span> $<span class="number">4</span>);</span><br><span class="line">        $&#123;<span class="number">0</span>&#125;</span><br><span class="line">        #<span class="number">1000</span>;</span><br><span class="line">        \<span class="built_in">$finish</span>;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Waveform dump</span></span><br><span class="line">    <span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">        \<span class="built_in">$dumpfile</span>(<span class="string">&quot;$&#123;8:`expand(&#x27;%:t:r&#x27;)`&#125;.vcd&quot;</span>);</span><br><span class="line">        \<span class="built_in">$dumpvars</span>(<span class="number">0</span>, $<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">endmodule</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># MODULE AND INTERFACE DEFINITIONS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">module</span></span><br><span class="line"><span class="keyword">module</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; #(</span><br><span class="line">    <span class="keyword">parameter</span> <span class="keyword">int</span> $&#123;<span class="number">2</span>:WIDTH&#125; = $&#123;<span class="number">3</span>:<span class="number">8</span>&#125;</span><br><span class="line">) (</span><br><span class="line">    <span class="keyword">input</span>  <span class="keyword">logic</span> $&#123;<span class="number">4</span>:clk&#125;,</span><br><span class="line">    <span class="keyword">input</span>  <span class="keyword">logic</span> $&#123;<span class="number">5</span>:rst_n&#125;,</span><br><span class="line">    $&#123;<span class="number">6</span>&#125;</span><br><span class="line">);</span><br><span class="line">    $&#123;<span class="number">0</span>&#125;</span><br><span class="line"><span class="keyword">endmodule</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">interface</span></span><br><span class="line"><span class="keyword">interface</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; (</span><br><span class="line">    <span class="keyword">input</span> <span class="keyword">logic</span> clk,</span><br><span class="line">    <span class="keyword">input</span> <span class="keyword">logic</span> rst_n</span><br><span class="line">);</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">endinterface</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">modport</span></span><br><span class="line"><span class="keyword">modport</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_mp (</span><br><span class="line">    $&#123;<span class="number">2</span>:<span class="keyword">input</span> clk&#125;</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">package</span></span><br><span class="line"><span class="keyword">package</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_pkg;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">endpackage</span>: $<span class="number">1_</span>pkg</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">program</span></span><br><span class="line"><span class="keyword">program</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">endprogram</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># DATA TYPES</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">logic</span></span><br><span class="line"><span class="keyword">logic</span> $&#123;<span class="number">1</span>:[<span class="number">7</span>:<span class="number">0</span>]&#125; $&#123;<span class="number">2</span>:signal&#125;$&#123;<span class="number">3</span>: = $&#123;<span class="number">4</span>:<span class="number">0</span>&#125;&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">wire</span></span><br><span class="line"><span class="keyword">wire</span> $&#123;<span class="number">1</span>:[<span class="number">7</span>:<span class="number">0</span>]&#125; $&#123;<span class="number">2</span>:signal&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">reg</span></span><br><span class="line"><span class="keyword">reg</span> $&#123;<span class="number">1</span>:[<span class="number">7</span>:<span class="number">0</span>]&#125; $&#123;<span class="number">2</span>:signal&#125;$&#123;<span class="number">3</span>: = $&#123;<span class="number">4</span>:<span class="number">0</span>&#125;&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">bit</span></span><br><span class="line"><span class="keyword">bit</span> $&#123;<span class="number">1</span>:[<span class="number">7</span>:<span class="number">0</span>]&#125; $&#123;<span class="number">2</span>:signal&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">byte</span></span><br><span class="line"><span class="keyword">byte</span> $&#123;<span class="number">1</span>:variable&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">int</span></span><br><span class="line"><span class="keyword">int</span> $&#123;<span class="number">1</span>:variable&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">parameter</span></span><br><span class="line"><span class="keyword">parameter</span> $&#123;<span class="number">1</span>:<span class="keyword">int</span>&#125; $&#123;<span class="number">2</span>:`toupper(expand(&#x27;%:t:r&#x27;))`&#125; = $&#123;<span class="number">3</span>:value&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">localparam</span></span><br><span class="line"><span class="keyword">localparam</span> $&#123;<span class="number">1</span>:<span class="keyword">int</span>&#125; $&#123;<span class="number">2</span>:`toupper(expand(&#x27;%:t:r&#x27;))`&#125; = $&#123;<span class="number">3</span>:value&#125;;</span><br><span class="line"></span><br><span class="line">snippet typedef_struct</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> <span class="keyword">packed</span> &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line">&#125; $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_s;</span><br><span class="line"></span><br><span class="line">snippet typedef_enum</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">enum</span> <span class="keyword">logic</span> $&#123;<span class="number">1</span>:[<span class="number">1</span>:<span class="number">0</span>]&#125; &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>:IDLE&#125;   = $&#123;<span class="number">3</span>:<span class="number">2&#x27;b00</span>&#125;,</span><br><span class="line">    $&#123;<span class="number">4</span>:ACTIVE&#125; = $&#123;<span class="number">5</span>:<span class="number">2&#x27;b01</span>&#125;</span><br><span class="line">&#125; $&#123;<span class="number">6</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_e;</span><br><span class="line"></span><br><span class="line">snippet typedef_union</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">union</span> <span class="keyword">packed</span> &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line">&#125; $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_u;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">enum</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">enum</span> $&#123;<span class="number">1</span>:<span class="keyword">logic</span>&#125; &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>:IDLE&#125;,</span><br><span class="line">    $&#123;<span class="number">3</span>:ACTIVE&#125;</span><br><span class="line">&#125; $&#123;<span class="number">4</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_e;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># ARRAYS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet dynamic_array</span><br><span class="line">$&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:array&#125;[];</span><br><span class="line"></span><br><span class="line">snippet associative_array</span><br><span class="line">$&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:array&#125;[$&#123;<span class="number">3</span>:key_type&#125;];</span><br><span class="line"></span><br><span class="line">snippet queue</span><br><span class="line">$&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:queue&#125;[$];</span><br><span class="line"></span><br><span class="line">snippet packed_array</span><br><span class="line">$&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; [$&#123;<span class="number">2</span>:msb&#125;:$&#123;<span class="number">3</span>:lsb&#125;] $&#123;<span class="number">4</span>:array&#125;;</span><br><span class="line"></span><br><span class="line">snippet unpacked_array</span><br><span class="line">$&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:array&#125;[$&#123;<span class="number">3</span>:size&#125;];</span><br><span class="line"></span><br><span class="line">snippet memory</span><br><span class="line"><span class="keyword">reg</span> [$&#123;<span class="number">1</span>:<span class="number">7</span>&#125;:<span class="number">0</span>] $&#123;<span class="number">2</span>:memory&#125; [<span class="number">0</span>:$&#123;<span class="number">3</span>:<span class="number">255</span>&#125;];</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># PROCEDURAL BLOCKS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">initial</span></span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">1</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">always</span></span><br><span class="line"><span class="keyword">always</span> @($&#123;<span class="number">1</span>:<span class="keyword">posedge</span> clk&#125;) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">always_ff</span></span><br><span class="line"><span class="keyword">always_ff</span> @(<span class="keyword">posedge</span> $&#123;<span class="number">1</span>:clk&#125; <span class="keyword">or</span> <span class="keyword">negedge</span> $&#123;<span class="number">2</span>:rst_n&#125;) <span class="keyword">begin</span></span><br><span class="line">    <span class="keyword">if</span> (!$<span class="number">2</span>)</span><br><span class="line">        $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">always_comb</span></span><br><span class="line"><span class="keyword">always_comb</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">1</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">always_latch</span></span><br><span class="line"><span class="keyword">always_latch</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">1</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">final</span></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">1</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># CONTROL STRUCTURES</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">if</span></span><br><span class="line"><span class="keyword">if</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet ife</span><br><span class="line"><span class="keyword">if</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">3</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">case</span></span><br><span class="line"><span class="keyword">case</span> ($&#123;<span class="number">1</span>:expression&#125;)</span><br><span class="line">    $&#123;<span class="number">2</span>:value1&#125;: <span class="keyword">begin</span></span><br><span class="line">        $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">default</span>: <span class="keyword">begin</span></span><br><span class="line">        $&#123;<span class="number">4</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">casex</span></span><br><span class="line"><span class="keyword">casex</span> ($&#123;<span class="number">1</span>:expression&#125;)</span><br><span class="line">    $&#123;<span class="number">2</span>:value1&#125;: $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">default</span>: $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">casez</span></span><br><span class="line"><span class="keyword">casez</span> ($&#123;<span class="number">1</span>:expression&#125;)</span><br><span class="line">    $&#123;<span class="number">2</span>:value1&#125;: $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">default</span>: $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">unique</span></span><br><span class="line"><span class="keyword">unique</span> <span class="keyword">case</span> ($&#123;<span class="number">1</span>:expression&#125;)</span><br><span class="line">    $&#123;<span class="number">2</span>:value&#125;: $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">default</span>: $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">priority</span></span><br><span class="line"><span class="keyword">priority</span> <span class="keyword">case</span> ($&#123;<span class="number">1</span>:expression&#125;)</span><br><span class="line">    $&#123;<span class="number">2</span>:value&#125;: $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">default</span>: $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"></span><br><span class="line">snippet ternary</span><br><span class="line">$&#123;<span class="number">1</span>:condition&#125; ? $&#123;<span class="number">2</span>:true&#125; : $&#123;<span class="number">3</span>:false&#125;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># LOOPS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">for</span></span><br><span class="line"><span class="keyword">for</span> ($&#123;<span class="number">1</span>:<span class="keyword">int</span> i = <span class="number">0</span>&#125;; $&#123;<span class="number">2</span>:i &lt; n&#125;; $&#123;<span class="number">3</span>:i++&#125;) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">foreach</span></span><br><span class="line"><span class="keyword">foreach</span> ($&#123;<span class="number">1</span>:array&#125;[$&#123;<span class="number">2</span>:i&#125;]) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">3</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">while</span></span><br><span class="line"><span class="keyword">while</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">do</span></span><br><span class="line"><span class="keyword">do</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">while</span> ($&#123;<span class="number">1</span>:condition&#125;);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">repeat</span></span><br><span class="line"><span class="keyword">repeat</span> ($&#123;<span class="number">1</span>:count&#125;) <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">forever</span></span><br><span class="line"><span class="keyword">forever</span> <span class="keyword">begin</span></span><br><span class="line">    $&#123;<span class="number">1</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># FUNCTIONS AND TASKS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">function</span></span><br><span class="line"><span class="keyword">function</span> $&#123;<span class="number">1</span>:<span class="keyword">void</span>&#125; $&#123;<span class="number">2</span>:`expand(&#x27;%:t:r&#x27;)`&#125;($&#123;<span class="number">3</span>&#125;);</span><br><span class="line">    $&#123;<span class="number">4</span>&#125;</span><br><span class="line"><span class="keyword">endfunction</span>: $<span class="number">2</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">task</span></span><br><span class="line"><span class="keyword">task</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;($&#123;<span class="number">2</span>&#125;);</span><br><span class="line">    $&#123;<span class="number">3</span>&#125;</span><br><span class="line"><span class="keyword">endtask</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet extern_function</span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">function</span> $&#123;<span class="number">1</span>:return_type&#125; $&#123;<span class="number">2</span>:`expand(&#x27;%:t:r&#x27;)`&#125;($&#123;<span class="number">3</span>&#125;);</span><br><span class="line"></span><br><span class="line">snippet extern_task</span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">task</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;($&#123;<span class="number">2</span>&#125;);</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># CLASSES</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">class</span></span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">        $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet class_param</span><br><span class="line"><span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125; #(</span><br><span class="line">    <span class="keyword">parameter</span> <span class="keyword">int</span> $&#123;<span class="number">2</span>:WIDTH&#125; = $&#123;<span class="number">3</span>:<span class="number">8</span>&#125;</span><br><span class="line">);</span><br><span class="line">    $&#123;<span class="number">4</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;$1&quot;</span>);</span><br><span class="line">        $&#123;<span class="number">5</span>&#125;</span><br><span class="line">    <span class="keyword">endfunction</span>: <span class="keyword">new</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet virtual_class</span><br><span class="line"><span class="keyword">virtual</span> <span class="keyword">class</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line">    <span class="keyword">pure</span> <span class="keyword">virtual</span> <span class="keyword">function</span> $&#123;<span class="number">3</span>:<span class="keyword">void</span>&#125; $&#123;<span class="number">4</span>:method&#125;();</span><br><span class="line"><span class="keyword">endclass</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">extends</span></span><br><span class="line"><span class="keyword">extends</span> $&#123;<span class="number">1</span>:base_class&#125;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">static</span></span><br><span class="line"><span class="keyword">static</span> $&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:name&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">protected</span></span><br><span class="line"><span class="keyword">protected</span> $&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:name&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">local</span></span><br><span class="line"><span class="keyword">local</span> $&#123;<span class="number">1</span>:<span class="keyword">type</span>&#125; $&#123;<span class="number">2</span>:name&#125;;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># CONCURRENCY</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">fork</span></span><br><span class="line"><span class="keyword">fork</span></span><br><span class="line">    <span class="keyword">begin</span></span><br><span class="line">        $&#123;<span class="number">1</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">    <span class="keyword">begin</span></span><br><span class="line">        $&#123;<span class="number">2</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">join</span></span><br><span class="line"></span><br><span class="line">snippet fork_join_any</span><br><span class="line"><span class="keyword">fork</span></span><br><span class="line">    <span class="keyword">begin</span></span><br><span class="line">        $&#123;<span class="number">1</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">join_any</span></span><br><span class="line"></span><br><span class="line">snippet fork_join_none</span><br><span class="line"><span class="keyword">fork</span></span><br><span class="line">    <span class="keyword">begin</span></span><br><span class="line">        $&#123;<span class="number">1</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">join_none</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">wait</span></span><br><span class="line"><span class="keyword">wait</span> ($&#123;<span class="number">1</span>:condition&#125;);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">event</span></span><br><span class="line"><span class="keyword">event</span> $&#123;<span class="number">1</span>:event_name&#125;;</span><br><span class="line"></span><br><span class="line">snippet trigger</span><br><span class="line">-&gt; $&#123;<span class="number">1</span>:event_name&#125;;</span><br><span class="line"></span><br><span class="line">snippet mailbox</span><br><span class="line">mailbox <span class="variable">#($&#123;1:type&#125;) $&#123;2:mbx&#125; = new($&#123;3:bound&#125;)</span>;</span><br><span class="line"></span><br><span class="line">snippet semaphore</span><br><span class="line">semaphore $&#123;<span class="number">1</span>:sem&#125; = <span class="keyword">new</span>($&#123;<span class="number">2</span>:count&#125;);</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># RANDOMIZATION AND CONSTRAINTS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet randomize</span><br><span class="line"><span class="keyword">assert</span> ($&#123;<span class="number">1</span>:object&#125;<span class="variable">.randomize</span>() <span class="keyword">with</span> &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>:constraints&#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">constraint</span></span><br><span class="line"><span class="keyword">constraint</span> $&#123;<span class="number">1</span>:name&#125;_c &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">dist</span></span><br><span class="line">$&#123;<span class="number">1</span>:variable&#125; <span class="keyword">dist</span> &#123;</span><br><span class="line">    $&#123;<span class="number">2</span>:value1&#125; := $&#123;<span class="number">3</span>:weight1&#125;,</span><br><span class="line">    $&#123;<span class="number">4</span>:value2&#125; := $&#123;<span class="number">5</span>:weight2&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">snippet solve_before</span><br><span class="line"><span class="keyword">solve</span> $&#123;<span class="number">1</span>:var1&#125; <span class="keyword">before</span> $&#123;<span class="number">2</span>:var2&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">soft</span></span><br><span class="line"><span class="keyword">soft</span> $&#123;<span class="number">1</span>:variable&#125; == $&#123;<span class="number">2</span>:value&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">inside</span></span><br><span class="line">$&#123;<span class="number">1</span>:variable&#125; <span class="keyword">inside</span> &#123;$&#123;<span class="number">2</span>:range&#125;&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">randcase</span></span><br><span class="line"><span class="keyword">randcase</span></span><br><span class="line">    $&#123;<span class="number">1</span>:weight1&#125;: $&#123;<span class="number">2</span>:stmt1&#125;;</span><br><span class="line">    $&#123;<span class="number">3</span>:weight2&#125;: $&#123;<span class="number">4</span>:stmt2&#125;;</span><br><span class="line"><span class="keyword">endcase</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># COVERAGE</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">covergroup</span></span><br><span class="line"><span class="keyword">covergroup</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_cg @($&#123;<span class="number">2</span>:<span class="keyword">posedge</span> clk&#125;);</span><br><span class="line">    option<span class="variable">.per_instance</span> = <span class="number">1</span>;</span><br><span class="line">    $&#123;<span class="number">3</span>&#125;</span><br><span class="line"><span class="keyword">endgroup</span>: $<span class="number">1_</span>cg</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">coverpoint</span></span><br><span class="line">$&#123;<span class="number">1</span>:signal&#125;_cp: <span class="keyword">coverpoint</span> $&#123;<span class="number">2</span>:signal&#125; &#123;</span><br><span class="line">    <span class="keyword">bins</span> low  = &#123;[<span class="number">0</span>:$&#123;<span class="number">3</span>:<span class="number">127</span>&#125;]&#125;;</span><br><span class="line">    <span class="keyword">bins</span> high = &#123;[$&#123;<span class="number">4</span>:<span class="number">128</span>&#125;:<span class="number">255</span>]&#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">cross</span></span><br><span class="line">$&#123;<span class="number">1</span>:name&#125;_cross: <span class="keyword">cross</span> $&#123;<span class="number">2</span>:cp1&#125;, $&#123;<span class="number">3</span>:cp2&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">bins</span></span><br><span class="line"><span class="keyword">bins</span> $&#123;<span class="number">1</span>:name&#125; = &#123;$&#123;<span class="number">2</span>:values&#125;&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">ignore_bins</span></span><br><span class="line"><span class="keyword">ignore_bins</span> $&#123;<span class="number">1</span>:name&#125; = &#123;$&#123;<span class="number">2</span>:values&#125;&#125;;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">illegal_bins</span></span><br><span class="line"><span class="keyword">illegal_bins</span> $&#123;<span class="number">1</span>:name&#125; = &#123;$&#123;<span class="number">2</span>:values&#125;&#125;;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># ASSERTIONS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">assert</span></span><br><span class="line"><span class="keyword">assert</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">else</span> \<span class="built_in">$error</span>(<span class="string">&quot;$&#123;2:Assertion failed&#125;&quot;</span>);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">property</span></span><br><span class="line"><span class="keyword">property</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)&#125;;</span><br><span class="line">    @(<span class="keyword">posedge</span> $&#123;<span class="number">2</span>:clk&#125;) $&#123;<span class="number">3</span>:condition&#125;;</span><br><span class="line"><span class="keyword">endproperty</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">sequence</span></span><br><span class="line"><span class="keyword">sequence</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)&#125;;</span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line"><span class="keyword">endsequence</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">assume</span></span><br><span class="line"><span class="keyword">assume</span> <span class="keyword">property</span> ($&#123;<span class="number">1</span>:property_name&#125;);</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">cover</span></span><br><span class="line"><span class="keyword">cover</span> <span class="keyword">property</span> ($&#123;<span class="number">1</span>:property_name&#125;);</span><br><span class="line"></span><br><span class="line">snippet sva</span><br><span class="line"><span class="keyword">property</span> $&#123;<span class="number">1</span>:prop_name&#125;;</span><br><span class="line">    @(<span class="keyword">posedge</span> $&#123;<span class="number">2</span>:clk&#125;) <span class="keyword">disable</span> <span class="keyword">iff</span> (!$&#123;<span class="number">3</span>:rst_n&#125;)</span><br><span class="line">    $&#123;<span class="number">4</span>:<span class="keyword">sequence</span>&#125;;</span><br><span class="line"><span class="keyword">endproperty</span></span><br><span class="line"></span><br><span class="line">assert_$<span class="number">1</span>: <span class="keyword">assert</span> <span class="keyword">property</span> ($<span class="number">1</span>)</span><br><span class="line">    <span class="keyword">else</span> \<span class="built_in">$error</span>(<span class="string">&quot;$1 failed at %0t&quot;</span>, \<span class="built_in">$time</span>);</span><br><span class="line"></span><br><span class="line">snippet implication</span><br><span class="line">$&#123;<span class="number">1</span>:antecedent&#125; |-&gt; $&#123;<span class="number">2</span>:consequent&#125;</span><br><span class="line"></span><br><span class="line">snippet overlapping</span><br><span class="line">$&#123;<span class="number">1</span>:antecedent&#125; |=&gt; $&#123;<span class="number">2</span>:consequent&#125;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># GENERATE</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">generate</span></span><br><span class="line"><span class="keyword">generate</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">genvar</span> $&#123;<span class="number">1</span>:i&#125; = <span class="number">0</span>; $<span class="number">1</span> &lt; $&#123;<span class="number">2</span>:N&#125;; $<span class="number">1</span>++) <span class="keyword">begin</span> : $&#123;<span class="number">3</span>:gen_block&#125;</span><br><span class="line">        $&#123;<span class="number">4</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endgenerate</span></span><br><span class="line"></span><br><span class="line">snippet generate_if</span><br><span class="line"><span class="keyword">generate</span></span><br><span class="line">    <span class="keyword">if</span> ($&#123;<span class="number">1</span>:condition&#125;) <span class="keyword">begin</span> : $&#123;<span class="number">2</span>:gen_label&#125;</span><br><span class="line">        $&#123;<span class="number">3</span>&#125;</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">endgenerate</span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">genvar</span></span><br><span class="line"><span class="keyword">genvar</span> $&#123;<span class="number">1</span>:i&#125;;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># INSTANTIATION</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet inst</span><br><span class="line">$&#123;<span class="number">1</span>:module_name&#125; #(</span><br><span class="line">    .$&#123;<span class="number">2</span>:PARAM&#125;($&#123;<span class="number">3</span>:VALUE&#125;)</span><br><span class="line">) $&#123;<span class="number">4</span>:u_$&#123;<span class="number">1</span>/([a-z]+).*/$<span class="number">1</span>/&#125;&#125; (</span><br><span class="line">    .$&#123;<span class="number">5</span>:clk&#125;($&#123;<span class="number">6</span>:clk&#125;),</span><br><span class="line">    .$&#123;<span class="number">7</span>:rst_n&#125;($&#123;<span class="number">8</span>:rst_n&#125;)$&#123;<span class="number">9</span>&#125;</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">snippet port</span><br><span class="line">.$&#123;<span class="number">1</span>:port&#125;($&#123;<span class="number">2</span>:signal&#125;)$&#123;<span class="number">3</span>:,&#125;</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">bind</span></span><br><span class="line"><span class="keyword">bind</span> $&#123;<span class="number">1</span>:<span class="keyword">instance</span>&#125; $&#123;<span class="number">2</span>:<span class="keyword">module</span>&#125; $&#123;<span class="number">3</span>:bind_inst&#125; ($&#123;<span class="number">4</span>&#125;);</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># CLOCKING</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">clocking</span></span><br><span class="line"><span class="keyword">clocking</span> $&#123;<span class="number">1</span>:`expand(&#x27;%:t:r&#x27;)`&#125;_cb @(<span class="keyword">posedge</span> $&#123;<span class="number">2</span>:clk&#125;);</span><br><span class="line">    <span class="keyword">default</span> <span class="keyword">input</span> #<span class="number">1</span>step <span class="keyword">output</span> #<span class="number">1</span>ns;</span><br><span class="line">    $&#123;<span class="number">3</span>&#125;</span><br><span class="line"><span class="keyword">endclocking</span>: $<span class="number">1</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># PREPROCESSOR DIRECTIVES</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet define</span><br><span class="line">\<span class="meta">`<span class="keyword">define</span> $&#123;1:`toupper(expand(&#x27;%:t:r&#x27;))`&#125; $&#123;2:value&#125;</span></span><br><span class="line"></span><br><span class="line">snippet ifdef</span><br><span class="line">\<span class="meta">`<span class="keyword">ifdef</span> $&#123;1:`toupper(expand(&#x27;%:t:r&#x27;))`&#125;</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line">\<span class="meta">`<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">snippet ifndef</span><br><span class="line">\<span class="meta">`<span class="keyword">ifndef</span> $&#123;1:`toupper(expand(&#x27;%:t:r&#x27;))`&#125;</span></span><br><span class="line">    $&#123;<span class="number">2</span>&#125;</span><br><span class="line">\<span class="meta">`<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">snippet <span class="keyword">include</span></span><br><span class="line">\<span class="meta">`<span class="keyword">include</span> &quot;$&#123;1:filename.svh&#125;&quot;</span></span><br><span class="line"></span><br><span class="line">snippet timescale</span><br><span class="line">\<span class="meta">`<span class="keyword">timescale</span> $&#123;1:1ns&#125;/$&#123;2:1ps&#125;</span></span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># SYSTEM TASKS</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line">snippet display</span><br><span class="line">\<span class="built_in">$display</span>(<span class="string">&quot;$&#123;1:message</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet monitor</span></span><br><span class="line"><span class="string">\$monitor(&quot;</span>Time=%<span class="number">0</span>t: $&#123;<span class="number">1</span>:signal&#125;=%<span class="number">0</span>d<span class="string">&quot;, \$time, $&#123;2:signal&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet finish</span></span><br><span class="line"><span class="string">\$finish;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet stop</span></span><br><span class="line"><span class="string">\$stop;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet readmemh</span></span><br><span class="line"><span class="string">\$readmemh(&quot;</span>$&#123;<span class="number">1</span>:file<span class="variable">.hex</span>&#125;<span class="string">&quot;, $&#123;2:memory&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet fopen</span></span><br><span class="line"><span class="string">integer $&#123;1:fh&#125;;</span></span><br><span class="line"><span class="string">$1 = \$fopen(&quot;</span>$&#123;<span class="number">2</span>:file<span class="variable">.txt</span>&#125;<span class="string">&quot;, &quot;</span>$&#123;<span class="number">3</span>:w&#125;<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sformatf</span></span><br><span class="line"><span class="string">\$sformatf(&quot;</span>$&#123;<span class="number">1</span>:format&#125;<span class="string">&quot;, $&#123;2:args&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet urandom</span></span><br><span class="line"><span class="string">\$urandom()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet urandom_range</span></span><br><span class="line"><span class="string">\$urandom_range($&#123;1:max&#125;, $&#123;2:min&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet cast</span></span><br><span class="line"><span class="string">\$cast($&#123;1:dest&#125;, $&#123;2:source&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># FSM TEMPLATE</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet fsm</span></span><br><span class="line"><span class="string">typedef enum logic [$&#123;1:1&#125;:0] &#123;</span></span><br><span class="line"><span class="string">    $&#123;2:IDLE&#125;   = $&#123;3:2&#x27;b00&#125;,</span></span><br><span class="line"><span class="string">    $&#123;4:ACTIVE&#125; = $&#123;5:2&#x27;b01&#125;,</span></span><br><span class="line"><span class="string">    $&#123;6:DONE&#125;   = $&#123;7:2&#x27;b10&#125;</span></span><br><span class="line"><span class="string">&#125; $&#123;8:state&#125;_t;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">$8_t current_state, next_state;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">always_ff @(posedge $&#123;9:clk&#125; or negedge $&#123;10:rst_n&#125;) begin</span></span><br><span class="line"><span class="string">    if (!$10)</span></span><br><span class="line"><span class="string">        current_state &lt;= $2;</span></span><br><span class="line"><span class="string">    else</span></span><br><span class="line"><span class="string">        current_state &lt;= next_state;</span></span><br><span class="line"><span class="string">end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">always_comb begin</span></span><br><span class="line"><span class="string">    next_state = current_state;</span></span><br><span class="line"><span class="string">    case (current_state)</span></span><br><span class="line"><span class="string">        $2:   $&#123;11&#125;</span></span><br><span class="line"><span class="string">        $4:   $&#123;12&#125;</span></span><br><span class="line"><span class="string">        $6:   $&#123;13&#125;</span></span><br><span class="line"><span class="string">        default: next_state = $2;</span></span><br><span class="line"><span class="string">    endcase</span></span><br><span class="line"><span class="string">end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># COMMON PATTERNS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet fifo</span></span><br><span class="line"><span class="string">logic [$&#123;1:DEPTH_W&#125;-1:0] wr_ptr, rd_ptr;</span></span><br><span class="line"><span class="string">logic [$&#123;2:DATA_W&#125;-1:0] mem [2**$1];</span></span><br><span class="line"><span class="string">logic empty, full;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">assign empty = (wr_ptr == rd_ptr);</span></span><br><span class="line"><span class="string">assign full  = (wr_ptr + 1 == rd_ptr);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet handshake</span></span><br><span class="line"><span class="string">logic $&#123;1:valid&#125;, $&#123;2:ready&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">always_ff @(posedge $&#123;3:clk&#125; or negedge $&#123;4:rst_n&#125;) begin</span></span><br><span class="line"><span class="string">    if (!$4)</span></span><br><span class="line"><span class="string">        $1 &lt;= 1&#x27;b0;</span></span><br><span class="line"><span class="string">    else if ($1 &amp;&amp; $2)</span></span><br><span class="line"><span class="string">        $1 &lt;= 1&#x27;b0;</span></span><br><span class="line"><span class="string">    else if ($&#123;5:condition&#125;)</span></span><br><span class="line"><span class="string">        $1 &lt;= 1&#x27;b1;</span></span><br><span class="line"><span class="string">end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet assign</span></span><br><span class="line"><span class="string">assign $&#123;1:target&#125; = $&#123;2:expression&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UVM COMPONENTS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet component_param sequence</span></span><br><span class="line"><span class="string">class $&#123;1:`expand(&#x27;%:t:r&#x27;)`&#125; #(</span></span><br><span class="line"><span class="string">    parameter int $&#123;2:DATA_WIDTH&#125; = $&#123;3:32&#125;</span></span><br><span class="line"><span class="string">) extends uvm_sequence #($&#123;4:`substitute(expand(&#x27;%:t:r&#x27;), &#x27;_\(seq\|sequence\)$&#x27;, &#x27;_item&#x27;, &#x27;&#x27;)`&#125;#($2));</span></span><br><span class="line"><span class="string">    `uvm_object_param_utils($1#($2))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    typedef $4#($2) item_t;</span></span><br><span class="line"><span class="string">    rand int unsigned num_trans = $&#123;5:10&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    extern function new(string name = &quot;</span>$<span class="number">1</span><span class="string">&quot;);</span></span><br><span class="line"><span class="string">    extern virtual task body();</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">endclass: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function $1#($2)::new(string name = &quot;</span>$<span class="number">1</span><span class="string">&quot;);</span></span><br><span class="line"><span class="string">    super.new(name);</span></span><br><span class="line"><span class="string">endfunction: new</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">task $1#($2)::body();</span></span><br><span class="line"><span class="string">    repeat (num_trans) begin</span></span><br><span class="line"><span class="string">        `uvm_do(req)</span></span><br><span class="line"><span class="string">    end</span></span><br><span class="line"><span class="string">endtask: body</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sequence_item</span></span><br><span class="line"><span class="string">class $&#123;1:`expand(&#x27;%:t:r&#x27;)`&#125; extends uvm_sequence_item;</span></span><br><span class="line"><span class="string">    `uvm_object_utils($1)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    // Transaction fields</span></span><br><span class="line"><span class="string">    rand bit [$&#123;2:7&#125;:0] $&#123;3:addr&#125;;</span></span><br><span class="line"><span class="string">    rand bit [$&#123;4:31&#125;:0] $&#123;5:data&#125;;</span></span><br><span class="line"><span class="string">    $&#123;6&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    // Constraints</span></span><br><span class="line"><span class="string">    constraint $&#123;7:valid&#125;_c &#123;</span></span><br><span class="line"><span class="string">        $&#123;8&#125;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    extern function new(string name = &quot;</span>$<span class="number">1</span><span class="string">&quot;);</span></span><br><span class="line"><span class="string">    extern function void do_copy(uvm_object rhs);</span></span><br><span class="line"><span class="string">    extern function bit do_compare(uvm_object rhs, uvm_comparer comparer);</span></span><br><span class="line"><span class="string">    extern function void do_print(uvm_printer printer);</span></span><br><span class="line"><span class="string">    extern function string convert2string();</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">endclass: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function $1::new(string name = &quot;</span>$<span class="number">1</span><span class="string">&quot;);</span></span><br><span class="line"><span class="string">    super.new(name);</span></span><br><span class="line"><span class="string">endfunction: new</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function void $1::do_copy(uvm_object rhs);</span></span><br><span class="line"><span class="string">    $1 rhs_;</span></span><br><span class="line"><span class="string">    if (!$cast(rhs_, rhs))</span></span><br><span class="line"><span class="string">        `uvm_fatal(get_type_name(), &quot;</span>Cast failed in do_copy<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    super.do_copy(rhs);</span></span><br><span class="line"><span class="string">    this.$3 = rhs_.$3;</span></span><br><span class="line"><span class="string">    this.$5 = rhs_.$5;</span></span><br><span class="line"><span class="string">endfunction: do_copy</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function bit $1::do_compare(uvm_object rhs, uvm_comparer comparer);</span></span><br><span class="line"><span class="string">    $1 rhs_;</span></span><br><span class="line"><span class="string">    if (!$cast(rhs_, rhs))</span></span><br><span class="line"><span class="string">        return 0;</span></span><br><span class="line"><span class="string">    return (super.do_compare(rhs, comparer) &amp;&amp;</span></span><br><span class="line"><span class="string">            (this.$3 == rhs_.$3) &amp;&amp;</span></span><br><span class="line"><span class="string">            (this.$5 == rhs_.$5));</span></span><br><span class="line"><span class="string">endfunction: do_compare</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function void $1::do_print(uvm_printer printer);</span></span><br><span class="line"><span class="string">    super.do_print(printer);</span></span><br><span class="line"><span class="string">    printer.print_field(&quot;</span>$<span class="number">3</span><span class="string">&quot;, this.$3, $2+1);</span></span><br><span class="line"><span class="string">    printer.print_field(&quot;</span>$<span class="number">5</span><span class="string">&quot;, this.$5, $4+1);</span></span><br><span class="line"><span class="string">endfunction: do_print</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function string $1::convert2string();</span></span><br><span class="line"><span class="string">    return $sformatf(&quot;</span>$<span class="number">3</span>=<span class="number">0</span>x%<span class="number">0</span>h, $<span class="number">5</span>=<span class="number">0</span>x%<span class="number">0</span>h<span class="string">&quot;, $3, $5);</span></span><br><span class="line"><span class="string">endfunction: convert2string</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># SYSTEMVERILOG ASSERTIONS (SVA) - COMPREHENSIVE</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_property</span></span><br><span class="line"><span class="string">// ============================================================================</span></span><br><span class="line"><span class="string">// SVA PROPERTY - Assertion Property (IEEE 1800-2017 Chapter 16)</span></span><br><span class="line"><span class="string">// ============================================================================</span></span><br><span class="line"><span class="string">// Purpose: Define temporal property for verification</span></span><br><span class="line"><span class="string">//</span></span><br><span class="line"><span class="string">// Property Structure:</span></span><br><span class="line"><span class="string">//   property name;</span></span><br><span class="line"><span class="string">//     @(posedge clk) disable iff (reset)</span></span><br><span class="line"><span class="string">//     antecedent |-&gt; consequent;</span></span><br><span class="line"><span class="string">//   endproperty</span></span><br><span class="line"><span class="string">//</span></span><br><span class="line"><span class="string">// Implication Operators:</span></span><br><span class="line"><span class="string">//   |-&gt;  Overlapping (consequent checked same cycle)</span></span><br><span class="line"><span class="string">//   |=&gt;  Non-overlapping (consequent checked next cycle)</span></span><br><span class="line"><span class="string">//</span></span><br><span class="line"><span class="string">// Sequence Operators:</span></span><br><span class="line"><span class="string">//   ##n  - Delay by n cycles</span></span><br><span class="line"><span class="string">//   ##[m:n] - Delay between m and n cycles</span></span><br><span class="line"><span class="string">//   [*n] - Repeat exactly n times</span></span><br><span class="line"><span class="string">//   [*m:n] - Repeat between m and n times</span></span><br><span class="line"><span class="string">//   [-&gt;n] - Goto repetition (non-consecutive)</span></span><br><span class="line"><span class="string">//   [=n]  - Non-consecutive repetition</span></span><br><span class="line"><span class="string">//</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">//   property req_ack;</span></span><br><span class="line"><span class="string">//     @(posedge clk) disable iff (rst)</span></span><br><span class="line"><span class="string">//     req |-&gt; ##[1:3] ack;</span></span><br><span class="line"><span class="string">//   endproperty</span></span><br><span class="line"><span class="string">// ============================================================================</span></span><br><span class="line"><span class="string">property $&#123;1:prop_name&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;) disable iff ($&#123;3:!rst_n&#125;)</span></span><br><span class="line"><span class="string">    $&#123;4:antecedent&#125; |-&gt; $&#123;5:consequent&#125;;</span></span><br><span class="line"><span class="string">endproperty: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">$&#123;6:assert_&#125;$1: assert property ($1)</span></span><br><span class="line"><span class="string">    else `uvm_error(&quot;</span>ASSERT<span class="string">&quot;, $sformatf(&quot;</span>$<span class="number">1</span> failed at %<span class="number">0</span>t<span class="string">&quot;, $time))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_sequence</span></span><br><span class="line"><span class="string">sequence $&#123;1:seq_name&#125;;</span></span><br><span class="line"><span class="string">    $&#123;2:expression&#125;;</span></span><br><span class="line"><span class="string">endsequence: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_implication</span></span><br><span class="line"><span class="string">property $&#123;1:overlap_prop&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;) disable iff ($&#123;3:!rst_n&#125;)</span></span><br><span class="line"><span class="string">    $&#123;4:req&#125; |-&gt; $&#123;5:grant&#125;;  // If req this cycle, grant must be true this cycle</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">property $&#123;6:nonoverlap_prop&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $4 |=&gt; $5;  // If req this cycle, grant must be true next cycle</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_delay</span></span><br><span class="line"><span class="string">// Fixed Delay: ##n</span></span><br><span class="line"><span class="string">property $&#123;1:fixed_delay&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;)</span></span><br><span class="line"><span class="string">    $&#123;3:req&#125; |-&gt; ##$&#123;4:2&#125; $&#123;5:ack&#125;;  // ack exactly 2 cycles after req</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// Range Delay: ##[m:n]</span></span><br><span class="line"><span class="string">property $&#123;6:range_delay&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $3 |-&gt; ##[$&#123;7:1&#125;:$&#123;8:5&#125;] $5;  // ack within 1-5 cycles after req</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// Unbounded Delay: ##[1:$]</span></span><br><span class="line"><span class="string">property $&#123;9:unbounded_delay&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $3 |-&gt; ##[1:$] $5;  // ack eventually after req</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_repetition</span></span><br><span class="line"><span class="string">// Consecutive Repetition: [*n]</span></span><br><span class="line"><span class="string">property $&#123;1:consecutive_rep&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;)</span></span><br><span class="line"><span class="string">    $&#123;3:busy&#125;[*$&#123;4:3&#125;] ##1 $&#123;5:done&#125;;  // busy for exactly 3 cycles, then done</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// Range Repetition: [*m:n]</span></span><br><span class="line"><span class="string">property $&#123;6:range_rep&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $3[*$&#123;7:2&#125;:$&#123;8:5&#125;] ##1 $5;  // busy for 2-5 cycles, then done</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// Goto Repetition: [-&gt;n]</span></span><br><span class="line"><span class="string">property $&#123;9:goto_rep&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $&#123;10:valid&#125;[-&gt;3] ##1 $&#123;11:complete&#125;;  // valid high 3 times (non-consecutive), then complete</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// Non-consecutive Repetition: [=n]</span></span><br><span class="line"><span class="string">property $&#123;12:noncons_rep&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $10[=3];  // valid high 3 times (may be non-consecutive)</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_throughout</span></span><br><span class="line"><span class="string">property $&#123;1:throughout_prop&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;)</span></span><br><span class="line"><span class="string">    $&#123;3:enable&#125; throughout ($&#123;4:req&#125; ##[1:5] $&#123;5:ack&#125;);</span></span><br><span class="line"><span class="string">    // enable must remain high from req until ack</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_advanced</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 1. Request-Acknowledge with Timeout</span></span><br><span class="line"><span class="string">property $&#123;1:req_ack_timeout&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;) disable iff ($&#123;3:!rst_n&#125;)</span></span><br><span class="line"><span class="string">    $&#123;4:req&#125; |-&gt; ##[1:$&#123;5:10&#125;] $&#123;6:ack&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 2. Mutual Exclusion</span></span><br><span class="line"><span class="string">property $&#123;7:mutex&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $&#123;8:sig_a&#125; |-&gt; !$&#123;9:sig_b&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 3. FIFO Full/Empty Relationship</span></span><br><span class="line"><span class="string">property $&#123;10:fifo_full_empty&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    !($&#123;11:full&#125; &amp;&amp; $&#123;12:empty&#125;);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 4. Handshake Protocol</span></span><br><span class="line"><span class="string">property $&#123;13:handshake&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $&#123;14:valid&#125; &amp;&amp; $&#123;15:ready&#125; |=&gt; !$&#123;16:valid&#125; || $&#123;17:new_data&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 5. One-Hot Encoding</span></span><br><span class="line"><span class="string">property $&#123;18:onehot&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $onehot($&#123;19:state&#125;);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_cover</span></span><br><span class="line"><span class="string">property $&#123;1:cover_prop&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;)</span></span><br><span class="line"><span class="string">    $&#123;3:condition&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">cover_$1: cover property ($1)</span></span><br><span class="line"><span class="string">    `uvm_info(&quot;</span>COVER<span class="string">&quot;, $sformatf(&quot;</span>$<span class="number">1</span> covered at %<span class="number">0</span>t<span class="string">&quot;, $time), UVM_MEDIUM)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_assume</span></span><br><span class="line"><span class="string">property $&#123;1:assume_prop&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;)</span></span><br><span class="line"><span class="string">    $&#123;3:input_constraint&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">assume_$1: assume property ($1);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_concurrent</span></span><br><span class="line"><span class="string">$&#123;1:assert_name&#125;: assert property (</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;) disable iff ($&#123;3:!rst_n&#125;)</span></span><br><span class="line"><span class="string">    $&#123;4:property_expression&#125;</span></span><br><span class="line"><span class="string">) else `uvm_error(&quot;</span>ASSERT<span class="string">&quot;, &quot;</span>$<span class="number">1</span> failed<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_immediate</span></span><br><span class="line"><span class="string">assert ($&#123;1:condition&#125;) else `uvm_error(&quot;</span>ASSERT<span class="string">&quot;, &quot;</span>$&#123;<span class="number">2</span>:Assertion failed&#125;<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_system</span></span><br><span class="line"><span class="string">// $rose - Detects 0-&gt;1 transition</span></span><br><span class="line"><span class="string">property $&#123;1:rose_detect&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;)</span></span><br><span class="line"><span class="string">    $rose($&#123;3:signal&#125;) |-&gt; $&#123;4:action&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// $fell - Detects 1-&gt;0 transition</span></span><br><span class="line"><span class="string">property $&#123;5:fell_detect&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $fell($3) |-&gt; $4;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// $stable - Signal unchanged</span></span><br><span class="line"><span class="string">property $&#123;6:stable_check&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $&#123;7:hold&#125; |-&gt; $stable($3);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// $past - Previous value</span></span><br><span class="line"><span class="string">property $&#123;8:past_check&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $&#123;9:valid&#125; |-&gt; $&#123;10:data&#125; == $past($&#123;11:prev_data&#125;);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// $onehot - Exactly one bit high</span></span><br><span class="line"><span class="string">property $&#123;12:onehot_check&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $onehot($&#123;13:state_vector&#125;);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// $onehot0 - At most one bit high</span></span><br><span class="line"><span class="string">property $&#123;14:onehot0_check&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    $onehot0($13);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// $isunknown - Check for X/Z</span></span><br><span class="line"><span class="string">property $&#123;15:unknown_check&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    !$isunknown($3);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_fifo</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 1. No write when full</span></span><br><span class="line"><span class="string">property $&#123;1:no_write_when_full&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;) disable iff ($&#123;3:!rst_n&#125;)</span></span><br><span class="line"><span class="string">    $&#123;4:full&#125; |-&gt; !$&#123;5:wr_en&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$1: assert property ($1);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 2. No read when empty</span></span><br><span class="line"><span class="string">property $&#123;6:no_read_when_empty&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $&#123;7:empty&#125; |-&gt; !$&#123;8:rd_en&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$6: assert property ($6);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 3. Write increments count (when not full)</span></span><br><span class="line"><span class="string">property $&#123;9:write_inc_count&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $5 &amp;&amp; !$4 |=&gt; $&#123;10:count&#125; == $past($10) + 1;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$9: assert property ($9);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 4. Read decrements count (when not empty)</span></span><br><span class="line"><span class="string">property $&#123;11:read_dec_count&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $8 &amp;&amp; !$7 |=&gt; $10 == $past($10) - 1;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$11: assert property ($11);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 5. Full and empty are mutually exclusive</span></span><br><span class="line"><span class="string">property $&#123;12:full_empty_mutex&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2)</span></span><br><span class="line"><span class="string">    !($4 &amp;&amp; $7);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$12: assert property ($12);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet sva_axi</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 1. Valid-Ready Handshake (AXI Rule)</span></span><br><span class="line"><span class="string">property $&#123;1:axi_valid_stable&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $&#123;2:clk&#125;) disable iff ($&#123;3:!rst_n&#125;)</span></span><br><span class="line"><span class="string">    $&#123;4:valid&#125; &amp;&amp; !$&#123;5:ready&#125; |=&gt; $stable($4) &amp;&amp; $stable($&#123;6:data&#125;);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$1: assert property ($1)</span></span><br><span class="line"><span class="string">    else `uvm_error(&quot;</span>AXI<span class="string">&quot;, &quot;</span>VALID/data must remain stable <span class="keyword">until</span> READY<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 2. BVALID follows WLAST and WREADY</span></span><br><span class="line"><span class="string">property $&#123;7:axi_bvalid_after_wlast&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $&#123;8:wlast&#125; &amp;&amp; $&#123;9:wready&#125; |-&gt; ##[1:$&#123;10:16&#125;] $&#123;11:bvalid&#125;;</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$7: assert property ($7);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">// 3. RVALID must not be dependent on RREADY</span></span><br><span class="line"><span class="string">property $&#123;12:axi_rvalid_independent&#125;;</span></span><br><span class="line"><span class="string">    @(posedge $2) disable iff ($3)</span></span><br><span class="line"><span class="string">    $&#123;13:rvalid&#125; |-&gt; $&#123;13:rvalid&#125; throughout (##[0:$] $&#123;14:rready&#125;);</span></span><br><span class="line"><span class="string">endproperty</span></span><br><span class="line"><span class="string">assert_$12: assert property ($12);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># MACROS AND PREPROCESSOR (IEEE 1800-2012 Section 22)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_define</span></span><br><span class="line"><span class="string">\`define $&#123;1:MACRO_NAME&#125;($&#123;2:args&#125;) \\</span></span><br><span class="line"><span class="string">    $&#123;3:macro body&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_stringify</span></span><br><span class="line"><span class="string">\`define $&#123;1:TO_STRING&#125;($&#123;2:x&#125;) \`&quot;</span>$&#123;<span class="number">2</span>&#125;\`<span class="string">&quot;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_concat</span></span><br><span class="line"><span class="string">\`define $&#123;1:CONCAT&#125;($&#123;2:a&#125;, $&#123;3:b&#125;) $&#123;2&#125;\`\`$&#123;3&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_ifdef_block</span></span><br><span class="line"><span class="string">\`ifdef $&#123;1:MACRO_NAME&#125;</span></span><br><span class="line"><span class="string">    $&#123;2:code when defined&#125;</span></span><br><span class="line"><span class="string">\`else</span></span><br><span class="line"><span class="string">    $&#123;3:code when not defined&#125;</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_ifndef_block</span></span><br><span class="line"><span class="string">\`ifndef $&#123;1:MACRO_NAME&#125;</span></span><br><span class="line"><span class="string">    $&#123;2:code when not defined&#125;</span></span><br><span class="line"><span class="string">\`else</span></span><br><span class="line"><span class="string">    $&#123;3:code when defined&#125;</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_undef</span></span><br><span class="line"><span class="string">\`undef $&#123;1:MACRO_NAME&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_line</span></span><br><span class="line"><span class="string">\`line $&#123;1:line_number&#125; &quot;</span>$&#123;<span class="number">2</span>:filename&#125;<span class="string">&quot; $&#123;3:level&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_default</span></span><br><span class="line"><span class="string">\`default_nettype $&#123;1:wire&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_resetall</span></span><br><span class="line"><span class="string">\`resetall</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_celldefine</span></span><br><span class="line"><span class="string">\`celldefine</span></span><br><span class="line"><span class="string">$&#123;1&#125;</span></span><br><span class="line"><span class="string">\`endcelldefine</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_pragma</span></span><br><span class="line"><span class="string">\`pragma $&#123;1:pragma_name&#125; $&#123;2:pragma_value&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_begin_keywords</span></span><br><span class="line"><span class="string">\`begin_keywords &quot;</span>$&#123;<span class="number">1</span>:<span class="number">1800</span>-<span class="number">2012</span>&#125;<span class="string">&quot;</span></span><br><span class="line"><span class="string">$&#123;2&#125;</span></span><br><span class="line"><span class="string">\`end_keywords</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># COMMON UVM MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_info_macro</span></span><br><span class="line"><span class="string">\`uvm_info(&quot;</span>$&#123;<span class="number">1</span>:ID&#125;<span class="string">&quot;, $sformatf(&quot;</span>$&#123;<span class="number">2</span>:Message: %s&#125;<span class="string">&quot;, $&#123;3:arg&#125;), $&#123;4:UVM_MEDIUM&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_warning_macro</span></span><br><span class="line"><span class="string">\`uvm_warning(&quot;</span>$&#123;<span class="number">1</span>:ID&#125;<span class="string">&quot;, $sformatf(&quot;</span>$&#123;<span class="number">2</span>:Message: %s&#125;<span class="string">&quot;, $&#123;3:arg&#125;))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_error_macro</span></span><br><span class="line"><span class="string">\`uvm_error(&quot;</span>$&#123;<span class="number">1</span>:ID&#125;<span class="string">&quot;, $sformatf(&quot;</span>$&#123;<span class="number">2</span>:Message: %s&#125;<span class="string">&quot;, $&#123;3:arg&#125;))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_fatal_macro</span></span><br><span class="line"><span class="string">\`uvm_fatal(&quot;</span>$&#123;<span class="number">1</span>:ID&#125;<span class="string">&quot;, $sformatf(&quot;</span>$&#123;<span class="number">2</span>:Message: %s&#125;<span class="string">&quot;, $&#123;3:arg&#125;))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_do_macro</span></span><br><span class="line"><span class="string">\`uvm_do($&#123;1:sequence_item&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_do_with_macro</span></span><br><span class="line"><span class="string">\`uvm_do_with($&#123;1:sequence_item&#125;, &#123;</span></span><br><span class="line"><span class="string">    $&#123;2:constraints&#125;</span></span><br><span class="line"><span class="string">&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_create_macro</span></span><br><span class="line"><span class="string">\`uvm_create($&#123;1:sequence_item&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_send_macro</span></span><br><span class="line"><span class="string">\`uvm_send($&#123;1:sequence_item&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_rand_send_macro</span></span><br><span class="line"><span class="string">\`uvm_rand_send($&#123;1:sequence_item&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_rand_send_with_macro</span></span><br><span class="line"><span class="string">\`uvm_rand_send_with($&#123;1:sequence_item&#125;, &#123;</span></span><br><span class="line"><span class="string">    $&#123;2:constraints&#125;</span></span><br><span class="line"><span class="string">&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_int</span></span><br><span class="line"><span class="string">\`uvm_field_int($&#123;1:field_name&#125;, $&#123;2:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_object</span></span><br><span class="line"><span class="string">\`uvm_field_object($&#123;1:field_name&#125;, $&#123;2:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_string</span></span><br><span class="line"><span class="string">\`uvm_field_string($&#123;1:field_name&#125;, $&#123;2:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_enum</span></span><br><span class="line"><span class="string">\`uvm_field_enum($&#123;1:enum_type&#125;, $&#123;2:field_name&#125;, $&#123;3:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_array_int</span></span><br><span class="line"><span class="string">\`uvm_field_array_int($&#123;1:field_name&#125;, $&#123;2:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_sarray_int</span></span><br><span class="line"><span class="string">\`uvm_field_sarray_int($&#123;1:field_name&#125;, $&#123;2:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_queue</span></span><br><span class="line"><span class="string">\`uvm_field_queue_$&#123;1:int&#125;($&#123;2:field_name&#125;, $&#123;3:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_field_aa</span></span><br><span class="line"><span class="string">\`uvm_field_aa_$&#123;1:int&#125;_$&#123;2:string&#125;($&#123;3:field_name&#125;, $&#123;4:UVM_DEFAULT&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># COMMON UTILITY MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_min</span></span><br><span class="line"><span class="string">\`define MIN(a, b) (((a) &lt; (b)) ? (a) : (b))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_max</span></span><br><span class="line"><span class="string">\`define MAX(a, b) (((a) &gt; (b)) ? (a) : (b))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_abs</span></span><br><span class="line"><span class="string">\`define ABS(x) (((x) &lt; 0) ? -(x) : (x))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_clamp</span></span><br><span class="line"><span class="string">\`define CLAMP(x, min, max) (((x) &lt; (min)) ? (min) : (((x) &gt; (max)) ? (max) : (x)))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_swap</span></span><br><span class="line"><span class="string">\`define SWAP(a, b, tmp) \\</span></span><br><span class="line"><span class="string">    tmp = a; \\</span></span><br><span class="line"><span class="string">    a = b; \\</span></span><br><span class="line"><span class="string">    b = tmp;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_bit_width</span></span><br><span class="line"><span class="string">\`define BIT_WIDTH(x) ($clog2(x))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_is_power_of_2</span></span><br><span class="line"><span class="string">\`define IS_POWER_OF_2(x) (((x) != 0) &amp;&amp; (((x) &amp; ((x) - 1)) == 0))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_align_up</span></span><br><span class="line"><span class="string">\`define ALIGN_UP(x, align) ((((x) + (align) - 1) / (align)) * (align))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_div_round_up</span></span><br><span class="line"><span class="string">\`define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># VERIFICATION MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_check_fatal</span></span><br><span class="line"><span class="string">\`define CHECK_FATAL(cond, msg) \\</span></span><br><span class="line"><span class="string">    if (!(cond)) begin \\</span></span><br><span class="line"><span class="string">        \$fatal(1, msg); \\</span></span><br><span class="line"><span class="string">    end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_check_error</span></span><br><span class="line"><span class="string">\`define CHECK_ERROR(cond, msg) \\</span></span><br><span class="line"><span class="string">    if (!(cond)) begin \\</span></span><br><span class="line"><span class="string">        \$error(msg); \\</span></span><br><span class="line"><span class="string">    end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_check_warning</span></span><br><span class="line"><span class="string">\`define CHECK_WARNING(cond, msg) \\</span></span><br><span class="line"><span class="string">    if (!(cond)) begin \\</span></span><br><span class="line"><span class="string">        \$warning(msg); \\</span></span><br><span class="line"><span class="string">    end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_assert</span></span><br><span class="line"><span class="string">\`define ASSERT(cond) \\</span></span><br><span class="line"><span class="string">    assert(cond) else \$error(&quot;</span>Assertion failed: \`<span class="string">&quot;cond\`&quot;</span> at %m<span class="string">&quot;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_cover</span></span><br><span class="line"><span class="string">\`define COVER(name, cond) \\</span></span><br><span class="line"><span class="string">    cover property (@(posedge clk) cond) \\</span></span><br><span class="line"><span class="string">        \$display(&quot;</span>Coverage: name hit at %t<span class="string">&quot;, \$time);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># DEBUG MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_debug</span></span><br><span class="line"><span class="string">\`ifdef DEBUG</span></span><br><span class="line"><span class="string">    \`define DEBUG_PRINT(msg) \$display(&quot;</span>[DEBUG] %t: msg<span class="string">&quot;, \$time)</span></span><br><span class="line"><span class="string">\`else</span></span><br><span class="line"><span class="string">    \`define DEBUG_PRINT(msg)</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_verbose</span></span><br><span class="line"><span class="string">\`ifdef VERBOSE</span></span><br><span class="line"><span class="string">    \`define VERBOSE_PRINT(level, msg) \\</span></span><br><span class="line"><span class="string">        if (verbose_level &gt;= level) \$display(&quot;</span>[VERBOSE] msg<span class="string">&quot;)</span></span><br><span class="line"><span class="string">\`else</span></span><br><span class="line"><span class="string">    \`define VERBOSE_PRINT(level, msg)</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_trace</span></span><br><span class="line"><span class="string">\`define TRACE(msg) \$display(&quot;</span>[TRACE] %t %m: msg<span class="string">&quot;, \$time)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_dump_vars</span></span><br><span class="line"><span class="string">\`define DUMP_VARS(var) \\</span></span><br><span class="line"><span class="string">    \$display(&quot;</span>[DUMP] %t %m: \`<span class="string">&quot;var\`&quot;</span> = %<span class="number">0</span>d<span class="string">&quot;, \$time, var)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># REGISTER ACCESS MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_reg_write</span></span><br><span class="line"><span class="string">\`define REG_WRITE(addr, data) \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    reg_addr = addr; \\</span></span><br><span class="line"><span class="string">    reg_wdata = data; \\</span></span><br><span class="line"><span class="string">    reg_wr_en = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    reg_wr_en = 1&#x27;b0;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_reg_read</span></span><br><span class="line"><span class="string">\`define REG_READ(addr, data) \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    reg_addr = addr; \\</span></span><br><span class="line"><span class="string">    reg_rd_en = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    data = reg_rdata; \\</span></span><br><span class="line"><span class="string">    reg_rd_en = 1&#x27;b0;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_reg_field</span></span><br><span class="line"><span class="string">\`define REG_FIELD(reg, msb, lsb) reg[msb:lsb]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_reg_bit</span></span><br><span class="line"><span class="string">\`define REG_BIT(reg, bit) reg[bit]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># TIMING MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_wait_clks</span></span><br><span class="line"><span class="string">\`define WAIT_CLKS(n) \\</span></span><br><span class="line"><span class="string">    repeat(n) @(posedge clk);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_wait_ns</span></span><br><span class="line"><span class="string">\`define WAIT_NS(ns) \\</span></span><br><span class="line"><span class="string">    #(ns * 1ns);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_wait_until</span></span><br><span class="line"><span class="string">\`define WAIT_UNTIL(cond) \\</span></span><br><span class="line"><span class="string">    wait(cond);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_wait_clk_edge</span></span><br><span class="line"><span class="string">\`define WAIT_CLK_EDGE \\</span></span><br><span class="line"><span class="string">    @(posedge clk);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># ARRAY/MEMORY MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_array_sum</span></span><br><span class="line"><span class="string">\`define ARRAY_SUM(arr, size) \\</span></span><br><span class="line"><span class="string">    function int; \\</span></span><br><span class="line"><span class="string">        int sum = 0; \\</span></span><br><span class="line"><span class="string">        for (int i = 0; i &lt; size; i++) \\</span></span><br><span class="line"><span class="string">            sum += arr[i]; \\</span></span><br><span class="line"><span class="string">        return sum; \\</span></span><br><span class="line"><span class="string">    endfunction</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_array_fill</span></span><br><span class="line"><span class="string">\`define ARRAY_FILL(arr, size, val) \\</span></span><br><span class="line"><span class="string">    for (int i = 0; i &lt; size; i++) \\</span></span><br><span class="line"><span class="string">        arr[i] = val;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_array_copy</span></span><br><span class="line"><span class="string">\`define ARRAY_COPY(dst, src, size) \\</span></span><br><span class="line"><span class="string">    for (int i = 0; i &lt; size; i++) \\</span></span><br><span class="line"><span class="string">        dst[i] = src[i];</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># CONDITIONAL COMPILATION MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_synthesis</span></span><br><span class="line"><span class="string">\`ifdef SYNTHESIS</span></span><br><span class="line"><span class="string">    $&#123;1:// Synthesis code&#125;</span></span><br><span class="line"><span class="string">\`else</span></span><br><span class="line"><span class="string">    $&#123;2:// Simulation code&#125;</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_formal</span></span><br><span class="line"><span class="string">\`ifdef FORMAL</span></span><br><span class="line"><span class="string">    $&#123;1:// Formal verification code&#125;</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_coverage</span></span><br><span class="line"><span class="string">\`ifdef COVERAGE</span></span><br><span class="line"><span class="string">    $&#123;1:// Coverage code&#125;</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_simulation</span></span><br><span class="line"><span class="string">\`ifndef SYNTHESIS</span></span><br><span class="line"><span class="string">    $&#123;1:// Simulation-only code&#125;</span></span><br><span class="line"><span class="string">\`endif</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># PARAMETERIZED MACROS (Advanced)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_gen_comparator</span></span><br><span class="line"><span class="string">\`define GEN_COMPARATOR(name, width) \\</span></span><br><span class="line"><span class="string">module name ( \\</span></span><br><span class="line"><span class="string">    input  logic [width-1:0] a, \\</span></span><br><span class="line"><span class="string">    input  logic [width-1:0] b, \\</span></span><br><span class="line"><span class="string">    output logic             eq, \\</span></span><br><span class="line"><span class="string">    output logic             gt, \\</span></span><br><span class="line"><span class="string">    output logic             lt  \\</span></span><br><span class="line"><span class="string">); \\</span></span><br><span class="line"><span class="string">    assign eq = (a == b); \\</span></span><br><span class="line"><span class="string">    assign gt = (a &gt; b); \\</span></span><br><span class="line"><span class="string">    assign lt = (a &lt; b); \\</span></span><br><span class="line"><span class="string">endmodule</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_gen_register</span></span><br><span class="line"><span class="string">\`define GEN_REGISTER(name, width, reset_val) \\</span></span><br><span class="line"><span class="string">always_ff @(posedge clk or negedge rst_n) begin \\</span></span><br><span class="line"><span class="string">    if (!rst_n) \\</span></span><br><span class="line"><span class="string">        name &lt;= reset_val; \\</span></span><br><span class="line"><span class="string">    else if (name``_en) \\</span></span><br><span class="line"><span class="string">        name &lt;= name``_next; \\</span></span><br><span class="line"><span class="string">end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_gen_fifo</span></span><br><span class="line"><span class="string">\`define GEN_FIFO(name, width, depth) \\</span></span><br><span class="line"><span class="string">logic [width-1:0] name``_mem [depth]; \\</span></span><br><span class="line"><span class="string">logic [\$clog2(depth)-1:0] name``_wr_ptr, name``_rd_ptr; \\</span></span><br><span class="line"><span class="string">logic name``_full, name``_empty;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># PROTOCOL-SPECIFIC MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_axi_handshake</span></span><br><span class="line"><span class="string">\`define AXI_HANDSHAKE(valid, ready) \\</span></span><br><span class="line"><span class="string">    (valid &amp;&amp; ready)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_axi_wait</span></span><br><span class="line"><span class="string">\`define AXI_WAIT_HANDSHAKE(valid, ready) \\</span></span><br><span class="line"><span class="string">    do begin \\</span></span><br><span class="line"><span class="string">        @(posedge clk); \\</span></span><br><span class="line"><span class="string">    end while (!(valid &amp;&amp; ready));</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_apb_write</span></span><br><span class="line"><span class="string">\`define APB_WRITE(addr, data) \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    paddr = addr; \\</span></span><br><span class="line"><span class="string">    pwdata = data; \\</span></span><br><span class="line"><span class="string">    pwrite = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    psel = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    penable = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    psel = 1&#x27;b0; \\</span></span><br><span class="line"><span class="string">    penable = 1&#x27;b0;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_apb_read</span></span><br><span class="line"><span class="string">\`define APB_READ(addr, data) \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    paddr = addr; \\</span></span><br><span class="line"><span class="string">    pwrite = 1&#x27;b0; \\</span></span><br><span class="line"><span class="string">    psel = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    penable = 1&#x27;b1; \\</span></span><br><span class="line"><span class="string">    @(posedge clk); \\</span></span><br><span class="line"><span class="string">    data = prdata; \\</span></span><br><span class="line"><span class="string">    psel = 1&#x27;b0; \\</span></span><br><span class="line"><span class="string">    penable = 1&#x27;b0;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># STRING MANIPULATION MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_str_concat</span></span><br><span class="line"><span class="string">\`define STR_CONCAT(a, b) &#123;a, b&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_str_format</span></span><br><span class="line"><span class="string">\`define STR_FORMAT(fmt, args) \\</span></span><br><span class="line"><span class="string">    \$sformatf(fmt, args)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_to_hex</span></span><br><span class="line"><span class="string">\`define TO_HEX(val, width) \\</span></span><br><span class="line"><span class="string">    \$sformatf(&quot;</span><span class="number">0</span>x%<span class="number">0</span>h<span class="string">&quot;, val)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_to_bin</span></span><br><span class="line"><span class="string">\`define TO_BIN(val, width) \\</span></span><br><span class="line"><span class="string">    \$sformatf(&quot;</span>%<span class="number">0</span>b<span class="string">&quot;, val)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># FILE I/O MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_file_open</span></span><br><span class="line"><span class="string">\`define FILE_OPEN(handle, filename, mode) \\</span></span><br><span class="line"><span class="string">    handle = \$fopen(filename, mode); \\</span></span><br><span class="line"><span class="string">    if (!handle) \\</span></span><br><span class="line"><span class="string">        \$fatal(1, &quot;</span>Failed to open file: filename<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_file_write</span></span><br><span class="line"><span class="string">\`define FILE_WRITE(handle, fmt, args) \\</span></span><br><span class="line"><span class="string">    \$fdisplay(handle, fmt, args);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_file_close</span></span><br><span class="line"><span class="string">\`define FILE_CLOSE(handle) \\</span></span><br><span class="line"><span class="string">    \$fclose(handle);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># RANDOM MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_rand_range</span></span><br><span class="line"><span class="string">\`define RAND_RANGE(min, max) \\</span></span><br><span class="line"><span class="string">    (\$urandom_range(max, min))</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_rand_bool</span></span><br><span class="line"><span class="string">\`define RAND_BOOL \\</span></span><br><span class="line"><span class="string">    (\$urandom() &amp; 1)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_rand_choice</span></span><br><span class="line"><span class="string">\`define RAND_CHOICE(arr, size) \\</span></span><br><span class="line"><span class="string">    arr[\$urandom_range(size-1, 0)]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># PERFORMANCE MEASUREMENT MACROS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_perf_start</span></span><br><span class="line"><span class="string">\`define PERF_START(name) \\</span></span><br><span class="line"><span class="string">    realtime name``_start_time = \$realtime;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_perf_end</span></span><br><span class="line"><span class="string">\`define PERF_END(name) \\</span></span><br><span class="line"><span class="string">    \$display(&quot;</span>[PERF] name: %<span class="variable">.2f</span> ns<span class="string">&quot;, \$realtime - name``_start_time);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_cycle_count</span></span><br><span class="line"><span class="string">\`define CYCLE_COUNT_START(name) \\</span></span><br><span class="line"><span class="string">    int name``_cycle_count = 0;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_cycle_count_inc</span></span><br><span class="line"><span class="string">\`define CYCLE_COUNT_INC(name) \\</span></span><br><span class="line"><span class="string">    name``_cycle_count++;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet macro_cycle_count_report</span></span><br><span class="line"><span class="string">\`define CYCLE_COUNT_REPORT(name) \\</span></span><br><span class="line"><span class="string">    \$display(&quot;</span>[CYCLES] name: %<span class="number">0</span>d cycles<span class="string">&quot;, name``_cycle_count);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># ADDITIONAL SYSTEMVERILOG CONSTRUCTS (IEEE 1800-2012)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet checker</span></span><br><span class="line"><span class="string">checker $&#123;1:checker_name&#125; (</span></span><br><span class="line"><span class="string">    $&#123;2:input logic clk&#125;,</span></span><br><span class="line"><span class="string">    $&#123;3:input logic rst_n&#125;</span></span><br><span class="line"><span class="string">);</span></span><br><span class="line"><span class="string">    $&#123;4:// Assertions&#125;</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endchecker: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet let</span></span><br><span class="line"><span class="string">let $&#123;1:name&#125; = $&#123;2:expression&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet expect</span></span><br><span class="line"><span class="string">expect ($&#123;1:property_name&#125;) else $&#123;2:action&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet restrict</span></span><br><span class="line"><span class="string">restrict property ($&#123;1:property_name&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet alias</span></span><br><span class="line"><span class="string">alias $&#123;1:new_name&#125; = $&#123;2:existing_name&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet nettype</span></span><br><span class="line"><span class="string">nettype $&#123;1:data_type&#125; $&#123;2:nettype_name&#125; with $&#123;3:resolution_function&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># INTERFACE AND MODPORT ADVANCED</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet interface_class</span></span><br><span class="line"><span class="string">interface class $&#123;1:interface_name&#125;;</span></span><br><span class="line"><span class="string">    pure virtual function $&#123;2:void&#125; $&#123;3:method&#125;($&#123;4&#125;);</span></span><br><span class="line"><span class="string">endclass: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet implements</span></span><br><span class="line"><span class="string">implements $&#123;1:interface_class_name&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet modport_clocking</span></span><br><span class="line"><span class="string">modport $&#123;1:name&#125; (</span></span><br><span class="line"><span class="string">    clocking $&#123;2:cb&#125;,</span></span><br><span class="line"><span class="string">    $&#123;3:input reset&#125;</span></span><br><span class="line"><span class="string">);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet interface_param</span></span><br><span class="line"><span class="string">interface $&#123;1:`expand(&#x27;%:t:r&#x27;)`&#125; #(</span></span><br><span class="line"><span class="string">    parameter int $&#123;2:WIDTH&#125; = $&#123;3:8&#125;</span></span><br><span class="line"><span class="string">) (</span></span><br><span class="line"><span class="string">    input logic clk,</span></span><br><span class="line"><span class="string">    input logic rst_n</span></span><br><span class="line"><span class="string">);</span></span><br><span class="line"><span class="string">    $&#123;4&#125;</span></span><br><span class="line"><span class="string">endinterface: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># ADVANCED CLASS FEATURES</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern_class</span></span><br><span class="line"><span class="string">extern class $&#123;1:class_name&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet constraint_mode</span></span><br><span class="line"><span class="string">$&#123;1:constraint_name&#125;.constraint_mode($&#123;2:0&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet rand_mode</span></span><br><span class="line"><span class="string">$&#123;1:variable&#125;.rand_mode($&#123;2:0&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet this</span></span><br><span class="line"><span class="string">this.$&#123;1:member&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet super</span></span><br><span class="line"><span class="string">super.$&#123;1:method&#125;($&#123;2&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet new_array</span></span><br><span class="line"><span class="string">$&#123;1:array&#125; = new[$&#123;2:size&#125;];</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet new_copy</span></span><br><span class="line"><span class="string">$&#123;1:object&#125; = new $&#123;2:original&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># PACKAGE IMPORT AND EXPORT</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet import_pkg</span></span><br><span class="line"><span class="string">import $&#123;1:package_name&#125;::$&#123;2:*&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet export_pkg</span></span><br><span class="line"><span class="string">export $&#123;1:package_name&#125;::$&#123;2:*&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet import_item</span></span><br><span class="line"><span class="string">import $&#123;1:package_name&#125;::$&#123;2:item_name&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># VIRTUAL INTERFACES</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet virtual_interface</span></span><br><span class="line"><span class="string">virtual $&#123;1:interface_name&#125; $&#123;2:vif&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet virtual_interface_param</span></span><br><span class="line"><span class="string">virtual $&#123;1:interface_name&#125;#($&#123;2:params&#125;) $&#123;3:vif&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># DPI (Direct Programming Interface)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dpi_import</span></span><br><span class="line"><span class="string">import &quot;</span>DPI-C<span class="string">&quot; function $&#123;1:return_type&#125; $&#123;2:function_name&#125;($&#123;3:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dpi_export</span></span><br><span class="line"><span class="string">export &quot;</span>DPI-C<span class="string">&quot; function $&#123;1:function_name&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dpi_context</span></span><br><span class="line"><span class="string">import &quot;</span>DPI-C<span class="string">&quot; context function $&#123;1:return_type&#125; $&#123;2:function_name&#125;($&#123;3:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dpi_pure</span></span><br><span class="line"><span class="string">import &quot;</span>DPI-C<span class="string">&quot; pure function $&#123;1:return_type&#125; $&#123;2:function_name&#125;($&#123;3:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># PROGRAM BLOCKS (Advanced)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet program_clocking</span></span><br><span class="line"><span class="string">program $&#123;1:`expand(&#x27;%:t:r&#x27;)`&#125; (</span></span><br><span class="line"><span class="string">    $&#123;2:interface_name&#125;.$&#123;3:modport&#125; $&#123;4:port&#125;</span></span><br><span class="line"><span class="string">);</span></span><br><span class="line"><span class="string">    clocking $&#123;5:cb&#125; @(posedge $&#123;4&#125;.clk);</span></span><br><span class="line"><span class="string">        $&#123;6&#125;</span></span><br><span class="line"><span class="string">    endclocking</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    initial begin</span></span><br><span class="line"><span class="string">        $&#123;0&#125;</span></span><br><span class="line"><span class="string">    end</span></span><br><span class="line"><span class="string">endprogram: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># CONFIG AND BIND</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet config</span></span><br><span class="line"><span class="string">config $&#123;1:config_name&#125;;</span></span><br><span class="line"><span class="string">    design $&#123;2:top_module&#125;;</span></span><br><span class="line"><span class="string">    $&#123;3&#125;</span></span><br><span class="line"><span class="string">endconfig: $1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet cell_config</span></span><br><span class="line"><span class="string">cell $&#123;1:instance_path&#125; use $&#123;2:library&#125;.$&#123;3:cell&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet instance_config</span></span><br><span class="line"><span class="string">instance $&#123;1:instance_path&#125; use $&#123;2:configuration&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># SPECIFY BLOCKS (Timing)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet specify</span></span><br><span class="line"><span class="string">specify</span></span><br><span class="line"><span class="string">    specparam $&#123;1:tPD&#125; = $&#123;2:10&#125;;</span></span><br><span class="line"><span class="string">    ($&#123;3:input&#125; =&gt; $&#123;4:output&#125;) = $1;</span></span><br><span class="line"><span class="string">endspecify</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet setuphold</span></span><br><span class="line"><span class="string">\$setuphold(posedge $&#123;1:clk&#125;, $&#123;2:data&#125;, $&#123;3:setup_time&#125;, $&#123;4:hold_time&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet width_check</span></span><br><span class="line"><span class="string">\$width(posedge $&#123;1:signal&#125;, $&#123;2:min_width&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet period_check</span></span><br><span class="line"><span class="string">\$period(posedge $&#123;1:clk&#125;, $&#123;2:min_period&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UNIQUE, PRIORITY, UNIQUE0</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet unique_if</span></span><br><span class="line"><span class="string">unique if ($&#123;1:condition&#125;) begin</span></span><br><span class="line"><span class="string">    $&#123;2&#125;</span></span><br><span class="line"><span class="string">end else if ($&#123;3:condition&#125;) begin</span></span><br><span class="line"><span class="string">    $&#123;4&#125;</span></span><br><span class="line"><span class="string">end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet priority_if</span></span><br><span class="line"><span class="string">priority if ($&#123;1:condition&#125;) begin</span></span><br><span class="line"><span class="string">    $&#123;2&#125;</span></span><br><span class="line"><span class="string">end else if ($&#123;3:condition&#125;) begin</span></span><br><span class="line"><span class="string">    $&#123;4&#125;</span></span><br><span class="line"><span class="string">end</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet unique0_case</span></span><br><span class="line"><span class="string">unique0 case ($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string">    $&#123;2:value&#125;: $&#123;3&#125;</span></span><br><span class="line"><span class="string">    default: $&#123;4&#125;</span></span><br><span class="line"><span class="string">endcase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># STREAMING OPERATORS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet stream_pack</span></span><br><span class="line"><span class="string">&#123;&lt;&lt;&#123;$&#123;1:data&#125;&#125;&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet stream_unpack</span></span><br><span class="line"><span class="string">&#123;&gt;&gt;&#123;$&#123;1:data&#125;&#125;&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet stream_slice</span></span><br><span class="line"><span class="string">&#123;&lt;&lt;$&#123;1:8&#125;&#123;$&#123;2:data&#125;&#125;&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># ARRAY METHODS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_size</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.size()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_delete</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.delete($&#123;2:index&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_exists</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.exists($&#123;2:index&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_first</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.first($&#123;2:index&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_last</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.last($&#123;2:index&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_next</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.next($&#123;2:index&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_prev</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.prev($&#123;2:index&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_find</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.find($&#123;2:item&#125;) with ($&#123;3:item&#125; == $&#123;4:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_find_index</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.find_index with ($&#123;2:item&#125; == $&#123;3:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_find_first</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.find_first with ($&#123;2:item&#125; &gt; $&#123;3:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_min</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.min()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_max</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.max()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_sum</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.sum()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_product</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.product()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_and</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.and()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_or</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.or()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_xor</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.xor()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_unique</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.unique()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_sort</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.sort()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_rsort</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.rsort()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_reverse</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.reverse()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet array_shuffle</span></span><br><span class="line"><span class="string">$&#123;1:array&#125;.shuffle()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># STRING METHODS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_len</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.len()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_getc</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.getc($&#123;2:index&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_putc</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.putc($&#123;2:index&#125;, $&#123;3:char&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_toupper</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.toupper()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_tolower</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.tolower()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_compare</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.compare($&#123;2:str2&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_icompare</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.icompare($&#123;2:str2&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_substr</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.substr($&#123;2:start&#125;, $&#123;3:end&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_atoi</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.atoi()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_atohex</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.atohex()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_atooct</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.atooct()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_atobin</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.atobin()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_atoreal</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.atoreal()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_itoa</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.itoa($&#123;2:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_hextoa</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.hextoa($&#123;2:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_octtoa</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.octtoa($&#123;2:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_bintoa</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.bintoa($&#123;2:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet string_realtoa</span></span><br><span class="line"><span class="string">$&#123;1:str&#125;.realtoa($&#123;2:value&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># PROCESS CONTROL</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet process_self</span></span><br><span class="line"><span class="string">process::self()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet process_status</span></span><br><span class="line"><span class="string">$&#123;1:proc&#125;.status()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet process_kill</span></span><br><span class="line"><span class="string">$&#123;1:proc&#125;.kill()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet process_await</span></span><br><span class="line"><span class="string">$&#123;1:proc&#125;.await()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet process_suspend</span></span><br><span class="line"><span class="string">$&#123;1:proc&#125;.suspend()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet process_resume</span></span><br><span class="line"><span class="string">$&#123;1:proc&#125;.resume()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># REFINEMENT (IEEE 1800-2012)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet global_clocking</span></span><br><span class="line"><span class="string">global clocking $&#123;1:cb&#125; @(posedge $&#123;2:clk&#125;);</span></span><br><span class="line"><span class="string">    $&#123;3&#125;</span></span><br><span class="line"><span class="string">endclocking</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet default_clocking</span></span><br><span class="line"><span class="string">default clocking $&#123;1:cb&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet default_disable</span></span><br><span class="line"><span class="string">default disable iff $&#123;1:reset&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># COVERAGE OPTIONS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet covergroup_option</span></span><br><span class="line"><span class="string">option.name = &quot;</span>$&#123;<span class="number">1</span>:name&#125;<span class="string">&quot;;</span></span><br><span class="line"><span class="string">option.weight = $&#123;2:1&#125;;</span></span><br><span class="line"><span class="string">option.goal = $&#123;3:100&#125;;</span></span><br><span class="line"><span class="string">option.comment = &quot;</span>$&#123;<span class="number">4</span>:comment&#125;<span class="string">&quot;;</span></span><br><span class="line"><span class="string">option.at_least = $&#123;5:1&#125;;</span></span><br><span class="line"><span class="string">option.auto_bin_max = $&#123;6:64&#125;;</span></span><br><span class="line"><span class="string">option.per_instance = $&#123;7:0&#125;;</span></span><br><span class="line"><span class="string">option.get_inst_coverage = $&#123;8:0&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet coverpoint_option</span></span><br><span class="line"><span class="string">option.weight = $&#123;1:1&#125;;</span></span><br><span class="line"><span class="string">option.goal = $&#123;2:100&#125;;</span></span><br><span class="line"><span class="string">option.comment = &quot;</span>$&#123;<span class="number">3</span>:comment&#125;<span class="string">&quot;;</span></span><br><span class="line"><span class="string">option.at_least = $&#123;4:1&#125;;</span></span><br><span class="line"><span class="string">option.auto_bin_max = $&#123;5:64&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># WILDCARD BINS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet bins_wildcard</span></span><br><span class="line"><span class="string">wildcard bins $&#123;1:name&#125; = &#123;$&#123;2:4&#x27;b10??&#125;&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet bins_transition</span></span><br><span class="line"><span class="string">bins $&#123;1:name&#125; = ($&#123;2:val1&#125; =&gt; $&#123;3:val2&#125; =&gt; $&#123;4:val3&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet bins_sequence</span></span><br><span class="line"><span class="string">bins $&#123;1:name&#125; = ($&#123;2:val1&#125;[*$&#123;3:2&#125;] =&gt; $&#123;4:val2&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># RANDSEQUENCE</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet randsequence</span></span><br><span class="line"><span class="string">randsequence($&#123;1:production&#125;)</span></span><br><span class="line"><span class="string">    $&#123;1&#125;: $&#123;2:item1&#125; $&#123;3:| item2&#125;;</span></span><br><span class="line"><span class="string">    $2: $&#123;4:/* actions */&#125;;</span></span><br><span class="line"><span class="string">    $3: $&#123;5:/* actions */&#125;;</span></span><br><span class="line"><span class="string">endsequence</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># SOFT CONSTRAINTS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet soft_constraint</span></span><br><span class="line"><span class="string">constraint $&#123;1:name&#125;_c &#123;</span></span><br><span class="line"><span class="string">    soft $&#123;2:variable&#125; == $&#123;3:value&#125;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># DIST CONSTRAINTS (Advanced)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dist_weight</span></span><br><span class="line"><span class="string">$&#123;1:variable&#125; dist &#123;</span></span><br><span class="line"><span class="string">    $&#123;2:value1&#125; := $&#123;3:weight1&#125;,</span></span><br><span class="line"><span class="string">    $&#123;4:value2&#125; := $&#123;5:weight2&#125;,</span></span><br><span class="line"><span class="string">    [$&#123;6:min&#125;:$&#123;7:max&#125;] := $&#123;8:weight3&#125;</span></span><br><span class="line"><span class="string">&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dist_equal</span></span><br><span class="line"><span class="string">$&#123;1:variable&#125; dist &#123;</span></span><br><span class="line"><span class="string">    $&#123;2:value1&#125;, $&#123;3:value2&#125;, $&#123;4:value3&#125;</span></span><br><span class="line"><span class="string">&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># IMPLICATION CONSTRAINTS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet constraint_implication</span></span><br><span class="line"><span class="string">constraint $&#123;1:name&#125;_c &#123;</span></span><br><span class="line"><span class="string">    $&#123;2:condition&#125; -&gt; $&#123;3:constraint&#125;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet constraint_if</span></span><br><span class="line"><span class="string">constraint $&#123;1:name&#125;_c &#123;</span></span><br><span class="line"><span class="string">    if ($&#123;2:condition&#125;)</span></span><br><span class="line"><span class="string">        $&#123;3:constraint1&#125;</span></span><br><span class="line"><span class="string">    else</span></span><br><span class="line"><span class="string">        $&#123;4:constraint2&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># FOREACH IN CONSTRAINTS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet constraint_foreach</span></span><br><span class="line"><span class="string">constraint $&#123;1:name&#125;_c &#123;</span></span><br><span class="line"><span class="string">    foreach ($&#123;2:array&#125;[$&#123;3:i&#125;])</span></span><br><span class="line"><span class="string">        $&#123;2&#125;[$3] $&#123;4:inside &#123;[0:10]&#125;&#125;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UNIQUE IN CONSTRAINTS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet constraint_unique</span></span><br><span class="line"><span class="string">constraint $&#123;1:name&#125;_c &#123;</span></span><br><span class="line"><span class="string">    unique &#123;$&#123;2:var1&#125;, $&#123;3:var2&#125;, $&#123;4:var3&#125;&#125;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># INLINE RANDOMIZATION</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet randomize_inline</span></span><br><span class="line"><span class="string">std::randomize($&#123;1:variable&#125;) with &#123;</span></span><br><span class="line"><span class="string">    $1 $&#123;2:inside &#123;[0:100]&#125;&#125;;</span></span><br><span class="line"><span class="string">&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># CROSS COVERAGE (Advanced)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet cross_binsof</span></span><br><span class="line"><span class="string">$&#123;1:name&#125;_cross: cross $&#123;2:cp1&#125;, $&#123;3:cp2&#125; &#123;</span></span><br><span class="line"><span class="string">    ignore_bins $&#123;4:ignore&#125; = binsof($&#123;2&#125;) intersect &#123;$&#123;5:values&#125;&#125;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet cross_iff</span></span><br><span class="line"><span class="string">$&#123;1:name&#125;_cross: cross $&#123;2:cp1&#125;, $&#123;3:cp2&#125; iff ($&#123;4:condition&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># SYSTEM FUNCTIONS (Additional)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet countones</span></span><br><span class="line"><span class="string">\$countones($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet countbits</span></span><br><span class="line"><span class="string">\$countbits($&#123;1:expression&#125;, $&#123;2:&#x27;1&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet onehot</span></span><br><span class="line"><span class="string">\$onehot($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet onehot0</span></span><br><span class="line"><span class="string">\$onehot0($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet isunknown</span></span><br><span class="line"><span class="string">\$isunknown($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet bits</span></span><br><span class="line"><span class="string">\$bits($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet typename</span></span><br><span class="line"><span class="string">\$typename($&#123;1:expression&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet high</span></span><br><span class="line"><span class="string">\$high($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet low</span></span><br><span class="line"><span class="string">\$low($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet left</span></span><br><span class="line"><span class="string">\$left($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet right</span></span><br><span class="line"><span class="string">\$right($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet increment</span></span><br><span class="line"><span class="string">\$increment($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet size</span></span><br><span class="line"><span class="string">\$size($&#123;1:array&#125;, $&#123;2:dimension&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet dimensions</span></span><br><span class="line"><span class="string">\$dimensions($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet unpacked_dimensions</span></span><br><span class="line"><span class="string">\$unpacked_dimensions($&#123;1:array&#125;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># SEVERITY SYSTEM TASKS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet fatal</span></span><br><span class="line"><span class="string">\$fatal($&#123;1:finish_number&#125;, &quot;</span>$&#123;<span class="number">2</span>:message&#125;<span class="string">&quot;, $&#123;3:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet error</span></span><br><span class="line"><span class="string">\$error(&quot;</span>$&#123;<span class="number">1</span>:message&#125;<span class="string">&quot;, $&#123;2:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet warning</span></span><br><span class="line"><span class="string">\$warning(&quot;</span>$&#123;<span class="number">1</span>:message&#125;<span class="string">&quot;, $&#123;2:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet info</span></span><br><span class="line"><span class="string">\$info(&quot;</span>$&#123;<span class="number">1</span>:message&#125;<span class="string">&quot;, $&#123;2:args&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UVM HDL ACCESS (uvm_hdl_read/force/deposit)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_read</span></span><br><span class="line"><span class="string">uvm_hdl_read(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;, $&#123;2:value&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_force</span></span><br><span class="line"><span class="string">uvm_hdl_force(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;, $&#123;2:value&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_release</span></span><br><span class="line"><span class="string">uvm_hdl_release(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_deposit</span></span><br><span class="line"><span class="string">uvm_hdl_deposit(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;, $&#123;2:value&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_check_path</span></span><br><span class="line"><span class="string">uvm_hdl_check_path(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_read_string</span></span><br><span class="line"><span class="string">uvm_hdl_read_string(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;, $&#123;2:str_value&#125;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_force_string</span></span><br><span class="line"><span class="string">uvm_hdl_force_string(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;, &quot;</span>$&#123;<span class="number">2</span>:str_value&#125;<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet uvm_hdl_deposit_string</span></span><br><span class="line"><span class="string">uvm_hdl_deposit_string(&quot;</span>$&#123;<span class="number">1</span>:hdl_path&#125;<span class="string">&quot;, &quot;</span>$&#123;<span class="number">2</span>:str_value&#125;<span class="string">&quot;);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UVM PHASE METHODS</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet build_phase</span></span><br><span class="line"><span class="string">function void build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.build_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: build_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_build_phase</span></span><br><span class="line"><span class="string">function void pre_build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_build_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: pre_build_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_build_phase</span></span><br><span class="line"><span class="string">function void post_build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_build_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: post_build_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet connect_phase</span></span><br><span class="line"><span class="string">function void connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.connect_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: connect_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_connect_phase</span></span><br><span class="line"><span class="string">function void pre_connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_connect_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: pre_connect_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_connect_phase</span></span><br><span class="line"><span class="string">function void post_connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_connect_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: post_connect_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet end_of_elaboration_phase</span></span><br><span class="line"><span class="string">function void end_of_elaboration_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.end_of_elaboration_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: end_of_elaboration_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_end_of_elaboration_phase</span></span><br><span class="line"><span class="string">function void pre_end_of_elaboration_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_end_of_elaboration_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: pre_end_of_elaboration_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_end_of_elaboration_phase</span></span><br><span class="line"><span class="string">function void post_end_of_elaboration_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_end_of_elaboration_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: post_end_of_elaboration_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet start_of_simulation_phase</span></span><br><span class="line"><span class="string">function void start_of_simulation_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.start_of_simulation_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: start_of_simulation_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_start_of_simulation_phase</span></span><br><span class="line"><span class="string">function void pre_start_of_simulation_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_start_of_simulation_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: pre_start_of_simulation_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_start_of_simulation_phase</span></span><br><span class="line"><span class="string">function void post_start_of_simulation_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_start_of_simulation_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: post_start_of_simulation_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet run_phase</span></span><br><span class="line"><span class="string">task run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.run_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: run_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_run_phase</span></span><br><span class="line"><span class="string">function void pre_run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_run_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: pre_run_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_run_phase</span></span><br><span class="line"><span class="string">function void post_run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_run_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: post_run_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extract_phase</span></span><br><span class="line"><span class="string">// Collect simulation data, statistics, etc.</span></span><br><span class="line"><span class="string">function void extract_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.extract_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: extract_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet check_phase</span></span><br><span class="line"><span class="string">function void check_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.check_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: check_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet report_phase</span></span><br><span class="line"><span class="string">function void report_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.report_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: report_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet final_phase</span></span><br><span class="line"><span class="string">function void final_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.final_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endfunction: final_phase</span></span><br><span class="line"><span class="string"># Runtime Phases (12-phase triads)</span></span><br><span class="line"><span class="string">snippet pre_reset_phase</span></span><br><span class="line"><span class="string">task pre_reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_reset_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: pre_reset_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet reset_phase</span></span><br><span class="line"><span class="string">task reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.reset_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: reset_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_reset_phase</span></span><br><span class="line"><span class="string">task post_reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_reset_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: post_reset_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_configure_phase</span></span><br><span class="line"><span class="string">task pre_configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_configure_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: pre_configure_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet configure_phase</span></span><br><span class="line"><span class="string">task configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.configure_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: configure_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_configure_phase</span></span><br><span class="line"><span class="string">task post_configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_configure_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: post_configure_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_main_phase</span></span><br><span class="line"><span class="string">task pre_main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_main_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: pre_main_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet main_phase</span></span><br><span class="line"><span class="string">task main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.main_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: main_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_main_phase</span></span><br><span class="line"><span class="string">task post_main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_main_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: post_main_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet pre_shutdown_phase</span></span><br><span class="line"><span class="string">task pre_shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.pre_shutdown_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: pre_shutdown_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet shutdown_phase</span></span><br><span class="line"><span class="string">task shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.shutdown_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: shutdown_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet post_shutdown_phase</span></span><br><span class="line"><span class="string">task post_shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    super.post_shutdown_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;1&#125;</span></span><br><span class="line"><span class="string">endtask: post_shutdown_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UVM PHASE METHODS (Optional Inline Completions)</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase build_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: create/configure components; do NOT call super</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // sqr = my_sequencer::type_id::create(&quot;</span>sqr<span class="string">&quot;, this);</span></span><br><span class="line"><span class="string">    // drv = my_driver::type_id::create(&quot;</span>drv<span class="string">&quot;, this);</span></span><br><span class="line"><span class="string">    // mon = my_monitor::type_id::create(&quot;</span>mon<span class="string">&quot;, this);</span></span><br><span class="line"><span class="string">    // if (!uvm_config_db#(virtual my_if)::get(this, &quot;</span><span class="string">&quot;, &quot;</span>vif<span class="string">&quot;, vif))</span></span><br><span class="line"><span class="string">    //   `uvm_fatal(get_name(), &quot;</span>Virtual <span class="keyword">interface</span> <span class="keyword">not</span> found<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    // uvm_config_db#(uvm_object_wrapper)::set(this, &quot;</span>sqr<span class="variable">.main_phase</span><span class="string">&quot;, &quot;</span>default_sequence<span class="string">&quot;, my_sequence::type_id::get());</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: build_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase connect_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: connect TLM ports/exports and analysis ports</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // drv.seq_item_port.connect(sqr.seq_item_export);</span></span><br><span class="line"><span class="string">    // mon.ap.connect(sb.analysis_export);</span></span><br><span class="line"><span class="string">    // if (is_active == UVM_ACTIVE) drv.seq_item_port.connect(sqr.seq_item_export);</span></span><br><span class="line"><span class="string">    super.connect_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: connect_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase end_of_elaboration_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::end_of_elaboration_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: validate topology, print configuration</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // uvm_root::get().print_topology();</span></span><br><span class="line"><span class="string">    // uvm_config_db#(type)::dump();</span></span><br><span class="line"><span class="string">    super.end_of_elaboration_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: end_of_elaboration_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase start_of_simulation_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::start_of_simulation_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: pre-sim setup/logging</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // `uvm_info(get_name(), &quot;</span>Start of simulation<span class="string">&quot;, UVM_LOW)</span></span><br><span class="line"><span class="string">    // uvm_report_server rs = uvm_report_server::get_server();</span></span><br><span class="line"><span class="string">    // rs.set_max_quit_count(0);</span></span><br><span class="line"><span class="string">    // uvm_root::get().set_timeout(1ms, 0);</span></span><br><span class="line"><span class="string">    // `uvm_info(get_name(), $sformatf(&quot;</span>Seed=%<span class="number">0</span>d<span class="string">&quot;, $get_initial_random_seed()), UVM_LOW)</span></span><br><span class="line"><span class="string">    super.start_of_simulation_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: start_of_simulation_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase run_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: time-based behavior, objections, stimulus</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // phase.raise_objection(this);</span></span><br><span class="line"><span class="string">    // fork</span></span><br><span class="line"><span class="string">    //   begin `uvm_do(req) end</span></span><br><span class="line"><span class="string">    //   begin monitor.run(); end</span></span><br><span class="line"><span class="string">    // join</span></span><br><span class="line"><span class="string">    // phase.drop_objection(this);</span></span><br><span class="line"><span class="string">    // `uvm_info(get_name(), &quot;</span>Run phase active<span class="string">&quot;, UVM_LOW)</span></span><br><span class="line"><span class="string">    super.run_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: run_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase extract_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::extract_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: collect data/statistics</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // sb.extract();</span></span><br><span class="line"><span class="string">    // void&#x27;($display(&quot;</span>Extracting stats<span class="string">&quot;));</span></span><br><span class="line"><span class="string">    // cov_db.sample();</span></span><br><span class="line"><span class="string">    super.extract_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: extract_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase check_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::check_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: validate results (scoreboards, assertions)</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // if (!sb.is_pass()) `uvm_error(get_name(), &quot;</span>Scoreboard failed<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    // `uvm_info(get_name(), $sformatf(&quot;</span>Coverage=%<span class="number">0</span><span class="variable">.2f</span><span class="string">&quot;, cov.get_inst_coverage()), UVM_LOW)</span></span><br><span class="line"><span class="string">    super.check_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: check_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase report_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::report_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: emit reports/summaries</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // `uvm_info(get_name(), sb.format_results(), UVM_NONE)</span></span><br><span class="line"><span class="string">    // void&#x27;($display(&quot;</span>Report: %s<span class="string">&quot;, get_full_name()));</span></span><br><span class="line"><span class="string">    // uvm_report_server::get_server().summarize();</span></span><br><span class="line"><span class="string">    super.report_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: report_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase final_phase</span></span><br><span class="line"><span class="string">function void `expand(&#x27;%:t:r&#x27;)`::final_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">    // Purpose: cleanup resources, finalize logs</span></span><br><span class="line"><span class="string">    // Example:</span></span><br><span class="line"><span class="string">    // void&#x27;($display(&quot;</span>Finalizing<span class="string">&quot;));</span></span><br><span class="line"><span class="string">    // if ($test$plusargs(&quot;</span>auto_finish<span class="string">&quot;)) $finish;</span></span><br><span class="line"><span class="string">    super.final_phase(phase);</span></span><br><span class="line"><span class="string">    $&#123;0&#125;</span></span><br><span class="line"><span class="string">endfunction: final_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># Runtime Inline (two-choice) snippets</span></span><br><span class="line"><span class="string">snippet phase pre_reset_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::pre_reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: prepare for reset (stop drivers, clear state)</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// drv.stop(); mon.clear(); sb.reset();</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: pre_reset_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase reset_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: apply and hold reset</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// vif.rst_n &lt;= 0; repeat (5) @(posedge vif.clk); vif.rst_n &lt;= 1;</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: reset_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase post_reset_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::post_reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: resume after reset (re-enable components)</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// drv.start(); mon.enable();</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: post_reset_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase pre_configure_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::pre_configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: set configuration knobs</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// uvm_config_db#(int)::set(this, &quot;</span>sqr<span class="string">&quot;, &quot;</span>burst_len<span class="string">&quot;, 16);</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: pre_configure_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase configure_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: program DUT registers/modes via sequences</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// cfg_seq seq = cfg_seq::type_id::create(&quot;</span>cfg_seq<span class="string">&quot;);</span></span><br><span class="line"><span class="string">// seq.start(sqr);</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: configure_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase post_configure_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::post_configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: validate configuration completion</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// `uvm_info(get_name(), &quot;</span>Configuration completed<span class="string">&quot;, UVM_LOW)</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: post_configure_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase pre_main_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::pre_main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: prepare for main stimulus (seed, counters)</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// void&#x27;($urandom(seed));</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: pre_main_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase main_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: primary stimulus with objections</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// phase.raise_objection(this);</span></span><br><span class="line"><span class="string">// my_seq seq = my_seq::type_id::create(&quot;</span>seq<span class="string">&quot;);</span></span><br><span class="line"><span class="string">// seq.start(sqr);</span></span><br><span class="line"><span class="string">// phase.drop_objection(this);</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: main_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase post_main_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::post_main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: cleanup after main stimulus</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// drv.flush(); sb.summarize();</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: post_main_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase pre_shutdown_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::pre_shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: prepare for shutdown (stop new transactions)</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// drv.stop_issuance();</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: pre_shutdown_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase shutdown_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: drain pipelines and flush outstanding items</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// phase.raise_objection(this);</span></span><br><span class="line"><span class="string">// wait_for_drain();</span></span><br><span class="line"><span class="string">// phase.drop_objection(this);</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: shutdown_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet phase post_shutdown_phase</span></span><br><span class="line"><span class="string">task `expand(&#x27;%:t:r&#x27;)`::post_shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">// Purpose: finalize run (close files, release handles)</span></span><br><span class="line"><span class="string">// Example:</span></span><br><span class="line"><span class="string">// `uvm_info(get_name(), &quot;</span>Shutdown complete<span class="string">&quot;, UVM_LOW)</span></span><br><span class="line"><span class="string">$&#123;0&#125;</span></span><br><span class="line"><span class="string">endtask: post_shutdown_phase</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"># UVM PHASE METHODS (Extern Completions)</span></span><br><span class="line"><span class="string"># Usage per phase (declarations only; implement outside the class):</span></span><br><span class="line"><span class="string"># - build_phase: extern function; implementation creates/configures components.</span></span><br><span class="line"><span class="string"># - connect_phase: extern function; implementation connects TLM/analysis ports.</span></span><br><span class="line"><span class="string"># - start_of_simulation_phase: extern function; implementation performs pre-sim setup.</span></span><br><span class="line"><span class="string"># Examples:</span></span><br><span class="line"><span class="string"># - Class declaration:</span></span><br><span class="line"><span class="string">#   class my_component extends uvm_component;</span></span><br><span class="line"><span class="string">#     extern function void build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">#     extern function void connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">#     extern task run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">#   endclass</span></span><br><span class="line"><span class="string"># - Implementation outside class:</span></span><br><span class="line"><span class="string">#   function void my_component::build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">#     mon = my_monitor::type_id::create(&quot;</span>mon<span class="string">&quot;, this);</span></span><br><span class="line"><span class="string">#   endfunction</span></span><br><span class="line"><span class="string">#   function void my_component::connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">#     drv.seq_item_port.connect(sqr.seq_item_export);</span></span><br><span class="line"><span class="string">#   endfunction</span></span><br><span class="line"><span class="string">#   task my_component::run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string">#     phase.raise_objection(this);</span></span><br><span class="line"><span class="string">#     // stimulus</span></span><br><span class="line"><span class="string">#     phase.drop_objection(this);</span></span><br><span class="line"><span class="string">#   endtask</span></span><br><span class="line"><span class="string"># - run_phase: extern task; implementation drives stimulus and objections.</span></span><br><span class="line"><span class="string"># - extract/check/report/final: extern functions; implementations collect, check,</span></span><br><span class="line"><span class="string">#   report, and cleanup.</span></span><br><span class="line"><span class="string"># =============================================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern build_phase</span></span><br><span class="line"><span class="string">extern function void build_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern connect_phase</span></span><br><span class="line"><span class="string">extern function void connect_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern end_of_elaboration_phase</span></span><br><span class="line"><span class="string">extern function void end_of_elaboration_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern start_of_simulation_phase</span></span><br><span class="line"><span class="string">extern function void start_of_simulation_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern run_phase</span></span><br><span class="line"><span class="string">extern task run_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern extract_phase</span></span><br><span class="line"><span class="string">extern function void extract_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern check_phase</span></span><br><span class="line"><span class="string">extern function void check_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern report_phase</span></span><br><span class="line"><span class="string">extern function void report_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern final_phase</span></span><br><span class="line"><span class="string">extern function void final_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern pre_reset_phase</span></span><br><span class="line"><span class="string">extern task pre_reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern reset_phase</span></span><br><span class="line"><span class="string">extern task reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern post_reset_phase</span></span><br><span class="line"><span class="string">extern task post_reset_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern pre_configure_phase</span></span><br><span class="line"><span class="string">extern task pre_configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern configure_phase</span></span><br><span class="line"><span class="string">extern task configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern post_configure_phase</span></span><br><span class="line"><span class="string">extern task post_configure_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern pre_main_phase</span></span><br><span class="line"><span class="string">extern task pre_main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern main_phase</span></span><br><span class="line"><span class="string">extern task main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern post_main_phase</span></span><br><span class="line"><span class="string">extern task post_main_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern pre_shutdown_phase</span></span><br><span class="line"><span class="string">extern task pre_shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern shutdown_phase</span></span><br><span class="line"><span class="string">extern task shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">snippet extern post_shutdown_phase</span></span><br><span class="line"><span class="string">extern task post_shutdown_phase(uvm_phase phase);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">#######</span></span><br><span class="line"><span class="string">snippet uvm_objection</span></span><br><span class="line"><span class="string">    phase.raise_objection(this);</span></span><br><span class="line"><span class="string">    \`uvm_info($&#123;1:get_full_name()&#125;,&quot;</span>$&#123;<span class="number">2</span>:main_phase&#125; started, objection raised.<span class="string">&quot;, $&#123;3:UVM_NONE&#125;)</span></span><br><span class="line"><span class="string">    $0</span></span><br><span class="line"><span class="string">    phase.drop_objection(this);</span></span><br><span class="line"><span class="string">    uvm_info($1, &quot;</span>$<span class="number">2</span> finished, objection dropped <span class="string">&quot;, $3)</span></span><br><span class="line"><span class="string">snippet objection</span></span><br><span class="line"><span class="string">    phase.raise_objection(this);</span></span><br><span class="line"><span class="string">    \`uvm_info($&#123;1:get_full_name()&#125;,&quot;</span>$&#123;<span class="number">2</span>:main_phase&#125; started, objection raised.<span class="string">&quot;, $&#123;3:UVM_NONE&#125;)</span></span><br><span class="line"><span class="string">    $0</span></span><br><span class="line"><span class="string">    phase.drop_objection(this);</span></span><br><span class="line"><span class="string">    uvm_info($1, &quot;</span>$<span class="number">2</span> finished, objection dropped <span class="string">&quot;, $3)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br></pre></td></tr></table></figure></details>]]></content>
    
    
      
      
    <summary type="html">&lt;details&gt;
&lt;summary&gt;点击查看代码&lt;/summary&gt;

&lt;figure class=&quot;highlight verilog&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;sp</summary>
      
    
    
    
    <category term="工具" scheme="https://sqlmaps.com/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://sqlmaps.com/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="开发环境" scheme="https://sqlmaps.com/tags/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/"/>
    
  </entry>
  
  <entry>
    <title>UVM 与 SystemVerilog</title>
    <link href="https://sqlmaps.com/2026/03/03/UVM%E4%B8%8ESystemVerilog/"/>
    <id>https://sqlmaps.com/2026/03/03/UVM%E4%B8%8ESystemVerilog/</id>
    <published>2026-03-03T00:16:00.000Z</published>
    <updated>2026-10-17T20:13:37.242Z</updated>
    
    <content type="html"><![CDATA[<h2 id="verilog-面向对象编程基础"><a href="#verilog-面向对象编程基础" class="headerlink" title="verilog 面向对象编程基础"></a>verilog 面向对象编程基础</h2><p>本节汇总 verilog（SV）面向对象编程（OOP）的核心概念，面向 UVM 学习或工程使用的入门读者。</p><blockquote><p>说明：本文代码片段相互独立，便于单独阅读与复制。</p></blockquote><h3 id="1-动物类与对象"><a href="#1-动物类与对象" class="headerlink" title="1. 动物类与对象"></a>1. 动物类与对象</h3><ul><li><code>class</code> 用来定义类，<code>new()</code> 用来创建对象。</li><li>类变量保存“句柄”，对象实例分配在堆上。</li></ul><pre><code class="highlight mermaid">flowchart TD    H1[&quot;栈区 句柄 c1&quot;] --&gt;|指向| O1[&quot;堆区 对象 Cat#1&quot;]    H2[&quot;栈区 句柄 c2&quot;] --&gt;|指向| O2[&quot;堆区 对象 Cat#2&quot;]    O1 --&gt;|动态类型| C[&quot;类 Cat&quot;]    O2 --&gt;|动态类型| C    C --&gt;|继承自| B[&quot;类 Animal&quot;]    B --&gt; M1[&quot;方法 eat&quot;]    C --&gt; M2[&quot;重写 eat&quot;]</code></pre><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">string</span> name;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;Animal&quot;</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.name</span> = name;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;Cat&quot;</span>);</span><br><span class="line"><span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats fish&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">Cat c1; <span class="comment">// 句柄</span></span><br><span class="line">Cat c2;</span><br><span class="line"></span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">c1 = <span class="keyword">new</span>(<span class="string">&quot;Mimi&quot;</span>);</span><br><span class="line">c2 = <span class="keyword">new</span>(<span class="string">&quot;Lulu&quot;</span>);</span><br><span class="line">c1<span class="variable">.eat</span>();</span><br><span class="line">c2<span class="variable">.eat</span>();</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h3 id="2-成员：属性与方法"><a href="#2-成员：属性与方法" class="headerlink" title="2. 成员：属性与方法"></a>2. 成员：属性与方法</h3><ul><li>属性：类中的变量。</li><li>方法：<code>function</code> 或 <code>task</code>，可访问类属性。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">int</span> age;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal eats&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">string</span> color;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="3-构造函数与-this"><a href="#3-构造函数与-this" class="headerlink" title="3. 构造函数与 this"></a>3. 构造函数与 <code>this</code></h3><ul><li>构造函数名字固定为 <code>new</code>。</li><li><code>this</code> 指向当前对象，避免名字冲突。</li></ul><pre><code class="highlight mermaid">flowchart TD    H[&quot;栈区 句柄 c&quot;] --&gt;|指向| O[&quot;堆区 对象 Cat&quot;]    O --&gt;|动态类型| C[&quot;类 Cat&quot;]    C --&gt; N[&quot;构造函数 new&quot;]    C --&gt; F[&quot;字段 age&quot;]    O --&gt;|this 指向自身| T[&quot;this&quot;]    T --&gt;|写入 age| F</code></pre><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">string</span> name;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;Animal&quot;</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.name</span> = name;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">int</span> age;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;Cat&quot;</span>, <span class="keyword">int</span> age = <span class="number">1</span>);</span><br><span class="line"><span class="keyword">super</span><span class="variable">.new</span>(name);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.age</span> = age;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats fish&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="4-继承与重写"><a href="#4-继承与重写" class="headerlink" title="4. 继承与重写"></a>4. 继承与重写</h3><ul><li>子类 <code>extends</code> 父类（Cat 继承 Animal）。</li><li>可重写父类方法，必要时调用 <code>super</code>。</li></ul><pre><code class="highlight mermaid">flowchart TD    H[&quot;栈区 句柄 h: Animal&quot;] --&gt;|指向| O[&quot;堆区 对象: Cat&quot;]    O --&gt;|动态类型| C[&quot;子类: Cat&quot;]    O --&gt;|继承自| B[&quot;父类: Animal&quot;]    C --&gt; M[&quot;子类方法: eat&quot;]    M --&gt;|调用 super.eat| S[&quot;父类方法: eat&quot;]</code></pre><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal eats&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="keyword">super</span><span class="variable">.eat</span>();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="5-多态与虚方法（详细）"><a href="#5-多态与虚方法（详细）" class="headerlink" title="5. 多态与虚方法（详细）"></a>5. 多态与虚方法（详细）</h3><p>多态的核心是“父类句柄指向子类对象”，方法的实际执行版本由运行时对象类型决定。</p><h4 id="5-x-父类句柄指向子类实例对象分析"><a href="#5-x-父类句柄指向子类实例对象分析" class="headerlink" title="5.x 父类句柄指向子类实例对象分析"></a>5.x 父类句柄指向子类实例对象分析</h4><p><strong>核心要点</strong></p><ul><li>句柄类型决定“可访问的接口范围”，对象真实类型决定“实际执行的实现”。</li><li>只有父类方法声明为 <code>virtual</code>，才能在子类中动态绑定。</li><li>父类句柄无法直接访问子类新增成员（除非进行类型转换）。</li></ul><p><strong>典型示例</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">string</span> name;</span><br><span class="line"><span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">string</span> toy;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats fish&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">Animal h; <span class="comment">// 父动物类句柄</span></span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">h = <span class="keyword">new</span> Cat();</span><br><span class="line">h<span class="variable">.name</span> = <span class="string">&quot;Mimi&quot;</span>;</span><br><span class="line"><span class="comment">// h.toy = &quot;ball&quot;; // 编译错误: 父动物类句柄不可见子猫类字段</span></span><br><span class="line">h<span class="variable">.eat</span>(); <span class="comment">// 动态绑定，执行 Cat.eat()</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p><strong>必要时的类型转换</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Cat m;</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">$cast</span>(m, h)) <span class="keyword">begin</span></span><br><span class="line">m<span class="variable">.toy</span> = <span class="string">&quot;ball&quot;</span>; <span class="comment">// 转换成功后访问子类字段</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><pre><code class="highlight mermaid">flowchart TD    H[&quot;父类句柄 h: Animal&quot;] --&gt;|$cast| M[&quot;子类句柄 m: Cat&quot;]    H --&gt;|失败| F[&quot;转换失败&quot;]    M --&gt;|成功| U[&quot;可访问 Cat 专有成员&quot;]</code></pre><p><strong>$cast 转换示例（Dog）</strong></p><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">string</span> name;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">new</span>(<span class="keyword">string</span> name = <span class="string">&quot;Generic&quot;</span>);</span><br><span class="line"><span class="keyword">this</span><span class="variable">.name</span> = name;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Dog <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> fetch();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Dog fetches&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">Animal animal = <span class="keyword">new</span>(<span class="string">&quot;Generic&quot;</span>);</span><br><span class="line">Dog    dog;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 危险！可能运行时错误</span></span><br><span class="line"><span class="comment">// dog = animal;  // 编译错误</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 正确做法</span></span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">$cast</span>(dog, animal)) <span class="keyword">begin</span></span><br><span class="line">dog<span class="variable">.fetch</span>();</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span></span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Not a Dog instance&quot;</span>);</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><pre><code class="highlight mermaid">flowchart TD    H[&quot;栈区 父动物类句柄 Animal&quot;] --&gt;|指向| O[&quot;堆区 对象 Cat&quot;]    O --&gt;|动态类型| C[&quot;子类 Cat&quot;]    H --&gt;|调用 eat| R[&quot;运行时绑定&quot;]    R --&gt; E[&quot;执行 Cat.eat&quot;]</code></pre><pre><code class="highlight mermaid">flowchart LR    H1[&quot;栈区 父动物类句柄 a1&quot;] --&gt;|指向| O1[&quot;堆区 对象 Cat&quot;]    H2[&quot;栈区 子猫类句柄 c1&quot;] --&gt;|指向| O1</code></pre><pre><code class="highlight mermaid">flowchart LR    H1[&quot;栈区 子猫类句柄 c&quot;] --&gt;|new| O1[&quot;堆区 对象 Cat&quot;]    H2[&quot;栈区 父动物类句柄 a&quot;] --&gt;|赋值指向| O1    H3[&quot;栈区 父动物类句柄 b&quot;] --&gt;|new| O2[&quot;堆区 对象 Animal&quot;]    O1 --&gt; R1[&quot;a.eat 触发子猫类 eat&quot;]    O2 --&gt; R2[&quot;b.eat 触发父动物类 eat&quot;]</code></pre><h4 id="5-1-基本多态示例"><a href="#5-1-基本多态示例" class="headerlink" title="5.1 基本多态示例"></a>5.1 基本多态示例</h4><ul><li>父类方法需要 <code>virtual</code>，才能在子类中实现动态绑定。</li><li>子类方法签名必须一致（参数、返回值匹配）。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Animal a;</span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">a = <span class="keyword">new</span> Cat();</span><br><span class="line">a<span class="variable">.eat</span>(); <span class="comment">// 动态绑定，执行 Cat.eat()</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h4 id="5-2-多态调用链与-super"><a href="#5-2-多态调用链与-super" class="headerlink" title="5.2 多态调用链与 super"></a>5.2 多态调用链与 <code>super</code></h4><ul><li>子类可以调用 <code>super</code> 保留父类行为，再追加特性。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal starts eating&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="keyword">super</span><span class="variable">.eat</span>();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h4 id="5-3-多态数组：统一管理不同子类"><a href="#5-3-多态数组：统一管理不同子类" class="headerlink" title="5.3 多态数组：统一管理不同子类"></a>5.3 多态数组：统一管理不同子类</h4><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal eats&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Kitten <span class="keyword">extends</span> Cat;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Kitten eats small fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">Animal zoo[$];</span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">zoo<span class="variable">.push_back</span>(<span class="keyword">new</span> Cat());</span><br><span class="line">zoo<span class="variable">.push_back</span>(<span class="keyword">new</span> Kitten());</span><br><span class="line"><span class="keyword">foreach</span> (zoo[i]) <span class="keyword">begin</span></span><br><span class="line">zoo[i]<span class="variable">.eat</span>(); <span class="comment">// 根据实际对象类型执行</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h4 id="5-4-动态绑定-vs-静态绑定"><a href="#5-4-动态绑定-vs-静态绑定" class="headerlink" title="5.4 动态绑定 vs 静态绑定"></a>5.4 动态绑定 vs 静态绑定</h4><ul><li>动态绑定：<code>virtual</code> + 父类句柄，运行时根据对象真实类型选择实现。</li><li>静态绑定：子类句柄直接调用，编译期就确定目标实现。</li></ul><p><strong>用途与场景</strong></p><ul><li>动态绑定适合“统一接口 + 不同实现”的场景，例如 UVM 中 driver&#x2F;monitor 的基类句柄统一调度不同协议实现。</li><li>静态绑定适合“已知具体类型”的场景，例如调试&#x2F;性能路径中直接调用子类方法，逻辑清晰、开销更低。</li></ul><p><strong>对比示例</strong></p><pre><code class="highlight mermaid">flowchart LR    D1[&quot;动态绑定: 父动物类句柄 a&quot;] --&gt;|指向| O1[&quot;堆区 对象 Cat&quot;]    D1 --&gt;|调用 eat| R1[&quot;运行时绑定&quot;]    R1 --&gt; E1[&quot;执行 Cat.eat&quot;]    S1[&quot;静态绑定: 子猫类句柄 c&quot;] --&gt;|指向| O2[&quot;堆区 对象 Cat&quot;]    S1 --&gt;|调用 eat| E2[&quot;编译期确定: Cat.eat&quot;]</code></pre><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Animal a;</span><br><span class="line">Cat c;</span><br><span class="line"></span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line"><span class="comment">// 动态绑定：父类句柄指向子类对象</span></span><br><span class="line">a = <span class="keyword">new</span> Cat();</span><br><span class="line">a<span class="variable">.eat</span>(); <span class="comment">// 运行时决定，实际调用 Cat.eat()</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 静态绑定：子类句柄直接调用</span></span><br><span class="line">c = <span class="keyword">new</span>();</span><br><span class="line">c<span class="variable">.eat</span>(); <span class="comment">// 编译期确定调用 Cat.eat()</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h4 id="5-5-多态常见注意点"><a href="#5-5-多态常见注意点" class="headerlink" title="5.5 多态常见注意点"></a>5.5 多态常见注意点</h4><ul><li>父类方法未声明 <code>virtual</code> 时，子类同名方法不会多态触发。</li><li>方法签名不一致会导致“隐藏”而非“重写”。</li><li>多态配合抽象类与纯虚方法更清晰地约束接口。</li></ul><h4 id="5-6-父类方法非-virtual-的情况"><a href="#5-6-父类方法非-virtual-的情况" class="headerlink" title="5.6 父类方法非 virtual 的情况"></a>5.6 父类方法非 <code>virtual</code> 的情况</h4><p><strong>现象</strong></p><ul><li>父类方法不是 <code>virtual</code> 时，父类句柄调用会固定到父类实现。</li><li>子类同名方法只是“隐藏”，不会触发多态。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal eats&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">Animal a;</span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">a = <span class="keyword">new</span> Cat();</span><br><span class="line">a<span class="variable">.eat</span>(); <span class="comment">// 仍然执行 Animal.eat()</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p><strong>如何实现多态</strong></p><ul><li>把父类方法声明为 <code>virtual</code>。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal eats&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line">Animal a;</span><br><span class="line"><span class="keyword">initial</span> <span class="keyword">begin</span></span><br><span class="line">a = <span class="keyword">new</span> Cat();</span><br><span class="line">a<span class="variable">.eat</span>(); <span class="comment">// 动态绑定，执行 Cat.eat()</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h3 id="6-抽象类与纯虚方法"><a href="#6-抽象类与纯虚方法" class="headerlink" title="6. 抽象类与纯虚方法"></a>6. 抽象类与纯虚方法</h3><ul><li>抽象类不能直接 <code>new</code>。</li><li>纯虚方法必须由子类实现。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">virtual</span> <span class="keyword">class</span> AnimalBase;</span><br><span class="line"><span class="keyword">pure</span> <span class="keyword">virtual</span> <span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> AnimalBase;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="7-访问控制：local-protected"><a href="#7-访问控制：local-protected" class="headerlink" title="7. 访问控制：local &#x2F; protected"></a>7. 访问控制：<code>local</code> &#x2F; <code>protected</code></h3><ul><li><code>local</code>：仅类内部可见（子类也不可见）。</li><li><code>protected</code>：类内部与子类可见。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">local</span> <span class="keyword">int</span> secret;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">int</span> age;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Animal eats&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;Cat eats fish&quot;</span>);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="8-句柄赋值与对象拷贝"><a href="#8-句柄赋值与对象拷贝" class="headerlink" title="8. 句柄赋值与对象拷贝"></a>8. 句柄赋值与对象拷贝</h3><ul><li>句柄赋值只复制“指针”，不是对象内容。</li><li>需要深拷贝时自定义 <code>copy()</code>。</li></ul><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal;</span><br><span class="line"><span class="keyword">string</span> name;</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Cat <span class="keyword">extends</span> Animal;</span><br><span class="line"><span class="keyword">string</span> color;</span><br><span class="line"><span class="keyword">function</span> Cat copy();</span><br><span class="line">Cat c = <span class="keyword">new</span>();</span><br><span class="line">c<span class="variable">.name</span> = <span class="keyword">this</span><span class="variable">.name</span>;</span><br><span class="line">c<span class="variable">.color</span> = <span class="keyword">this</span><span class="variable">.color</span>;</span><br><span class="line"><span class="keyword">return</span> c;</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> eat();</span><br><span class="line"><span class="built_in">$display</span>(<span class="string">&quot;%s eats fish&quot;</span>, name);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure><h3 id="9-参数化类"><a href="#9-参数化类" class="headerlink" title="9. 参数化类"></a>9. 参数化类</h3><figure class="highlight verilog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> CatCage <span class="variable">#(type T = Cat)</span>;</span><br><span class="line">T q[$];</span><br><span class="line"><span class="keyword">function</span> <span class="keyword">void</span> push(T v);</span><br><span class="line">q<span class="variable">.push_back</span>(v);</span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">endclass</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;verilog-面向对象编程基础&quot;&gt;&lt;a href=&quot;#verilog-面向对象编程基础&quot; class=&quot;headerlink&quot; title=&quot;verilog 面向对象编程基础&quot;&gt;&lt;/a&gt;verilog 面向对象编程基础&lt;/h2&gt;&lt;p&gt;本节汇总 verilog（S</summary>
      
    
    
    
    <category term="SystemVerilog" scheme="https://sqlmaps.com/categories/SystemVerilog/"/>
    
    
    <category term="芯片验证" scheme="https://sqlmaps.com/tags/%E8%8A%AF%E7%89%87%E9%AA%8C%E8%AF%81/"/>
    
    <category term="SystemVerilog" scheme="https://sqlmaps.com/tags/SystemVerilog/"/>
    
  </entry>
  
</feed>
