Verilog组合逻辑电路设计实战:建模方法、编码规范与竞争冒险
组合逻辑电路这个主题Part1我们聊完了最基础的与或非门、布尔代数、卡诺图化简这些底子那Part2就得上点真家伙了——直接上手用Verilog把组合逻辑写出来并且写得好、写得稳。说实话很多同学卡住的地方不是不会写逻辑而是不知道怎么写才是规范的、可综合的、不给自己埋坑的所以这篇文章重点解决两件事一是常用组合逻辑模块的Verilog实现套路二是那些在综合和仿真里才会炸出来的问题比如竞争冒险、意外Latch、赋值方式用错等等。适合正在学数字电路和Verilog的初学者也适合做FPGA开发但组合逻辑部分经常踩坑的工程师看完可以直接把代码拿过去用。1. 组合逻辑设计思维先理顺三种建模方式1.1 三种建模方式怎么选Verilog描述组合逻辑核心就三把刀连续赋值assign、always块加阻塞赋值、generate结构。用对了是趁手工具用错了就是给自己添乱所以先把这个选型思路掰扯清楚。assign适合描述简单的逻辑表达式比如一个加法器、一个比较器、一个多路选择器的单bit判断。它的特点是并行、连续驱动也就是说只要右边表达式里任何一个信号变化左边就会立刻重新计算。我经常把assign比作水管信号流过去输出端跟着变没有时序概念也没有先执行哪条语句的问题。always (*)加上阻塞赋值适合描述带有分支判断的组合逻辑比如多路选择器、译码器、优先级编码器。它的本质是用C语言式的if-else或case来描述真值表综合工具会帮你翻译成门级电路。有人问那既然always能写assign也能写到底用哪个我的建议很简单能一行assign写完的不要非用always一旦逻辑里出现多条件分支、优先级判断、多输出才用always。道理不复杂assign写多条件分支很别扭读起来费劲而always让条件和输出一目了然。generate则用于参数化的结构复制比如多位全加器的级联、参数化多路选择器、多个相同模块的例化。它的核心价值是避免手写重复代码。举个例子例化8个相同的模块手写8遍不仅容易抄错改起来也是灾难用generate循环一次搞定。1.2 真值表到代码的转换套路很多新手拿到一个功能需求第一反应是直接开写代码这是最常见的错误。我自己的习惯是先在纸上把真值表列出来哪怕只有两三个输入也老老实实写一遍。真值表是组合逻辑的需求文档代码只是它的翻译跳过真值表直接写代码相当于跳过高德地图直接开车迟早翻车。举个简单例子设计一个3-8译码器。真值表就是一个输入编码对应一个输出拉高000对应out8b0000_0001001对应out8b0000_0010以此类推。看到这种输入输出一一对应的结构马上想到case语句最合适因为它的语法本身就是根据输入值匹配输出值和真值表的形态天然对齐。另一个经验用FPGA做设计时不必过度担心门级优化。很多人喜欢手工用卡诺图化简逻辑、减少门数这在分立元件时代是必杀技但FPGA综合工具会自动做逻辑优化和映射你把真值表写完整、功能描述正确工具会帮你搞定门级问题。真正需要关心的是分支是否完整、位宽是否匹配、会不会综合出多余Latch。这就像你请了厨师不用自己切菜但得把菜单写清楚。2. 常用模块的Verilog实现与优化思路2.1 多路选择器三种写法各有脾气多路选择器是组合逻辑里最基础也最常用的模块。先看最简单的2选1if-else版本module mux2_1 ( input wire a, input wire b, input wire sel, output reg y ); always (*) begin if (sel) y b; else y a; end endmodule这段代码看起来很直白但注意两点第一组合逻辑的always块里用阻塞赋值这是硬性规定后文会展开讲第二if-else隐含了优先级——if条件优先于else所以多个if-else嵌套会综合成优先级结构路径时延可能更长。如果你只想要一个纯粹的并行多路选择器case才是更合适的描述方式。用三目运算符可以一行搞定同样功能assign y sel ? b : a;三目运算符适合做单bit或简单信号的二选一可读性非常好。但一旦输入路数变多三目嵌套会变成天书这时候老老实实用casemodule mux4_1 ( input wire [1:0] sel, input wire [3:0] d, output reg y ); always (*) begin case (sel) 2b00: y d[0]; 2b01: y d[1]; 2b10: y d[2]; 2b11: y d[3]; default: y 1b0; endcase end endmodule这里给个实操心得case语句的default千万别省。虽然这个例子看起来所有分支都覆盖了但综合工具对未覆盖分支的处理是保守的一旦它认为某些输入值没有走任何分支就可能推断出LatchLatch在组合逻辑里是定时炸弹。与其让工具猜不如用default明确告诉它其他情况输出0。2.2 译码器和编码器优先级是隐藏主角译码器是case语句的经典应用代码很好写module decoder3_8 ( input wire [2:0] in, output reg [7:0] out ); always (*) begin case (in) 3b000: out 8b0000_0001; 3b001: out 8b0000_0010; 3b010: out 8b0000_0100; 3b011: out 8b0000_1000; 3b100: out 8b0001_0000; 3b101: out 8b0010_0000; 3b110: out 8b0100_0000; 3b111: out 8b1000_0000; default: out 8b0000_0000; endcase end endmodule还可以用移位操作一行实现同样的功能assign out 8b1 in;。这个写法输出直接是one-hot编码综合后资源也不差。这里有个小坑如果输入值大于7左移结果会超出位宽被截断所以最好确认输入范围或通过default兜底。编码器稍微复杂一点尤其是优先级编码器。什么叫优先级就是多个输入同时有效只承认最高的那个。这在实际系统里太常见了比如多个中断源同时来了系统得先响应优先级高的。Verilog里描述优先级最方便的是casezmodule priority_encoder ( input wire [7:0] in, output reg [2:0] out ); always (*) begin casez (in) 8b1???????: out 3d7; 8b01??????: out 3d6; 8b001?????: out 3d5; 8b0001????: out 3d4; 8b00001???: out 3d3; 8b000001??: out 3d2; 8b0000001?: out 3d1; 8b00000001: out 3d0; default: out 3d0; endcase end endmodulecasez把?当作任意匹配于是从上到下天然形成优先级链。我在实际项目里经常借鉴这个思路但说句实话当优先级条件变得很复杂时casez的可读性会下降这时候改用多个if-else反而更直观虽然综合结果都是优先级结构但代码的维护性更重要。2.3 加法器从半加器到超前进位加法器是组合逻辑里的硬骨头也是面试和笔试的高频考点。先看半加器它只考虑两个加数本身不考虑低位进位module half_adder ( input wire a, input wire b, output wire sum, output wire cout ); assign sum a ^ b; assign cout a b; endmodule全加器多了个进位输入cinmodule full_adder ( input wire a, input wire b, input wire cin, output wire sum, output wire cout ); assign sum a ^ b ^ cin; assign cout (a b) | (a cin) | (b cin); endmodule全加器的进位逻辑可以这么理解三个输入里只要有两个或以上的1就产生进位。ab是两个加数本身都是1acin和bcin是其中一个加数和进位同时为1三种情况一或就是答案。多位加法器最朴素的做法是行波进位加法器把全加器一级级串起来每一级的进位输出作为下一级的进位输入。用generate实现module rca #( parameter WIDTH 4 )( input wire [WIDTH-1:0] a, input wire [WIDTH-1:0] b, input wire cin, output wire [WIDTH-1:0] sum, output wire cout ); wire [WIDTH:0] carry; assign carry[0] cin; genvar i; generate for (i 0; i WIDTH; i i 1) begin : gen_adder full_adder u_full_adder ( .a (a[i]), .b (b[i]), .cin (carry[i]), .sum (sum[i]), .cout (carry[i1]) ); end endgenerate assign cout carry[WIDTH]; endmodulegenerate循环里每个例化模块的名字叫gen_adder[0]、gen_adder[1]这样方便仿真和综合时报错定位。行波进位的最大问题是延迟进位要一级级传下去N位加法器进位链延迟近似N倍单级延迟位数一高就成瓶颈了。解决这个问题就要上超前进位加法器。核心思想是提前把进位算出来而不是等低位算完。定义两个信号g a bgenerate本级必然产生进位和p a | bpropagate本级传播进位那么进位公式可以写成c1 g0 | (p0 c0) c2 g1 | (p1 g0) | (p1 p0 c0)每一位的进位只取决于输入和初始进位c0不再依赖前一级的进位计算结果所以理论上进位计算只要两级门延迟。代价是逻辑表达式随位数指数膨胀所以工程上不会一下子算32位而是4位一组做超前进位组间再用行波或再套一层超前进位。这也是为什么很多CPU设计里加法器是分层结构的。面试时能把这几层讲清楚比背代码强得多。3. 竞争与冒险组合逻辑最隐蔽的坑3.1 为什么会出现毛刺竞争冒险大概是组合逻辑里最让人头疼的问题因为它在仿真里能看到、在真实电路里会冒泡但功能仿真结果可能表现不出来。先说机理。现实中的门电路有延迟同一个信号经过不同路径到达同一个逻辑门的时间可能不一样这种现象叫竞争而产生的短暂错误脉冲叫冒险毛刺。举个最经典的例子module glitch ( input wire a, output wire f ); wire not_a; assign not_a ~a; assign f a not_a; // 理论上恒为0 endmodule从布尔代数看a ~a永远等于0。但真实电路里a直接到达与门需要经过一个门的延迟而not_a却要经过反相器再加与门两条路径延迟不同。当a从0跳变为1的瞬间not_a可能还没来得及变为0此时与门的两个输入短时间里同时为1输出就冒出一个高电平毛刺。再如f a b如果a从1变成0、b从0变成1这两个信号在理想情况下是同时变化的但真实电路里它们的延迟不同可能有一小段窗口内两个输入都为1输出就产生毛刺。组合逻辑层级越多、扇出越大毛刺问题越严重。3.2 四种消除毛刺的方案与选型消除毛刺不能靠运气要分场景选方案。我列个对比表方案原理适用场景注意事项卡诺图冗余项增加冗余与项让输出在信号变化窗口内保持稳定门级手工设计、中低速电路增加逻辑面积只在关键路径用输出端加D触发器组合逻辑输出在时钟边沿采样毛刺落在采样窗口外同步数字系统最常用适合的是同步设计不是异步信号输出滤波电容利用RC低通特性吸收毛刺板级模拟电路、低速信号会拖慢信号边沿高频场景不可用选通脉冲在输出稳定后再用脉冲读取结果总线读写、存储器接口需要额外时序控制我几乎只在同步设计里用D触发器采样这一招。原因很简单在FPGA里前面那些门级优化手段都不太现实而D触发器每个Slice都有不用白不用。你把组合逻辑的输出打一拍只要毛刺宽度小于时钟周期采样到的就是稳定值。这本质上是让时序逻辑来容忍组合逻辑的不确定性也是同步设计思想的精髓。3.3 仿真中如何定位竞争冒险功能仿真里定位毛刺有个小技巧把仿真的时间精度调高。比如用timescale 1ns/1ps如果毛刺宽度在皮秒级精度不够的仿真根本看不到。另外可以用$monitor实时打印输出变化一旦输出出现理论真值表里不存在的状态基本就能确定存在竞争冒险。我自己的调试习惯是先看波形里有没有宽度极窄的脉冲尤其是多个输入同时翻转的时刻。如果毛刺反复出现再去回溯RTL代码看哪些信号经过了不对称的路径。说句实在话纯粹的组合逻辑毛刺在FPGA里一般不会导致系统崩溃因为最终都会通过寄存器采样真正致命的往往是毛刺被当成时钟或异步复位所以下面这点要特别记住不要把组合逻辑的输出直接接到时钟引脚或异步复位引脚这类信号必须经过同步处理。4. 组合逻辑的Verilog编码规范守住红线4.1 阻塞赋值与非阻塞一条铁律这个知识点可以说被讲烂了但每次项目评审我还能看到有人栽跟头。规则就一条时序逻辑用非阻塞赋值组合逻辑用阻塞赋值两者绝不混用。为什么这么规定关键在于仿真器的调度机制。非阻塞赋值不是立刻生效的它先把值放到待更新队列等当前时间步所有赋值语句都执行完再统一更新。如果组合逻辑里用了非阻塞赋值你在语句块内读到的信号可能是旧值仿真结果和你预想的真值表就对不上。而阻塞赋值是立即生效的从上到下按顺序执行正好符合组合逻辑的输入变、输出跟着变的特性。举个反面例子如果组合逻辑里两个信号互相依赖用非阻塞赋值会导致仿真出现同一时刻读不到更新值的怪象而在真实电路里组合逻辑本来是可以瞬间稳定的。这种仿真和实现行为不一致才是这个规则最坑人的地方。顺便说一句always块里给reg类型赋值不代表综合出来一定是触发器组合逻辑的always块综合结果是一堆门电路只有时序逻辑的always块才会综合成寄存器。4.2 完整分支与Latch的纠缠Latch锁存器在组合逻辑设计里基本是个贬义词但很多初学者不知道它的来源。我总结一下只要always块里存在某些输入条件下信号没有被赋值的情况综合工具就可能推断出Latch。最常见的有三类写法问题if语句缺少else分支条件为假时保持原值这就是存储器行为case语句缺少default未覆盖分支保持原值同理在always块中对信号进行自己到自己的赋值比如y y;更是明摆着要Latch。确保Latch不出现的做法只有一套组合拳if必须配elsecase必须配default组合逻辑里别给自己赋值。我见过太多人写完代码综合完莫名其妙面积大了一圈打开网表一看全是Latch根源就在这几行。用了default和else还有一层好处综合工具能明确未定义状态的输出值路径优化更干净。4.3 参数化与generate让代码可复用参数化设计是组合逻辑进阶的必修课。核心是用parameter定义位宽、用generate批量例化写一次代码、多处复用。举个例子把上面的2选1多路选择器改成参数化位宽版本module mux_n #( parameter N 8 )( input wire sel, input wire [N-1:0] a, input wire [N-1:0] b, output wire [N-1:0] y ); assign y sel ? b : a; endmodule例化时只需要传参mux_n #(.N(16)) u_mux (...)同一个模块既能当2选1用也能当16位总线选择器用。再配合generate就能做任意位宽的加法器、移位器、交叉开关。我自己常用的参数化场景还有localparam它和parameter的区别是localparam不能从外部传参适合模块内部定义常量。比如定义一个状态编码表、一个延迟参数用localparam避免模块接口被无关参数污染。参数化不仅是省代码量更是提高可维护性的关键想改位宽的时候只动一个参数而不是到处改constant这种幸福感用过都懂。5. 常见问题排查与调试实录5.1 仿真波形不对从哪查起仿真波形和预期不符别急着怀疑工具先从这几个方向排查。第一敏感列表。如果你在always块里手写了always (a or b)而实际逻辑里还用了信号c那c变化时输出完全不更新波形自然不对。解决办法是全部用always (*)让工具自动推导敏感列表这就是为什么我一直推荐(*)而不是手写列表。第二未知态X。信号如果没初始化、或者有多个驱动源仿真会出现红色的X态之后所有依赖它的信号全部变X看起来就是一片乱码。排查方法是全局搜索有没有未复位寄存器、有没有信号被多模块同时驱动多驱动是设计错误综合会直接报错。第三位宽不匹配。比如一个4bit信号和一个8bit信号做运算仿真器会按最大位宽扩展符号数的符号扩展偶尔会带来意外结果。排查时先确认所有信号的位宽和有无符号属性。5.2 综合后资源暴增的元凶组合逻辑代码综合后资源异常我碰到过几种典型原因。最坑的是在组合逻辑里写了除法。除法在FPGA里是个昂贵的东西非除数的除法综合工具一般会生成大量的逻辑单元面积和延迟都爆炸。能用移位实现就用移位比如除2就是右移1位、除4就是右移2位稍微复杂点的定值除法可以用乘法加移位近似。第二种是过长的if-else优先级链。前面讲过if-else天然是优先级结构十几层嵌套会让关键路径拉得很长。解决办法是重新审视逻辑结构能用case就用case能把长链拆成多段就拆开。第三类是case条件写得不完整导致Latch这个第4章讲过了。每回综合完第一件事就是看综合报告里的Latch数量不为0就回头查分支完整性。这个习惯能帮你把80%的资源问题扼杀在摇篮里。5.3 经验速查表症状常见原因快速排查手段仿真输出一直是X未初始化、多驱动查复位、查Q驱动源输出和真值表对不上敏感列表漏信号改用always (*)综合出Latch缺少else或default检查分支完整性面积异常大除法、长if-else链查综合报告关键路径波形有毛刺竞争冒险提高仿真精度、加寄存器采样时序违例组合逻辑路径过长在中间插入寄存器流水线最后说一个我自己在项目中反复验证过的体会组合逻辑设计的很多坑都是在仿真通过但上板失败的时候才暴露的因为仿真只验证功能不验证时序细节。所以从一开始就要用规范写法约束自己——分支写全、赋值方式用对、敏感列表用(*)、位宽对齐、参数化复用。这些习惯看着琐碎但每一个都是在给后面的自己排雷。另外仿真里看到毛刺别急着改代码先判断这个毛刺有没有可能被采样到如果后续都经过寄存器那它就只是纸老虎真正要警惕的是那些绕过寄存器、直接参与控制逻辑的毛刺信号那种才是真会炸的雷。

相关新闻

华为IAD语音交换机配置实战:从组网规划到故障排查

华为IAD语音交换机配置实战:从组网规划到故障排查

简介:华为语音交换机IAD配置手册的光盘交付内容,完整收录了官方配置说明与故障排除文档;面向通信网络运维人员、企业IT管理员及语音网关项目集成商,覆盖开局部署、日常配置、故障排查等实际场景。包内共114个文件、约19.89MB&…

2026/10/17 5:07:18 阅读更多 →
机器人时维感知:时间同步、相位建模与因果推理技术解析

机器人时维感知:时间同步、相位建模与因果推理技术解析

1. 项目概述:给机器人装上“时间感知神经”的真实含义“时维感知融资数千万,给机器人造神经系统”——这个标题乍看像科幻小说封面,但拆开来看,它其实精准指向一个正在快速落地的工业级技术突破:让机器人不再只靠“此刻…

2026/10/17 5:06:18 阅读更多 →
Claude Code模板驱动实践:用CLAUDE.md与prompt模板打造高效AI编程工作流

Claude Code模板驱动实践:用CLAUDE.md与prompt模板打造高效AI编程工作流

1. 为什么我最后把Claude Code用成了模板驱动先说个真实场景。我大概是在Claude Code还比较早期的时候就开始用了,那时候的想法很简单:它就是一个能读懂代码库、能帮我改代码、能执行命令的终端助手。用了一段时间之后,我发现一个问题——每次…

2026/10/17 5:06:18 阅读更多 →

最新新闻

世界模型创建流程全解析:从任务定义到下游部署

世界模型创建流程全解析:从任务定义到下游部署

我第一次把一个完整的world_model跑通,是在一个带随机障碍物的二维导航任务里。训练的损失曲线说实话并不惊艳,重建出来的画面也有点糊。但真正震撼我的时刻,是闭掉真实观测之后,模型自己在潜空间里预测出来的那几十步轨迹&#x…

2026/10/17 5:44:29 阅读更多 →
XML自动生成工具:从手写拼接转向序列化库与配置驱动

XML自动生成工具:从手写拼接转向序列化库与配置驱动

简介:这是一款面向Java后端开发与数据集成人员的XML文件自动生成工具,核心解决从数据库快速导出结构化XML文档、避免手工编写易出错的问题。工具基于JDBC连接数据源,通过加载驱动、建立连接、执行SQL查询并遍历结果集,将每行数据映…

2026/10/17 5:44:29 阅读更多 →
Allegro DRC报错类型详解:PCB设计工程师的排查指南

Allegro DRC报错类型详解:PCB设计工程师的排查指南

PCB设计评审时,Allegro的DRC报错经常是整块板子上最扎眼的东西。看到满屏的红、白、绿色标记,很多人第一反应是“完了,设计有问题”,但老工程师不会急着改图,而是先看报错类型:哪个规则被触发了、对象是什么…

2026/10/17 5:44:29 阅读更多 →
结构光三维重建:散斑、多频与相移格雷码选型全解析

结构光三维重建:散斑、多频与相移格雷码选型全解析

做三维重建、机器人视觉定位或者工业检测的人,大概率都绕不开“结构光”这个词。散斑结构光、多频结构光、相移加格雷码,这三套方案几乎是市面上结构光相机和3D扫描仪的三条主流技术路线。我经常被问到同一个问题:这三种到底选哪个&#xff1…

2026/10/17 5:44:29 阅读更多 →
Docker部署ELK日志系统全流程实战

Docker部署ELK日志系统全流程实战

最近业务日志量上来了,接触ELK的朋友越来越多。我见过不少人折腾这套东西,最有意思的是:他们往往不是被Elasticsearch的查询语法难倒的,而是卡在最开始——怎么把三个组件干干净净地跑起来。本机装个单机版ES倒是简单,…

2026/10/17 5:44:29 阅读更多 →
基于MP2642GR-Z与TM4C129LNCZAD的双串电池主动均衡方案设计

基于MP2642GR-Z与TM4C129LNCZAD的双串电池主动均衡方案设计

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

2026/10/17 5:43:29 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/16 21:54:38 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →