芯片实现码代码的部分

电子说

1.3w人已加入

描述

 

0 绪论

经过了上篇文章的文档设计,我们这一章开始写代码。码代码这个问题确实是一个必备技能,任何设计不会码代码其实无法实现的。

这块儿流程上包括了两个东西。第一个码代码,第二个是一些必要的代码检查,保证代码不会出现什么歧义导致实现结果和设计意图不一致。具体语法我们就不在这一章讲了,写出来也是千篇一律,此处就简单讲讲HDL的简介,同时讲一下如何提高编码质量,供大家参考。然后简单讲一个代码写完必要的检查工序spyglass检查,这个工具可以避免大部分低级BUG。

代码

 

1 码代码

代码

1.1 HDL简介

此处的代码主要指的是HDL, hardware design language, 最主流的只有一种:Verilog,以及它的衍生品system verilog。其实还有两种语言,VHDL,属于它的时代已经过去了, 还有一种Chisel为代表的高级语言,属于它的时代似乎还没到来。所以我们这个地方重点讲讲verilog。

verilog 1983年被gateway设计,1990年gateway被candance收购。然后90年代出了第一个标准Verilog-95,定义了最原始的语法。直到现在,部分公司还是只允许使用95中的特性。2001年公布新一代标准,verilog-2001, 这一代标准中加入了generate, 多维数组等等实用的语法,现在是verilog使用最主流的标准,基本上所有的软件工具链都支持该标准,后续verilog更新了一代标准verilog2005, 不过这一代标准开始向着一个独立的方向演变,最后被合并到了systemverilog 2009。system verilog中提供了interface等等一系列面向对象的方法,已经广泛被验证支持了,但是在设计实现中只被支持了少部分特性。具体什么特性允许使用其实各个公司都有自己的看法与标准,你需要注意一下公司的编码标准。从我个人的观点来看,如果确认新特性没问题最好用新特性,减少工作量的同时还能避免代码出低级错误。

verilog代码长这样。下面实现了一个十进制的计数器。

代码

1.2 编码质量

Verilog其实不是一个很难的语言,但是由于比较落后,编码质量很多需要人为来注意。编码质量主要就是两个方面考虑。容易出错的点以及提高后续步骤效率的点。常见容易出错的点大家应该都懂,此处简单总结了一下我觉得需要了解又容易被忽略的点,欢迎大家补充。

1.2.1 容易出错的点

·命名有意义,代码有注释。这个任何编程语言都需要注意,我把它列在第一点,这是一个码农最起码的素质。即可以避免自己出错,又可以避免接手代码的人一头雾水。我也看过不少代码没注释,命名还全是tmp1 tmp2 tmp3, 最后结局只能是自己重写。

·信号不要以Reg以及数字结尾。这个点很容易被忽略,综合时会自动给信号加上reg, 到时候就没办法区分是你写的,还是自动生成的,非要标识这是个寄存器可以用ff结尾。同时,如果多组信号不要命名为xx1,xx2, 这么做非常容易和xx[1]混淆,建议改成xxa, xxb。

·敏感列表用*,不要用具体的信号。always实现组合逻辑的时候一个敏感列表always @(列表),这个列表直接用*,让综合去自动填敏感列表,把信号写进去非常容易出错。

·少用magic numer。设计的时候好多时候需要用到参数,比如fifo的深度,这种东西尽量用参数表示出来,不同地方引用一个参数,否则非常容易出现不一致的情况。

·不要生产latch。latch指的是没有锁存的寄存,生成latch会产生毛刺,所以非必要不允许使用latch。之所以产生latch其原理是你实现了组合逻辑,但是某个周期某个变量值没有发生变化。所以牢记规律,时序逻辑值可以不变,但组合逻辑必须每个周期都赋值。具体点讲,实现组合逻的时候,case必须有default, if必须有else。

·不要生产组合逻辑环。组合逻辑环指的是同周期A变化的条件是B,而B变化依赖于A。相当于软件中的死循环。功能上就不可能正确,所以设计的时候要记得避免组合逻辑环。

·异步信号不要直接打拍。异步信号需要特别注意。在详设的时候应该就要考虑清楚怎么处理。是用多级打拍,DMUX,异步FIFO等等办法,总之,不能当做同步信号给直接处理了,否则必出错。

1.2.2 提高后续效率需要注意的点

·尽量一个模块用一个时钟域。主要是为了后端设计起来比较方便,CTS步骤(见后续文章)较容易。

·大的模块最好reg in和reg out。可以最大程度上避免后端时序上出问题。因为后端模块与模块之间不一定是按着放的,寄存器输出寄存器输入留出足够的时间余量。

·不可综合的与可综合的代码分模块。设计代码的时候有时候可能会用到SRAM cell, 或者其他硬核IP,再或者designware IP。这些东西最好单独封装模块调用。主要是为了后续代码可能会用FPGA或者emulation验证,不可综合的部件直接替换成逻辑版本。

码代码部分内容大致就是这些。其实也不必压力太大,因为代码写出来是要经过多轮工具检查的。尤其经过下面讲的spyglass检查后,想出错也没有那么容易(当然,一旦出错就是非常隐蔽的错误,可能流片后都没发现Orz)

 

2 Spyglass检查

码完代码,其实我们有一个非常强力的工具可以避免大部分低级错误。这个工具应该是synopsys公司出的。这个工具的GUI长这样。

代码

最主要检查的东西应该有两个,lint检查一些常用的语法错误,CDC (Clock Domain Crossing )检查异步的处理是不是有问题。

代码

lint会检查出所有等号左右位宽不匹配、组合逻辑环、生成了latch, 端口连接不对等等问题。基本上常见的错误都会报出来,一般它会采用宁可错杀不会放过的策略。所以此处会爆出一大堆的错误,需要逐个check一下有没有问题。当然,好多问题也是可以waive掉的,但必须每个waive都要十分确定能不能waive掉。比如计数器,一般计数器到溢出就自动回环了,这种时候lint就会爆出错,你就要检查一下是不是真的要让计数器回环。一般spygalss给你报的错分为四类,fatel, error, warning, info。其中fatel和error是一定不能有的, 有了必然不让你拿去流片,warning可以适当waive,info大多不用管。

CDC会检查异步问题。主要检查是不是所有跨时钟域的信号经过了同步,如果spyglass没检查到跨时钟域的信号没有经过多级打拍或者dmux同步会报错。再比如A时钟域的两个信号同步到了B时钟域,然后合并了,这个时候也会报错,因为这两个信号同步过去以后时序可能会发生变化,要仔细检查。再比如要同步的信号不是寄存器输出的,这种情况由于存在毛刺风险,会增大亚稳态的概率,所以也会报出来。总之, 你能想到的错误基本上都会检查出来。

本部分主要简单介绍了编码完后要用到的最重要的工具之一spyglass。实际使用的时候确实也要有一定的经验积累,什么问题可以waive掉,什么问题必须改。没必要所有问题都改掉,耗费的精力实在是太大,但真的存在风险的问题必须改掉,否则就可能搞出大事儿。。。

 

3 总结

本节我们讲了芯片实现码代码的部分。主要就是verilog以及后续的检查。芯片流片是一锤子买卖,所以一定要保证写的代码不出错,一方面,在本节讲的编码阶段要尽量少写bug, 另一方面,要经过缜密的验证,最大程度上拦截BUG。

审核编辑 :李倩

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分