后仿真中的race问题:三类典型场景与五步定位法

干后仿仿真时间长了,我最怕的不是功能跑挂,而是那种“功能仿真全绿、门级仿真一开就莫名出现X”的情况。这类问题里,race-condition占了相当大一部分。前两篇讲了一些常见场景,这篇继续补充三个我实际遇到过、而且定位过程比较有代表性的案例。如果你也在跟后仿中的X态、毛刺、偶发失效做斗争,这期内容应该能帮你省下不少排查时间。

所谓后仿race,本质上是多个信号在同一仿真时刻、同一轮或相邻几轮事件调度里产生竞争,导致仿真器按照事件到达顺序不同而给出不稳定的结果。它不是时序违例,却往往以“偶发X”“某一次回归失败”“换了随机种子就消失”之类的面貌出现。真正可怕的是,这类问题在代码review里看不见,在PR前仿真的波形里也不出现,等门级仿真一上,就变成悬在头顶的剑。

1. 后仿真里race的底层机制,先搞懂再排查

在讲具体场景之前,先把race的根源说透。后仿中race高发,和门级仿真的仿真机制有直接关系,不理解这个底层机制,后面排查会很费劲。

1.1 前后仿真的“同时”不是一回事

RTL功能仿真里,组合逻辑没有绝对延迟,同一个时钟沿触发的信号会在同一仿真时刻的同一轮事件里更新。看起来“所有信号同时变化”,实际上仿真器把它们排在一个有序的事件队列里,只是在同一个时间戳内完成而已。这个阶段很少有race,因为信号更新的先后顺序对最终结果基本没有影响。

门级仿真完全不同。经过SDF反标之后,每个标准单元、每条互连路径都有延迟参数,而且上升延迟和下降延迟经常不一样。组合逻辑的输出不再是一个时间点的跳变,而是散布在多个时间点上的小翻转。两个输入信号到达同一个cell的延迟差,可能在前仿中完全不存在,在后仿中却直接暴露出来,于是“同时变化”变成了“不同时刻的连续变化”。

这里有一个很常见的误区:总觉得race是那种“两个信号在同一时刻打架”的问题。其实后仿中的race往往表现为“一个信号在事件队列里的先后顺序与另一个信号的计算节点产生交叉”。它不一定是同一时刻的关系,而是同一时间戳内不同delta cycle(delta轮)之间的竞争关系。

1.2 delta轮次为什么会造成不确定性

delta cycle是仿真器在同一仿真时间内,为了处理信号传播而引入的连续迭代机制。比如一个NOT门,输入从0变成1,输出并不是立刻变化,而是在下一个delta轮里被更新成0。这个输出再驱动下一级,又会在再下一个delta轮更新。也就是说,在一个固定的仿真时间点内部,可能存在几十上百个delta轮次。

要理解race,就得把每个delta轮次当成一个独立的“事件计算阶段”。问题来了:如果A事件在第3个delta轮更新了信号,B事件在第4个delta轮采样了另一个信号,那结果取决于到底谁先被仿真器取走。不同仿真器、不同版本、甚至同一仿真器的不同优化选项,都可能导致这两个事件在delta轮上的顺序不同。

我用一个生活化的类比帮你理解:你同时给两个人发了消息,一个说“灯关掉”,另一个说“同学马上要来”。如果收信人先看到前一条,他会关灯;先看到后一条,他会留着灯。硬件电路里,这两个消息对应的是同一时刻到达的翻转和采样窗口;在仿真器里,它们的先后顺序由delta调度决定,而不是由真实物理时间决定。这就是race的源头。

1.3 区分仿真假象与真实隐患

不是所有race都是硬件bug。有一部分race纯粹是仿真器对门级模型的事件调度引入的假象,放到真实芯片上根本不会发生。但也有一部分race恰恰反映了真实电路中的时序风险,只是发生在仿真时间尺度上,被我们用“那只是个仿真X”的借口放过去了。

我的经验是:遇到race别急着改代码,先做一次定性判断。如果问题只在特定仿真选项下出现,或者只影响X传播路径而对0/1结果完全没有影响,那多半是仿真调度假象。如果问题影响了判决结果(比如采样到错误值、状态机进错分支),并且路径上存在真实的时序余量不足,那就要当成硬件隐患处理。这个判断直接影响后续的修复策略,做反了会浪费大量时间。

2. 场景A:异步复位释放撞上时钟沿,一个X态把一屏波形带崩

第一个场景来自一次典型的后仿回归失败。某模块在复位释放后的第一个时钟上升沿,出现了一大批寄存器输出X,紧接着X像多米诺骨牌一样扩散到了后续好几个周期。功能仿真完全正常,门级仿真只要换一个随机种子,X扩散的范围和路径就变化。

2.1 现象:复位释放后的首个时钟沿一片X

当时我的第一反应是检查复位释放时序。打开波形后,瑞斯释放信号在某个时刻拉高,紧接着不到几纳秒就是时钟上升沿。问题是,这个释放沿并没有整齐地送到所有寄存器的复位端,而是经过了好几级缓冲单元和修复单元。由于SDF反标,各条复位分支的延迟差异很大,导致释放沿到达不同寄存器复位端的时间点散开。

真正触发X的寄存器,其复位端在时钟沿到来时并没有完全变成1,而是处在由X到1的过渡过程中。门级lib里的复位端模型通常不会瞬间翻转,它在仿真器内部可能产生一个亚稳态X状态。一旦寄存器的复位端是X,输出自然是X,而且这个X从此跟定了这个寄存器,除非有明确的复位或置位事件把它拉回来。

我在波形里追下去,发现第一个X源来自一个很小的触发器,它既不是关键路径上的寄存器,也不是复位树的末端,而是刚好处于时钟沿和复位释放沿之间一个“夹缝”位置的倒霉蛋。它自己变成X之后,下游一大片组合逻辑跟着被污染。

2.2 根因:复位释放沿与时钟采样的delta竞争

打开事件列表后我印象非常深刻:复位释放信号的下升沿(这里注意,是异步复位的释放沿,不是有效沿)和系统时钟上升沿在同一个仿真时间戳内,但落在不同的delta轮次上。复位释放信号先在一个delta轮里变化,经过缓冲单元后传到寄存器复位端却已经是几个delta轮之后;此时时钟有效沿已经在更早的delta轮里完成了采样事件调度。

寄存器在这种状态下如何判决?不同厂家单元库的门级模型处理方式不一样。有的库会直接输出X,有的库会保持上一状态,有的库会在X恢复为1后再次触发Q端更新。我遇到的这个库选择了最不友好的路径:复位端在时钟有效沿时是X,输出端直接变X,且后续不自动恢复。

从根因看,这是异步复位释放路径与时钟采样路径之间的真实约束缺口。PR工具通常会在复位释放路径上做时序修复,但如果复位释放被误设成了false path,或者时钟门控单元所在的时钟分支延迟反而比复位释放缓冲链快,这个缺口就会被掩盖到后仿阶段。

2.3 处置:同步器、约束与仿真豁免

这一类问题我最终的处置分成三层。

第一层,RTL层面强制修复:复位释放必须经过同步器(通常用两级触发器同步后再分发到各模块),确保释放沿和采样时钟之间建立足够宽松的时间窗口。这属于让人挑不出毛病的标准做法。如果设计里用的是异步复位、异步置位,那释放路径的同步化尤其不能省。

第二层,时序约束层面:在SDC里把复位释放路径设为false path,避免PR工具在复位树上花过多力气;同时对真正的复位释放做set_output_delay或者set_case_analysis,让工具严格检查释放沿与时钟沿的timing。这一点很容易被忽略,因为很多项目复位释放路径从来不查时序,结果后仿就把账算回来了。

第三层,仿真豁免层:如果确认某条复位路径只是仿真模型过激反应,可以这么做——在testbench里给复位释放信号加一个稍微提前的$delay,让释放沿避开时钟有效沿的delta窗口;或者对目标路径加仿真的no_timing_check。但要清醒:这是豁免仿真工具的行为,不是修复硬件,只能作为验证环境的特殊处理,不能写进交付代码。

还有一个小提示:这类race的排查非常依赖波形对比。我建议事后把复位释放分支里延迟最大的那条路径单独拉出来,和时钟沿做时间差统计,记录下来作为下次回归的监控指标。

3. 场景B:SDF反标后的组合毛刺在采样窗口翻车

第二个场景是一个关于组合逻辑毛刺的典型坑。某模块的MUX输出在RTL仿真里稳如老狗,后仿里却偶发采样到错误数据。最初我以为是数据路径上的时序违例,做了一堆setup/hold分析,全部绿。后来才发现问题根本不在时序收敛,而是毛刺被采样了。

3.1 为什么前仿看不到这个毛刺

这个模块里,MUX的sel信号来自两级组合逻辑,而MUX的两个输入data分别来自不同的上游寄存器和组合路径。前仿中,sel的两个来源信号在同一delta轮里更新,sel在同一时刻完成跳变;MUX的输出在同一个delta轮里直接跟随新的sel和data组合,干净利落,没有任何中间状态。

门级仿真就不一样了。两条路径经过SDF反标后,到达sel端的时间差可能是几百皮秒。如果sel信号的A来源先到、B来源后到,那么sel在中间这段窗口内并不是一个稳定的0或1,而是可能出现一次甚至多次翻转。这个翻转窗口如果恰好对准了时钟沿,那MUX输出会先按旧sel的值采样,再按新sel的值采样,甚至可能出现X。

问题的关键点在于:毛刺不是“有没有”的问题,而是“采样点会不会正好落在毛刺窗口”的问题。RTL仿真没有时间概念,它不知道什么叫毛刺窗口;后仿有了延迟时间,毛刺窗口就变成了真实存在的事件序列。

3.2 毛刺从产生到被采样的完整链路

为了把整个链路讲清楚,我假设一个简单的场景:一个AND门,输入A和输入B分别到达该门的延迟差为500ps,而这个门的输入到输出传播延迟是200ps。B先到达,A后到达。当B从0变成1时,由于A还是0,输出稳定在0;几皮秒后A也变成1,这时B已经是1,AND输出从0变成1。这中间其实没有毛刺,因为两个输入变化方向相同。

但如果B先到达且从1变成0,A还没变、仍为1,此时AND输出会从1变成0;再过几百皮秒,A从1变成0,输出保持0,这也没有毛刺。真正产生毛刺的情况是:B先到达且从1变0,A未变化之前维持在1,输出瞬间为0;随后A变化到某个中间状态或恢复为1,输出再次变成1。这样的0脉冲就是毛刺。

这个窄脉冲只要宽度小于寄存器的采样窗口要求,就可能不被后一级寄存器当作有效数据,也可能被当成有效数据采集到。更麻烦的是,门级lib对窄脉冲有最小脉冲宽度检查,如果毛刺太窄,单元库模型会直接把它变成X传播出去。我遇到的情况就是这样:毛刺宽度不到50ps,采样寄存器的时钟沿正好落在其中,输出先是采到一个错误值,同时由于库模型对窄脉冲的X化处理,输出直接变成X。

3.3 不是消灭毛刺,而是清理采样路径

接手这个问题时,我最开始的想法是给MUX输出加一个毛刺滤波器。但想了想不对:毛刺是路径延迟差造成的,滤波它不如拉开采样点和毛刺的距离。

最终方案是重定时。把MUX输出经过的那一级组合逻辑拆开,在毛刺源和采样寄存器之间插入一级寄存器,让毛刺在传播到采样点之前就被隔断。这步操作既改了RTL,也重新走了PR,后仿立即稳定。

不过我见过更省事的处理方式:如果确认毛刺只会出现在特定配置组合下,可以调整SDC中的max_delay约束,让两条路径的延迟差收敛到安全范围。本质上和重定时一样,都是让毛刺窗口远离采样沿。但如果路径本身已经被推满,约束调整的空间不大,重定时往往更可靠。

这里有一个工程判断:并不是所有后仿毛刺都需要修硬件。如果是仿真器对太窄脉冲的过激反应,且脉冲宽度远小于芯片实际可能出现的脉宽,完全可以通过库模型或仿真参数处理掉。可一旦毛刺宽度接近或超过工艺下的最小可分辨脉宽,就要当真实风险处理。

4. 场景C:force/release和时钟进程的竞争,验证环境把自己带沟里

第三个场景不是设计本身的问题,而是验证环境自己给自己挖的坑。我在一个后仿调试环境里,为了隔离某个模块的失效点,直接对内部信号做了force。结果force本身引入了一个新的race,让原本只是想Debug的现象变得完全不可复现。

4.1 现象:隔离式force让下游接口“随机”出错

当时的现象很怪:只要对某个时钟门控信号做了force,下游接口偶发出现错误的数据选通;去掉force之后又完全正常;加大force持续时间,错误概率又会变。我一度怀疑是设计有问题,但换一种force方式之后问题又没了。

后来把waveform导出事件列表逐条看,发现问题出在force/release和时钟进程的同步上。force是在一个仿真时间点内执行的,但它具体落在哪个delta轮,取决于testbench里force语句的触发条件。如果force和当前时钟沿落在同一个时间戳内,下游组合逻辑有可能在下一个delta轮就按照force后的值计算,而另一部分逻辑仍然按force前的值计算,形成行为上的割裂。

release也类似。release的一瞬间,逻辑值从强制值跳回原始值。这个跳变如果发生在时钟沿附近,采样寄存器看到的可能不是“最终的稳定值”,而是“跳跃过程中的某个中间值”。尤其是release的信号本身还在活跃翻转状态,这个中间值就直接变成了X或者错误值。

4.2 根因:force/release事件的调度位置

根因在于,force/release在仿真器的事件调度模型里属于“用户命令区”操作,它和普通的事件传播、NBA更新不在同一个优先级层级。不同仿真器对这个区域的实现细节不同,有的仿真器允许force在任意delta轮之间插入,有的则只在特定轮次生效。于是,同一个testbench在不同仿真器上,或者同一仿真器的不同优化级别下,force生效的delta位置可能完全不一样。

这种差异带来的后果就是:你可以复现同一个测试向量,但force的race行为每次不完全一样。它不是典型的0/1竞争,而是“谁先看到这条命令”的竞争。

从那之后我养成了一个习惯:在做任何后仿debug时,先弄清楚force是在什么仿真时间、什么delta轮被执行的,而不是只看波形值。

4.3 几个把force用安全的方法

要避免这类race,我的建议是三条。

第一条,强制的时间点不要贴着时钟沿。在testbench里先等待一个明确的事件(比如时钟下降沿),再执行force或release,确保force动作发生在时钟静默期。这样避免和采样窗口正面冲突。

第二条,release之后不要立即做断言。等两三个时钟周期,让信号从强制值恢复并稳定后再检查结果。很多临时Debug条件失败,都是因为release后还没等信号稳定就下了结论。

第三条,如果不得不在时钟沿附近force,那就给force的目标信号加一个显式的小延迟,例如#1ps,把它推到下一个仿真delta轮。注意这个延迟必须是仿真层级的小量,不要影响其他信号的时序关系。

我还遇到过一个更狡猾的情况:force一个时钟门控信号为常1,结果内部时钟被强制无毛刺地切换,导致某个计数器模块以为自己永远处于活动状态,跑出来的结果和真实芯片行为完全不同。这个案例再次提醒我:force只能用来隔离问题,不能用来模拟真实行为,race问题可能因此被掩盖或放大。

5. 通用排查链路与工程化建议

前面三个场景各有各的细节,但背后的排查思路是一致的。我整理了一套五步定位法,基本可以覆盖绝大多数后仿race。

5.1 五步定位法

第一步,找首因。不要从最终的X态或者错误结果往前倒推,那样会被中间扩散的X态带偏。直接在波形里定位“第一个非预期信号变化”发生在哪个仿真时间、哪个信号上。

第二步,拉事件列表。把该时刻前后所有相关信号按delta轮排列,重点看同时间戳内哪几个事件在竞争。这一步在GUI里很难看清,我习惯直接导出文本事件日志。

第三步,做对照实验。换随机种子、换仿真器选项、调整SDF反标精度、临时修改单元延迟模型,看race是否变化。如果换一种配置问题就消失,多半是调度层竞争;如果无论怎么换都稳定出现,就要怀疑真实硬件风险。

第四步,排除testbench因素。看有没有$random、$urandom、force/release、interface里的时钟采样边沿等不确定因素混进来。这个顺序要放在硬件分析之后,因为testbench self-inflicted的race也很多,但容易被人忽略。

第五步,归类修复。硬件问题回到RTL/约束/PR去修;仿真模型问题回到仿真参数去修;testbench问题回到testbench去修。不要用仿真豁免去掩盖硬件问题,也不要在testbench问题上反复调整RTL。

5.2 race现象、首查动作与修复方向速查
现象特征可能根因首查动作推荐方向
复位释放后首个时钟沿X扩散异步复位释放与时钟沿竞争检查释放沿到各寄存器复位端的delta分布复位同步器、SDC豁免修正
组合逻辑路径偶发采样错误但setup/hold全绿SDF反标后毛刺窗口命中采样沿拉取毛刺源路径延迟差与采样时间点重定时、约束收紧、毛刺滤波
换随机种子后X路径变化事件调度顺序不稳定导出事件列表对比delta轮修正仿真选项、稳定testbench同步
force/release后结果不稳定force动作与时钟进程竞争确认force/release所在delta轮force打点避让时钟沿、释放后稳定再断言
5.3 仿真器设置与回归策略

多数仿真器对X传播都做了优化控制。在排查race时,我通常会把X传播相关报告全部打开,而不是默认让仿真器自动把一个X变成0或1。一旦发现X,立即定位到具体cell和delta轮,比事后猜测要高效太多。

关于回归策略,我的做法是:每一个涉及复位释放、时钟门控、跨时钟域的testbench,都在常规回归之外再跑一轮随机种子轮换。这个成本不高,但能把调度层的race暴露出来。很多race问题第一次出现都是“某一次随机回归挂了但重跑就好了”,如果不做这种轮换,这类问题可能在交付前都不会再出现。

还有一点经验:race问题尽量用小波形、小范围去查。不要一上来就铺满整屏信号,那样既看不清事件顺序,也容易被后续X传播的大量信号干扰。一次只看三个对象:源头信号、中间路径信号、采样点信号。定位后逐步扩大范围。

后仿真race排查的一些个人体会

跟race打了这么多年交道,最大的体会是:它看着神出鬼没,其实套路固定。我遇到的后仿race,八成以上落在复位释放、组合逻辑毛刺采样、testbench自身调度这三类框架里。按前面说的顺序排查,基本不会空手而归。再补一个小技巧:排查race时多利用文本事件日志,别只靠波形。波形适合看趋势,但delta轮级别的先后顺序,必须靠事件列表来判断。每次定位完一个race,我会顺手把事件摘要存档,后续同类问题直接对照,排查速度会快很多。

相关新闻

STM32F103内部Flash读写:免外部EEPROM,实现掉电数据保存

STM32F103内部Flash读写:免外部EEPROM,实现掉电数据保存

简介:面向STM32F103嵌入式开发者的内部Flash读写资料包,覆盖Flash存储器原理、读取操作、扇区擦除、写入时序与EEPROM模拟方法,帮助解决程序代码存储、配置数据保存及非易失性数据读写等实用问题。资源包共156个文件,以C源码和头文…

2026/10/22 14:53:08 阅读更多 →
杰理AC696N开发板Windows开发环境搭建完整指南

杰理AC696N开发板Windows开发环境搭建完整指南

很多人拿到一块新开发板,第一反应都是先插USB、找资料、装IDE。我拿到AC6966B开发板的时候也差不多,但实际走了一遍才发现,这套AC696N开发环境并不是一个安装包能搞定的,它由固件工程、编译工具链、下载工具和调试串口四部分拼装而…

2026/10/21 7:38:02 阅读更多 →
私域流量自动化运营系统架构与实操:事件驱动规则引擎

私域流量自动化运营系统架构与实操:事件驱动规则引擎

1. 私域自动化运营的底层逻辑与方案选型1.1 为什么私域运营必须走自动化路线做私域的人都有一个共同的痛:手动运营的天花板来得特别快。一个人管三五个群还能应付,一旦群数量上到二十个、三十个,每天光是欢迎新成员、发公告、回答重复问题就能…

2026/10/22 12:29:56 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/21 21:32:28 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 21:50:56 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 21:51:55 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 16:24:48 阅读更多 →