2026年FPGA校招笔试Verilog手写序列检测和分频电路,为什么仿真对了但综合后功能不对?

开放10 回答 125 浏览

最近做FPGA校招笔试题,Verilog写序列检测器和奇数分频,仿真波形完全正确,但面试官说综合后可能有问题。我检查了阻塞非阻塞赋值,也用了状态机。想请教:笔试和上板之间常见的坑有哪些?比如复位、时钟、锁存器、综合器优化,哪些最容易导致仿真对但实际不对?

分享:

10 个回答

  • 嵌入式小白

    先说最容易被忽略的一条:仿真对、综合后不对,八成不是状态机写错了,而是你写的东西和综合器理解的不一样。笔试里最常见的就是组合逻辑漏了 else 或者 case 没写 default,仿真时恰好没走到那条路径所以看着没事,综合器却给你推出一个锁存器来,上板就飘。另一个高频坑是分频器用组合逻辑去翻时钟,或者拿 always @(posedge clk) 里又去分频出个时钟给别的模块用,仿真能跑,综合后时钟树一塌糊涂。所以准备笔试时,习惯比技巧重要:时序逻辑一律非阻塞,组合一律阻塞且补全分支,时钟只从全局时钟脚进来、用使能或计数器做分频输出,别自己造时钟。你现在的复位是同步还是异步、有没有做同步释放,这决定了面试官下一个问题会往哪问。

  • 芯片设计入门

    我当年也踩过这个坑,说几个笔试到上板之间真实的落差吧。仿真器是理想世界,综合器是现实世界,中间隔着三样东西:不确定的初值、被优化掉的逻辑、以及时钟本身的物理属性。

    第一样,寄存器上电初值在仿真里常常是 x,但很多仿真器默认给 0,你看着波形干净,实际上板时 FPGA 的寄存器初值是确定的但未必是你要的,所以状态机和计数器最好显式复位,别指望 initial 块,那玩意儿综合器多半不认。

    第二样,综合器会砍掉它认为冗余的逻辑。比如你写了个信号只在某个分支里赋值、其他分支没管,仿真时它保持旧值看着对,综合后要么被优化要么变锁存器。反过来,你为了「保险」加的一堆冗余判断也可能被合并掉,时序就变了。

    第三样最容易被笔试忽略:奇数分频。用计数器做 50% 占空比的奇数分频,标准做法是上升沿和下降沿各数一遍再相或,如果你只用单边沿,占空比就不是 50%,仿真波形你可能没仔细量,面试官一眼就看出来。

    替代做法上,其实很多「分频」需求根本不需要真分频,用时钟使能(clock enable)打拍就行,既避免跨时钟域又省 BUFG。笔试时如果你能主动说出「我这里用使能而不是分频」,是加分项。

    建议你把自己写的模块过一遍综合报告,看有没有 latch、有没有被优化的 warning,比反复看波形有用。你笔试时用的是哪家综合工具,报告里 warning 是怎么写的?

  • FPGA新手仔

    把这个问题往深里想,其实是「可综合子集」和「仿真语义」两套规则的错位。Verilog 一开始是仿真语言,很多语法在仿真器里有明确行为,但综合器只认其中一部分,而且对边界情况的处理未必和仿真一致。你仿真对、综合错,本质是踩在了这两套规则的缝隙上。

    缝隙一,赋值语义。always 块里阻塞和非阻塞混用,仿真时因为事件调度顺序,结果可能恰好是你想要的;综合成硬件后,阻塞赋值在同一个块里是顺序执行的组合逻辑,非阻塞是并行的寄存器更新,两者混在一起,仿真器的调度顺序和综合出的电路结构就对不上了。所以规则不是死记的:时序逻辑用非阻塞,是为了让所有寄存器在同一时刻更新,对应硬件的并行翻转;组合逻辑用阻塞,是为了让它像一条表达式链。

    缝隙二,不完整赋值。组合 always 里 if 没 else、case 没 default,仿真时信号保持上一次的值,看起来像「记忆」,综合器为了复现这个记忆行为,只能推断出锁存器。锁存器在 FPGA 里不是不能用,但它对毛刺敏感、时序分析困难,笔试里基本等于扣分。

    缝隙三,时钟处理。用组合逻辑分频、用门控时钟、在 always 里产生时钟,仿真都能跑,但 FPGA 的时钟走专用网络,你造出来的时钟进不了 BUFG,要么被工具报错,要么抖动和偏斜大得没法用。正确姿势是全局时钟进来,分频只产生使能信号,或者用厂商的 MMCM/PLL 原语。

    缝隙四,复位。异步复位同步释放是工程惯例,但笔试里很多人只写异步复位,仿真没问题,实际上板复位释放时刻和时钟沿靠得太近,可能进入亚稳态。这个点面试官很爱问,因为它区分了「会写 Verilog」和「懂数字设计」。

    缝隙五,综合器优化。没被使用的信号、常量传播、状态编码方式都会改变最终电路。比如你用 one-hot 编码写状态机,综合器可能重新编码,仿真波形里的状态值上板就对不上了,所以调试时别盯着状态编码看,要看功能。

    往学习路径上说,我的建议是别把笔试和上板当成两件事。笔试时就用可综合的思维写:每个 always 块问自己「这对应什么电路」,每个信号问自己「它有没有被完整赋值」,每个时钟问自己「它从哪来」。练到形成条件反射,面试时被追问复位、跨时钟域、时序约束,你才有话可说。

    最后补一句取舍:校招笔试时间紧,不必追求每个模块都写得像工程代码,但锁存器、组合分频、混用赋值这三条底线要守住,因为它们是最容易被一眼看穿的。你现在练手是用仿真为主,还是已经有机会上板跑一跑?

  • HelloWorld

    最常见的就是组合逻辑漏分支推出锁存器,仿真时路径没走到所以波形干净,综合后多出个 latch 上板就飘。再就是复位没同步释放、自己用组合逻辑分频出时钟。笔试写的时候直接按可综合风格来,别等面试官挑。你那个奇数分频是打算用上升沿计数还是双沿都数?

  • 电路设计新人

    笔试里最容易被抓的就是组合逻辑漏 else 或 case 没 default,仿真恰好没走到那条路,看着干干净净,综合直接给你推出个 latch,上板就飘。你先回头看看序列检测器里那几个状态译码是不是全分支赋值了。另外奇数分频别用组合逻辑翻时钟,这个是面试官最爱追问的点。你那个分频是打算输出 50% 占空比吗?

  • FPGA探索者

    笔试阶段最容易翻车的是组合逻辑漏分支推出锁存器,以及自己拿组合逻辑去翻时钟。你先确认序列检测的状态译码和输出是不是所有分支都赋值了,分频是不是走的计数器加使能而不是造新时钟。你那个奇数分频是打算要 50% 占空比吗?

  • 电路设计萌新

    先说一个容易被忽略的因果:仿真器和综合器其实在回答两个不同的问题。仿真器问的是『按事件调度,这个 always 块会算出什么值』,综合器问的是『这段代码对应什么电路结构,面积和时序怎么算』。你仿真对,只证明前者成立;面试官说综合后可能有问题,是在问后者。这两个问题的答案在大多数代码里是一致的,但有几类写法会让它们分岔,而校招笔试恰好爱考这几类。

    第一类是组合逻辑的不完整赋值。你写 if 没 else、case 没 default,仿真时因为测试激励没覆盖到那条路径,信号保持旧值,波形看着完全正常;综合器看到的是『所有未覆盖分支下这个信号要保持不变』,那就只能给你一个锁存器。锁存器本身不是错,错在它是电平敏感的、时序分析麻烦、上板容易出毛刺,而且面试官一眼就知道你没按可综合风格写。序列检测器的状态译码和输出逻辑是最容易中招的地方,建议你回头对着每个 always 块数一遍:是不是每个输出在每条路径上都有确定赋值。

    第二类是时钟。分频器如果用组合逻辑去翻时钟,或者在一个 always @(posedge clk) 里生成一个新时钟再送给别的模块,仿真能跑,综合后时钟树会很难看,甚至综合器直接报 warning 说你在用非时钟信号当时钟。奇数分频尤其典型:想要 50% 占空比,标准做法是上升沿数一遍、下降沿数一遍,再把两个信号相或;只用一个沿数,占空比必然不是 50%,仿真波形你可能没仔细量。

    第三类是初值和复位。仿真里寄存器上电常常是 x,有些仿真器默认给 0,你就以为没问题;实际上板时 FPGA 寄存器初值确定,但未必是你要的。状态机和计数器最好显式复位,别指望 initial 块。复位本身还有同步异步、同步释放的问题,面试官很可能顺着往下问。

    准备笔试时的取舍很简单:别追求写法花哨,就按可综合子集来。时序逻辑一律非阻塞,组合逻辑一律阻塞且补全分支,时钟只从全局时钟脚进、分频输出走计数器加使能。你现在的复位是同步还是异步,有没有做同步释放?这个决定了面试官下一个问题会往哪问。

    另外提醒一句,笔试写完别急着交,花两分钟自查:有没有在 always 里混用阻塞和非阻塞,有没有组合逻辑当敏感列表里漏信号,有没有自己造时钟。这三条能挡掉大部分『仿真对综合错』的坑。

  • 嵌入式开发小白

    核心就一句话:仿真器按事件调度算值,综合器按电路结构算面积和时序,你写的东西得让两边理解一致。组合逻辑漏 else、case 没 default,综合器理解成『其他情况保持』,于是给你推出锁存器;分频用组合逻辑翻时钟,综合器理解成你造了个新时钟,时钟树就乱了。所以笔试时直接按可综合风格写,别等面试官挑。你那个奇数分频打算要 50% 占空比吗?

  • EE新生

    我换个角度说:笔试里所谓仿真对、综合不对,本质是你在用仿真器的语义写代码,但面试官在用综合器的语义读代码。这两套语义在大多数写法下重合,重合区就是可综合子集;你要做的是把代码写进重合区里,而不是去研究边界情况。

    顺着这条线推,最容易踩的坑其实有优先级。第一优先级是组合逻辑的不完整赋值,因为它同时触发两个后果:仿真看着对、综合出锁存器。序列检测器的次态译码和输出译码是重灾区,你用了状态机没错,但如果输出逻辑写成 case 只列了部分状态,综合器只能推 latch。第二优先级是时钟,奇数分频如果拿组合逻辑或另一个 always 去翻时钟,综合器会把它当新时钟域,时钟树和时序约束全乱,仿真器根本不关心这个,所以波形永远好看。第三优先级才是复位和初值,仿真里 initial 能给你干净初值,上板寄存器初值由器件决定,状态机不复位就可能从非法态起跑。

    再说取舍。校招准备时间有限,我的建议是把精力压在三件事上:所有时序逻辑非阻塞、所有组合逻辑补全分支、所有时钟只从全局时钟进来用使能分频。这三条覆盖了笔试八成以上的坑,剩下两成交给面试时讲清楚你的复位策略。至于阻塞非阻塞混用、综合器优化冗余逻辑这些,属于知道就行、不必专门花时间演练的边角。

    一个学习路径上的提醒:写完一段代码,别只看波形,试着在心里把它翻译成电路图,问自己这段综合出来是几个触发器、几个多路选择器、有没有意外的保持路径。这个习惯比刷题更能防坑。

    你现在这套序列检测器和分频,复位是同步还是异步,有没有做同步释放?

  • FPGA新手村村民

    你说的这两个题,其实面试官想听的不是「哪里错了」,而是「你知道上板后有哪些东西是仿真器根本不建模的」。我换个维度讲:把仿真到上板之间想象成三道关卡,笔试只考你能不能过第一道。

    第一道是语法与可综合性,也就是锁存器、阻塞非阻塞、组合逻辑翻时钟这些,网上资料最多,你已经查过了。第二道是「复位与初值」这道关,仿真里 initial 和默认 x 帮你兜底,FPGA 上电后寄存器值由器件决定,状态机和计数器如果没显式复位,仿真波形干净不代表上板从合法状态开始,序列检测器一旦跑进未定义状态就可能自己锁死。第三道是「时序与约束」,这是笔试最不考、上板最要命的一关:你仿真时波形周期看着对,是因为仿真器不关心时钟树、不关心建立保持时间,分频出来的信号如果拿去做别的逻辑时钟,上板可能根本没收敛。

    一个我建议你顺手练的小例子:写一个 3 分频,先用计数器加使能的标准写法跑一遍,再故意用组合逻辑翻时钟跑一遍,两版仿真波形几乎一样,但后者你去看综合报告或者布局布线后的时序告警,差别就出来了。这种「同一功能两种写法对比」的练习,比背知识点有用得多。

    替代做法上,笔试时间紧的话,先把可综合子集当成硬约束:组合 always 全分支赋值、时序 always 只用非阻塞、时钟只从顶层端口或 PLL 来、状态机加默认跳转。做到这四条,第二第三道关的坑能躲掉大半。

    你现在是卡在「知道有坑但笔试写不出来」,还是「写出来但说不清为什么」?这两个阶段的练法不太一样。

登录后可在本页底部提交回答

提问者

算法小白查看主页
浏览「其他」

描述场景与已尝试方案,更容易获得有效解答

相关问题

同分类

提问建议

  • 标题写清核心疑问,避免「求助」「请问」等空泛用语
  • 正文补充环境、版本、报错信息或截图
  • 先搜索本站是否已有相近问题,减少重复提问
  • 若与课程相关,请标明课时或章节便于讲师定位