尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

SystemVerilog双向信号建模:从tranif1到rtranif0的完整指南

发布时间:2026/9/28 14:18:32

资讯中心
01
ARTICLE

SystemVerilog双向信号建模:从tranif1到rtranif0的完整指南

SystemVerilog双向信号建模:从tranif1到rtranif0的完整指南
做数字IC验证这些年我在双向信号上栽过的跟头比在UVM环境上踩的坑还要多。记得有一次做I2C从机验证仿真波形里SCL和SDA总线上莫名其妙出现毛刺数据被莫名其妙拉低排查了整整两天最后发现是inout端口没有正确建模导通逻辑——我一直在用连续赋值驱动双向端口却忽略了SystemVerilog里专门用来处理双向传输的开关原语。这个问题可能很多刚接触SystemVerilog的人都会遇到写声明的时候知道用inout写驱动的时候却完全不知道该用哪条语句。这里直接给结论真正适合双向信号建模的是tranif1和rtranif0这一族晶体管开关原语。这篇内容我会从底层机制讲起手把手带你写一个完整可仿真的示例并结合bind语法和队列来做信号监视把我在实际仿真中踩过的坑一并梳理清楚。无论是做IC设计、验证还是刚入门的学生这篇都能帮你少走不少弯路。1. 双向信号传输的底层机制与常见误区1.1 一根net上为什么会有争执多驱动强度决议机制说到双向信号必须先理解一个基础概念在SystemVerilog里一根wire上可以同时挂多个驱动源。这和软件编程里的变量赋值完全不同——软件里一个变量只能被一个地方赋值硬件里一根物理连线却天然可以接多个输出。平时写RTL时你可能不太会注意这个问题因为大部分内部信号确实是单驱动的但一到了总线、IO、存储接口这些场景多驱动就成了常态。多驱动带来一个关键问题当两个驱动同时向一根线输出不同值时最终这根线显示什么SystemVerilog通过信号强度决议机制来回答这个问题。每个驱动器在驱动net时除了带数值0、1、z还带一个强度属性。强度等级从高到低排列supply strong pull large weak medium small hiZ。当多个驱动冲突时强度高的胜出强度相同但数值不同时结果变成未知x。举个例子一个MOS管的上拉网络用pull强度驱动1一个普通门电路的输出用strong强度驱动0那么最终net上的值就是0因为strong比pull高一级。这个机制放在单向信号场景时几乎不会引起注意但放到双向信号场景它就是我们判断总线数据到底归谁说了算的底层依据。很多双向仿真波形异常追根溯源都是强度决议的结果不符合预期。1.2 tran原语家族SystemVerilog留给门级建模的开关工具箱既然知道了net上存在多驱动强度决议那么如何建模开关SystemVerilog在语言层面提供了六种开关原语用来描述MOS晶体管级别的导通行为。这六种分别是原语控制端电阻特性导通条件tran无理想始终导通tranif1有理想控制端为1时导通tranif0有理想控制端为0时导通rtran无带电阻始终导通rtranif1有带电阻控制端为1时导通rtranif0有带电阻控制端为0时导通带r前缀的rtran、rtranif1、rtranif0在导通时会对信号强度做一次衰减用来模拟真实MOS管导通时的电阻效应不带r的是理想开关导通时信号强度不损失。tran无控制端常用来做强制短接tranif1和tranif0带控制端是双向可控开关的核心rtranif0则是带电阻且低电平导通的反向开关在某些总线隔离场景下非常有用。这里要注意的是这些原语源于Verilog时代的门级建模SystemVerilog完全继承了它们并且在仿真器里得到支持。我们平时写抽象级RTL时很少直接提到它们但在IO建模、总线仲裁建模、门级网表仿真中它们是绕不开的核心元件。文章标题里把从tranif1到rtranif0作为完整指南的主线其实就是在讲清楚这套开关建模工具的应用全貌。1.3 常见误区把inout端口当成自动双向我见过太多次这样的写法module bidirectional_gpio ( inout wire data_bus, input logic dir, input logic data_out ); assign data_bus dir ? data_out : 1bz; endmodule这个写法本身没有错但很多人搞混了它在表达什么。inout只是告诉编译器该端口是双向的具体什么时候驱动、什么时候释放仍然需要逻辑来保证。assign语句里用条件表达式实现了三态驱动——dir为1时把data_out灌到总线上dir为0时输出高阻z。这是数据流向的控制不等于端口自动双向。更关键的区别在于三态驱动解决的是单向输出但可释放问题而tran原语解决的是两侧都可以主动驱动同一根线的问题。举个例子I2C的SDA引脚主机和从机都可能拉低它所以它不是一端输出一端输入的简单三态关系而是两端都能驱动的真双向关系。用assign做三态建模当然也可以但它写起来更像在描述驱动器的行为用tranif1则是在描述物理开关本身的导通特性尤其在门级仿真精度要求高的时候这种底层建模的价值就体现出来了。所以在开始写示例之前先把概念摆正inout是端口方向声明tran原语是双向导通的结构描述两者配合起来才构成完整的双向传输建模体系。2. tranif1与rtranif0的核心差异与应用边界2.1 控制逻辑相反的两个开关if1与if0的语义先看最直接的区别tranif1在控制端为1时开关导通tranif0在控制端为0时开关导通。命名里的1和0就是控制电平这个理解起来不难。但放在具体工程场景里控制电平的选择往往不是随意定的。通常我们在设计IO接口时使能信号默认高有效所以tranif1很自然地匹配使能即导通的直觉。而tranif0则适合用低电平使能的总线隔离场景。比如某些存储芯片的片选信号是低有效和这个低有效控制信号配合的开关自然应该用tranif0如果手头只有高有效的控制信号但硬件上电时序要求开关默认导通、仅在特定时间段断开这时候也用tranif0更顺手因为控制端为0时导通意味着控制信号为0的默认态下开关就是通的省去了一级反相逻辑。在RTL仿真层面这个选择影响的是控制逻辑的简洁性和故障概率。控制信号是高有效还是低有效在没有原语时都需要在行为级代码里自己判断有了tranif1和tranif0就可以直接把控制信号接上去不需要额外翻转这在门级网表仿真里能省不少排查时间。2.2 rtran的电阻效应强度衰减如何改变总线上的话语权带r前缀的原语核心差异是导通时有电阻效应反映到SystemVerilog信号强度体系里就是强度衰减。具体来说经过rtran族原语导通后信号强度会从当前级别衰减一级。这里的衰减一级在不同仿真器里可能有微小的处理差异但主流的理解是strong驱动的信号经过rtran后变成pull强度pull变成weakweak变成small。也就是说物理上接了一个带电阻的开关后信号驱动能力变弱在多驱动竞争时话语权下降一级。这在实际工程中非常关键。想象一个双向总线主机端用tranif1理想开关连接强驱动信号从机端用rtranif0带电阻开关连接弱驱动信号。当两边同时驱动且数值相反时主机的信号强度更高总线最终呈现主机的值。这正是很多真实总线的仲裁逻辑——主机拥有优先控制权。如果两边都用tranif1强度相等且数值冲突时结果变成x仿真就崩了。因此用rtran族来模拟从机侧较弱的驱动能力不只是为了建模精度更是为了让多驱动竞争时的强度决议可预测。2.3 选型逻辑什么时候用tranif1什么时候用rtranif0总结一下我的选型经验供你直接参考。遵循这条判断链大多数场景都能快速锁定原语先看导通控制是否需要可控。不需要控制、只是强制短接选tran需要控制再往后分。再看控制电平。高电平导通选tranif1低电平导通选tranif0。后看是否需要模拟导通电阻。需要强度衰减、模拟真实工艺把原语换成带r前缀的rtran、rtranif1或rtranif0。最后看方向语义。这里有个容易忽略的点tran族原语本身是不区分方向的两个端口完全对称导通时信号可以从任意一侧流向另一侧。所谓双向传输的意思就是仿真器在导通瞬间自动按强度决议规则决定数据实际流向而不需要我们在代码里指定方向。举个例子我要给一个GPIO建模输入侧接引脚、内部有上拉输出侧接寄存器数据控制逻辑希望高电平使能输出、同时模拟IO驱动能力弱一些的情况那么rtranif1就是最合适的选择。如果是一个纯数字的片上总线隔离开关不关心强度衰减那直接用tranif1就够了因为带电阻反而会引入不必要的强度损失。rtranif0则适合那些低有效控制的模拟IO路径——比如音频编解码器里的模拟开关控制信号很多就是低电平导通的设计。3. 从零搭建一个可仿真的双向传输示例3.1 先定需求我们要模拟的场景为了不纸上谈兵我设计一个完整的示例一个简化的双向数据总线两个设备挂在同一根data_bus上。设备A为主控通过tranif1控制自身数据是否能送上总线设备B为从设备通过rtranif0建模控制端低电平导通并且带电阻效应模拟从设备驱动能力较弱。另外加一根方向控制线来切换数据流方向。从功能上讲这个结构很像I2C或者SPI这类半双工总线的雏形。代码设计目标有三个第一验证tranif1在高使能时能把数据正确送到总线上第二验证rtranif0在低使能时能导通且强度衰减后主机数据依然能覆盖从机数据第三验证双方同时释放时总线恢复高阻态。下面逐步写代码。3.2 顶层设计模块接口与内部连线先定义顶层模块的接口。这里要说清楚双向端口必须声明为net类型wire不能是logic。很多人在这里摔过跟头因为logic类型是不允许被多驱动或者连接到inout方向的。在SystemVerilog里inout端口声明的本质是net类型连接。// 顶层模块双向总线测试平台 module top ( inout wire data_bus, input logic clk, input logic rst_n ); // 设备A的数据线与控制线 logic a_data; logic a_en; // 设备B的数据线与控制线低有效 logic b_data; logic b_nen; // 设备A使用tranif1高电平导通 tranif1 u_tran_a (data_bus, a_data, a_en); // 设备B使用rtranif0低电平导通带电阻衰减 rtranif0 u_rtran_b (data_bus, b_data, b_nen); // 后续逻辑激励或者简单寄存器逻辑 // ... endmodule注意tranif1实例化的语法第一个端口接总线wire第二个端口接设备内部驱动信号第三个端口是控制端。两个数据端口是对称的顺序不影响功能。3.3 设备侧建模数据源与方向控制的配合接下来给设备A和设备B添加实际驱动逻辑。为了让示例可仿真我用一个简单的状态机让两个设备交替驱动总线。设备A在使能期间把内部寄存器值送上总线设备B在另一个时间段接管总线。// 设备A驱动逻辑 always_ff (posedge clk or negedge rst_n) begin if (!rst_n) begin a_en 1b0; a_data 1b0; end else begin // 仿真激励轮流让两个设备驱动 if (bus_owner 2b01) begin a_en 1b1; a_data counter_a; end else begin a_en 1b0; a_data 1b0; end end end // 设备B驱动逻辑低有效使能 always_ff (posedge clk or negedge rst_n) begin if (!rst_n) begin b_nen 1b1; // 复位时处于释放状态 b_data 1b0; end else begin if (bus_owner 2b10) begin b_nen 1b0; // 低有效使能导通 b_data counter_b; end else begin b_nen 1b1; b_data 1b0; end end end这段逻辑的关键在于设备B使能是低有效所以复位时b_nen要拉高释放总线需要驱动时b_nen拉低。很多人在rtranif0上出错都是因为习惯了tranif1的高有效思维把低有效控制端当成高有效来拉结果总线一直处于断开状态。3.4 测试平台激励生成与总线状态采样有了设计模块还不够仿真必须有testbench来驱动激励。这里我把测试平台写成SystemVerilog的program块在时钟沿驱动激励信号通过采样总线值来检查功能正确性。program automatic test_tb; timeunit 1ns; timeprecision 1ps; logic clk 0; logic rst_n 0; wire data_bus; // 时钟生成 initial begin forever #5 clk ~clk; end // 复位与激励 initial begin (negedge rst_n); (posedge clk); rst_n 1; // 先让设备A驱动总线 bus_owner 2b01; repeat(10) (posedge clk); // 让设备B驱动总线 bus_owner 2b10; repeat(10) (posedge clk); // 双方释放 bus_owner 2b00; repeat(5) (posedge clk); $finish; end // 总线波形跟踪 initial begin $monitor(time%0t bus%b owner%b\n, $time, data_bus, bus_owner); end top u_top (.data_bus(data_bus), .clk(clk), .rst_n(rst_n)); endprogram这里注意program块和module的调度区域不同在program里用阻塞赋值驱动时序逻辑时需要格外小心最好通过接口或者虚拟接口来连接。更稳妥的做法是直接在testbench模块里用always块生成激励尤其在双向信号仿真时program块和design的采样竞争会带来不确定性。3.5 总线竞争仿真强度决议如何呈现把上述代码放到仿真器里跑你会看到这样的现象阶段一设备A使能时data_bus a_data稳定输出。阶段二设备A释放、设备B使能时data_bus b_data但因为经过rtranif0衰减如果此时A还在驱动强信号A的信号会覆盖B。阶段三双方都释放时data_bus z。如果设备A和设备B都在驱动且数值相反tranif1是理想开关强度不减rtranif0衰减一级最终总线显示设备A的数值。如果两边用的都是tranif1且数值相反总线会出现不定态x并且这个x状态会通过导通的原语传播出去导致连接在这根net上的所有接收器都收到x。这就是为什么在总线竞争场景中必须刻意使用不同强度的开关来避免x态扩散。3.6 企业级仿真环境的补充说明如果你用的工具是VCS、Questa或者Xceliumtran原语都是直接支持的。但如果你用的是Verilator要注意它对tran原语的支持比较有限因为Verilator主要面向2态快速仿真tran原语涉及4态和双向连接语义不是它的强项。这种情况下可以用行为级的三态门模型替代——也就是用assign语句加高阻z输出这是当前综合流程里唯一可综合的方案。4. 进阶用bind语法和队列把双向信号监视起来4.1 为什么直接force双向信号不靠谱在调试双向总线的过程中很多验证工程师会尝试用force命令直接把总线值强制成某个固定值用来绕过驱动冲突的问题。但在双向信号上这是非常危险的操作。force会直接覆盖net上所有驱动源的强度决议结果导致原本的多驱动竞争信息丢失。更糟糕的是如果你在testbench里force了总线值又忘了release后续所有驱动源的行为都会被掩盖排错排到天荒地老也找不到问题。正确的调试方式不是强行改变总线行为而是监视总线上已经发生的事件。SystemVerilog提供了bind语法可以把验证用的monitor模块绑定到设计模块上不需要修改RTL代码就能采样内部信号。这个能力对双向信号调试特别有价值。4.2 bind一个总线监控器到DUT的inout端口下面我用一个具体的例子来演示bind的用法。假设我对top模块里的data_bus和内部驱动信号都感兴趣想在总线每次发生变化时记录下当时的驱动状态。// 总线监控模块 module bus_monitor; time last_time; logic [1:0] last_owner; always (top.data_bus) begin last_time $time; last_owner top.bus_owner; $display([%0t] data_bus change: bus%b owner%b a_en%b b_nen%b, $time, top.data_bus, top.bus_owner, top.u_tran_a.a_en, top.u_rtran_b.b_nen); end // 监视信号强度变化 always (top.a_en, top.b_nen) begin if ($time ! last_time) begin $display([%0t] enable toggle: a_en%b b_nen%b, $time, top.a_en, top.b_nen); end end endmodule // bind到顶层模块 bind top bus_monitor u_bus_monitor();bind之后这个monitor就像生长在top模块内部一样可以直接引用top的层次信号。关键是bind不会改变原模块的连接关系也不会被综合工具翻译成额外逻辑它只存在于仿真环境中。在验证双向总线时这个手段能让你实时追踪到哪一端在什么时刻改变了驱动状态这比事后翻波形高效得多。要注意的是bind模块里引用设计信号必须走层次路径。如果你bind到的是top那么引用top内部的信号可以直接写信号名但如果要从外部bind一个模块到多层以下的设计路径就要写全否则编译时会报找不到信号。4.3 用队列缓存总线历史事务快速定位驱动冲突时间点监视到总线事件只是第一步更高级的用法是把这些事件缓存下来形成事务队列方便事后分析。SystemVerilog的队列类型在这个场景下非常好用。队列的优势在于它像动态数组一样可以随时push和pop而且不需要声明固定大小非常适合做历史事务缓冲。我习惯的做法是定义一个结构体把每次总线变化的时间戳、总线值、各设备使能状态都记录下来push到队列尾部当队列长度超过预设值时从头pop丢弃。typedef struct packed { time ts; logic [7:0] bus_data; logic [1:0] owner; logic a_en; logic b_nen; } bus_mon_t; bus_mon_t bus_mon_queue[$]; always (top.data_bus) begin bus_mon_t entry; entry.ts $time; entry.bus_data top.data_bus; entry.owner top.bus_owner; entry.a_en top.u_tran_a.a_en; entry.b_nen top.u_rtran_b.b_nen; if (bus_mon_queue.size() 1024) void(bus_mon_queue.pop_front()); bus_mon_queue.push_back(entry); end跑完仿真后你可以遍历bus_mon_queue按时间戳排序很容易就定位到哪一时刻总线值进入了x态或者z态以及当时是哪一端在驱动。我在实际调试I2C从机的总线冲突问题时就是靠这个队列定位到主机和从机同时在驱动SDA导致总线被锁死的时间点的。4.4 关于绿皮书的一些学习建议很多人在博客或者问答里找SystemVerilog的绿皮书中文版——就是《SystemVerilog for Verification》的中译资料这本书确实是验证方向绕不开的经典。不过提个醒绿皮书的主线是类、随机化、覆盖率、UVM这些验证方法学内容对tran这类门级原语只是提了一下并没有展开讲。如果你想深入双向信号建模光看绿皮书是不够的。更合适的是去翻IEEE 1800标准中关于switch primitives和net strength的章节以及LRM里对连续赋值、net resolution的论述。绿皮书适合建立验证整体框架而原语细节还需要回到标准和仿真器手册里去对照。5. 实测踩坑记录双向仿真跑挂的六类典型问题排查5.1 问题一编译报错tranif1 not supported——综合与仿真工具差异这是最常遇到的第一个坑。你在写RTL时把tranif1放到设计代码里跑lint或者DC综合编译器直接报错unsupported construct。原因很简单tran原语属于结构级描述是仿真器用来模拟晶体管行为的综合工具不会把它翻译成门级网表。这不是语法错误而是工具能力边界不同。排查思路先确认报错工具是综合工具还是仿真工具。如果是综合工具报错那属于预期行为你需要把tran原语用可综合的三态门替代或者放到仿真专用的建模代码里。如果是仿真器也报不支持看一下自己用的仿真器版本——老旧的仿真器可能对tranif1支持不完整需要把rtranif1这类带电阻的原语换成行为级模型。这里提供一个排查的顺序先确认工具类型、再确认语言标准、最后确认代码位置。如果必须在同一份代码里兼容综合和仿真建议用ifdef分开ifdef SIMULATION tranif1 u_tran_a (data_bus, a_data, a_en); else assign data_bus a_en ? a_data : 1bz; endif这样仿真时用精确的原语建模综合时用可综合的三态门描述两不耽误。5.2 问题二波形里总是Z可en明明拉高了这个坑我印象太深了。有次调试一个双向IO控制信号明明拉高了波形里data_bus却始终是z数据根本没送上去。排查了很久最后发现是控制信号和开关原语的端口连接顺序打错了。tranif1的端口表是第一个是双向net端第二个是内部数据端第三个是控制端。如果我把内部数据和控制信号接反了仿真器不会报错因为两个端口都是net类型类型完全兼容但行为就完全错乱了——控制端收到了数据信号数据端收到了控制信号总线自然不可能正确导通。这种错误编译器发现不了只能靠仔细检查实例化代码。我后来养成了一个习惯每写完一个tran原语实例就对着一张对照表核对端口方向而不是靠记忆。另外如果你在仿真波形里看到控制端高电平但总线还是z也可以用$display打印出控制端实际值有时候是上游逻辑把信号拉低了而你误以为它拉高了——这个问题就是逻辑错误而不是建模错误了要从驱动链路上游找。5.3 问题三两个使能同时有效导致X态扩散在一个多设备共享总线的仿真中如果两个使能信号设计上应该互斥但因为时序或者控制逻辑Bug同时有效总线就会出现x态而且这个x会通过导通的开关传播到所有挂载设备上引发连锁反应。这个问题的根因在于无效的互斥设计很多工程师习惯了用if-else写互斥逻辑但硬件上如果多个信号分别来自不同的控制状态机没人能保证它们严格互斥。仿真层面可以先加断言property p_mutex_enable; (posedge clk) disable iff (!rst_n) not (a_en (!b_nen)); endproperty assert property(p_mutex_enable);如果这个断言能报出来说明互斥条件被破坏接下来就可以回到控制逻辑上排查问题。在调试的时候我还会配合队列监视器看看使能翻转的时间点和总线x态出现的时间点是否严格对应。如果x态出现在使能交叉时刻那大概率是竞态条件如果x态出现在某个设备内部逻辑错误之后那就要往数据通路上查。这里也补充一个经验在仿真里x态并不总是坏事。有时候x态是设计Bug的预警信号它比0/1更能暴露问题。但前提是你没有用defineSVR_NO_X之类的选项把所有x都强制优化掉否则等于把预警系统关了。5.4 问题四bind监控器里采集到的数据全是X有次我在bind监控器里采样总线数据波形显示data_bus明明正常但监控器里打印出来的数据全部是x。一开始以为bind层次引用错了后来发现不是层次问题而是时间片问题。bind模块内部的采样时机和总线数据变化的时机不在同一个时间片。data_bus在T时刻发生变化监控器的采样可能在Tdelta时刻中间经过了一些net resolution和不确定的延迟采样到的数据可能是过渡态x。这种问题在${ }解决方法是在监控器里加同步逻辑在时钟沿稳定的窗口采样数据而不是在always (data_bus)里直接采样。把采样时刻锁定到时钟沿之后的不定区间比如#1step能有效避开过渡态。always (posedge clk) begin #1step; // 此时数据总线状态已经稳定 bus_mon_queue.push_back(entry); end这样采集到的数据就是稳定且可消费的了。5.5 问题五rtranif0导通方向搞反数据流方向错乱rtranif0是低电平导通而且带电阻数据流双向。但在某些总线架构中即便开关本身对称两端接的信号类型不同数据流方向也会出现预想不到的效果。比如我把rtranif0的一个端口接到了强驱动的主机输出另一个端口接到了弱驱动的从机从机低有效使能时开关导通但数据流可能仍是主机强信号覆盖从机导致从机的数据根本送不出来。这个问题从开关行为上说是正常的但从功能逻辑上说是建模不当。解决方法是先明确期望的数据流方向如果从机必须能把数据送上总线那么主机侧在从机驱动期间必须释放也就是主机使能要关掉。而如果你不想依赖主机释放就要把从机侧的开关改成tranif0而不是rtranif0让两个驱动强度在同一水平然后靠逻辑上不同的时间段来避免竞争。也就是说选型不只要看控制电平还要看驱动力学和总线仲裁策略。5.6 问题六时序仿真时tran原语与SDF反标的配合问题最后一个坑集中在门级时序仿真。做完综合和布局布线后网表里会带上SDF标准延时文件仿真器在反标后按单元延迟来计算时序。这时候如果原设计里的tran原语被综合工具替换成了三态门网表就不再含tran原语时序仿真正常。但如果你的仿真平台还在同时跑原始RTL模型这个RTL模型里又用了tran原语而SDF反标是针对网表的两边的时间基准不一致就会出现数据错位。排查方法是明确区分仿真模式功能仿真用RTL加tran原语时序仿真用门级网表加SDF不要混着跑。如果非要在门级环境里保留tran的语义那就需要给tran建模一个专用的行为级模型并在反标时排除这个模型的时间弧避免SDF覆盖它。这个操作比较复杂一般情况下遵守分离原则就够了。6. 关于SystemVerilog双向传输建模的一些最终经验把这一整套流程走下来我想说些实际操作层面的体会。tranif1和rtranif0这类开关原语在大多数高抽象级的RTL设计里用不太到——抽象建模和验证逻辑用三态门assign语句就很方便了。但是一旦你的工作涉及IO建模、总线竞争分析、门级仿真、或者是混合信号设计的前仿部分这些原语就变成了无可替代的基础工具。它们的价值不只是能导通而在于把方向、控制、强度、电阻这几个维度统一到一个开关模型里仿真结果更接近真实的物理行为。如果你刚接触这个概念我建议不要只停留在读文档。拿今天这个示例工程先跑一遍功能仿真看看波形图里不同阶段的总线状态变化再把两个开关都换成tranif1模拟一次竞争场景观察x态如何扩散最后再切换到rtranif0看看强度衰减对总线最终值的影响。这三轮跑完你对双向信号传输的强度决议机制就有一个很直观的理解了。双向信号传输这个课题表面上是语法和原语问题本质上是关于net上多驱动如何决议的思维方式问题。掌握了tranif1和rtranif0的用法以后再碰到复杂总线建模你就能从底层逻辑上判断问题而不是靠试错碰运气。如果后面有机会我再写一篇关于三态门和tran原语在UVM环境里如何协同工作的实践经验那个话题比单讲原语还要更绕一些但掌握了就是真正的硬功夫。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。