既然如此,分数高低的意义就只是将别人踩在脚下或被别人踩在脚下罢了。
——《那些年,我们一起追的女孩》
有句电影台词说得好:“人生本来就有很多事是徒劳无功的,但是我们还是依然要经历。”
一个胖大老和尚说这种小清新的话,估计列位的鸡皮疙瘩掉了几斤吧!实属无奈啊,这一讲的内容,真正做设计的读者估计一辈子都不会用到,着实属于老衲经常骂的屠龙之技。这类东西听着很炫,但是大家到底去哪里能找到一条龙来屠呢?玄幻小说里不少,可是钻不进去啊。但是又怕哪位听众遇到哪位头脑贵恙的面试者,问到这个方面的内容。面试的时候,张飞抓耗子——大眼瞪小眼,总是很尴尬的。真心不排除有些BT(变态)的面试官喜欢炫技的。
想当年,老僧面试C语言程序员时,就被问过那个著名的“用一条语句交换变量a和b的数值”的题目。看清楚,是“一条语句”而不是“不用中间变量”啊!依稀记得老师抄了洋洋洒洒半黑板的字符,对错到目前还不得而知,估计也没人会去验证一下。遇到这种面试题目,老僧的态度是:某家还是回小木庵练秋风功好了。
很多刚毕业的娃儿们,甚至都没有小木庵这个保底的去处。为了贵人们的前途,老僧硬着头皮讲讲这些闲篇,有面试需要时施主们也姑且看看。这叫作:“有备无患,既来之则安之。”(为难得老衲现在已经语无伦次了,该死的道士去哪里了?晓得这个难讲就尿遁啊,狡猾狡猾的!哎,拼得挨了一身剐,敢把皇帝拉下马;舍得这张老脸皮,敢讲开关级电路。豁出去了……)
正式宣布:以下内容为冷知识,只学习逻辑实现的听众朋友可以选择绕行,门票概不退还,广而告之。
随便打开一本《数字电子技术》的教材(顺道说一句,听本套评书,最好身边必带一本《数字电子技术》教科书,时不时需要看看的),看个热闹,图2.2是一个用晶体管实现与门的例子。这么简单的与门,不算供电和数字地还用掉了5个元器件,更何况其他更加复杂的功能乎?
图2.2 与门的晶体管电路
能够在低抽象级别对电路进行描述是 Verilog 的一个重要特点。Verilog 中提供了多种开关级(也称晶体管级)元件类型,包括N型金属氧化物半导体场效应管(关键字为nmos)、P型金属氧化物半导体场效应管(关键字为pmos)、互补式金属氧化物半导体(关键字为cmos)、带阻抗的互补式金属氧化物半导体(关键字为rcmos)、电源单元(关键字为supply1)、接地单元(关键字为supply0)等。所有的晶体管都可以设置延迟属性。设计人员可以利用这些低抽象级元件构建所需要的逻辑门或直接构成其他高级组件。
表2.2是与开关级设计有关的Verilog关键词的一个总结,供大家参考(其中很多老衲理解也不深,不用一秒,吾就做下了一个决定:讲完这一讲没有答疑时间了,立即某遁!)。
表2.2 与开关级设计有关的Verilog关键词
毋庸置疑,开关级设计是直接的集成电路生产的参考,那么为什么老衲说这是屠龙呢?很简单,看看有关集成电路规模的划分及现在集成电路的发展,一个IC里存在100 001~10M(1 M=1 000,000)个晶体管都算小的了。冷知识里的冷知识:一个酷睿TM i7-4960X包含18.6亿个晶体管,就连早期的8086里也有4万个晶体管。这么多个晶体管的行为都写成代码,估计要以太空为纸了,不大靠谱的感觉。
如果说开关级是海平面0米,在这里连个蚂蚁都看得见;则门级就是在海拔100米悬停了,虽然看不到蚂蚁,但是基本的电路情况还是非常清楚的。各位听众朋友们,我们现在就悬停在100米的高度给大家直播集成电路的样子。
还是先看看图2.3的热闹,题目是:如何用门电路实现D锁存器(Latch)。至于什么是锁存器,包括关联的触发器什么的概念,《数字电子技术》里讲过。本书的后面也会介绍,这里读者看个结构,领会精神就好。
图2.3 D锁存器的门电路
逻辑门级描述的抽象级别较低,仅次于晶体管级。实际的硬件电路往往都是以逻辑门级网表作为基础构建的,而设计人员常常会再进行更高抽象级别的设计。尽管如此,逻辑门级的设计还是更接近真实电路形式。Verilog提供了一系列逻辑门原语(Primitive)供用户使用,如非(not)、与门(and)、或门(or)、与非门(nand)、或非(nor)、异或(xor)、同或(xnor)。逻辑门原语和模块类似,可以通过实例引用的方式使用。
表2.3是与门级设计有关的Verilog关键词的一个总结,供大家参考(对于这些大家可尽管提问,吾将知无不言,言无不尽)。
表2.3 与门级设计有关的Verilog关键词
在表2.3里,输入门、扇出门应该是大家耳熟能详的。三态门大家也应该知道,即使不了解下文书讲到Verilog语言的值域时也会介绍。此外,pulldown、pullup分别为下拉、上拉电阻。在数字电路中,上拉电阻(Pull-up resistors)是当某输入端口未连接设备或处于高阻抗的情况下,一种用于保证输入信号为预期逻辑电平的电阻元件,通常在不同的逻辑器件之间工作,提供一定的电压信号。同样的,一个下拉电阻(Pull-down resistor)以类似的方式工作,不过是与地(GND)连接。它可以使逻辑信号保持在接近0伏特的状态,即使没有活动的设备连接在其引脚上。有关它们功能、用途等的详细介绍,可以参考网页:http://www.seattlerobotics.org/encoder/mar97/basics.html。
真实的硬件电路,不可避免地都存在延迟现象。在Verilog语言中,可以对逻辑门、晶体管这些元件的延迟信息进行描述;可以为元件的延迟指定一个时间,则上升、下降、关断的延迟都使用这个时间;也可以按照先后顺序分别指定上升延迟、下降延迟,而关断延迟取两者中的较小值;当然,也可以为上升、下降、关断各指定一个时间。例如,下面的代码为与门实例添加了三个延迟时间,分别对应上升、下降、关断:
and #(1,2,3)my_and(out,in1,in2);
在实际工程设计中,这些时间的数值是依赖于集成电路的生产工艺的,需要由生产厂家提供。
逻辑门和晶体管的延迟属于“惯性延迟”。它的意思是,逻辑门和晶体管获得外部输入之后,延迟指定的时间后,才会将结果呈现在输出端上。在延迟期间,如果输入改变,但是这个信号的持续时间小于指定延迟的时间,则不会影响逻辑门和晶体管的输出;如果这个信号的持续时间大于指定延迟的时间,则之前的结果将不会呈现在输出端,改变输入信号后的结果将经过延迟后呈现在输出端。
在实际设计过程中,门级设计也会出现类似开关级设计的规模过大的问题,因此一般不被普遍使用。
本高僧已经系上了安全带,飞机将以近乎90度上升到行为层的上层——用户自定义原语(UDP)。这里绝对属于不可综合的领域了,也即接近航空(设计)与航天(仿真验证)的边沿,空气稀薄需要自带氧气。
Verilog语言,除了系统提供的逻辑门、晶体管原语外,也提供用户自定义原语。UDP倒是符合上一会书说的只描述行为、不描述电路细节的,所谓美国军方的要求。但是,现在这个东西主要被应用于系统链接的外围芯片的行为描述,至少老夫看到的是这样的。不过话说回来,老衲与美军也没什么交集,不知道别人是不是玩这个。
闲言少叙,原语与模块的层次结构类似,但是原语的输入/输出关系是完全通过查表实现的。组合逻辑用户自定义原语的核心是真值表,时序逻辑的用户自定义原语的核心是激励表。设计人员需要在状态表中罗列可能出现的输入和输出情况。如果在实际使用过程中,遇到状态表中没有定义的情况,则输出不确定值 x。使用自定义原语很直观,但是如果输入变量较多,状态表就会变得很复杂。在很多情况中,用户自定义原语并不能被逻辑综合工具转换。
UDP里专用的关键词有table、endtable、primitive、endprimitive、r、f、p、n。其中,table /endtable 是查找表、真值表及激励表的“表”的开始和结束意思;primitive /endprimitive是原语的开始和结束;其他四个字母则是对数字信号沿的表示。其他有关内容还有Verilog的四个值域表示,这个后文书将会详细介绍。有关UDP模块内电平等的含义见表2.4(完全翻译的IEEE协议的有关内容,大家见笑了)。
表2.4 UDP内的电平/沿表示
顺便抄写标准里组合逻辑(1位选择器)和时序逻辑(SR锁存器)的以下例子给大家,大家还是看看热闹即可,估计极少数人会真的自己写这个UDP的。
【例2.1】1位选择器
primitive multiplexer(mux,control,dataA,dataB);
output mux;
input control,dataA,dataB;
table
//controldataAdataBmux
0 1 0: 1 ;
0 1 1 :1 ;
0 1 x :1 ;
0 0 0 :0 ;
0 0 1 :0 ;
0 0 x :0 ;
1 0 1 :1 ;
1 1 1 :1 ;
1 x 1 :1 ;
1 0 0 :0 ;
1 1 0 :0 ;
1 x 0 :0 ;
x 0 0 :0 ;
x 1 1 :1 ;
endtable
endprimitive
需要强调一下,输入与输出之间用“:”隔离;输入、输出信号的顺序严格按照程序定义书写。
【例2.2】SR锁存器
primitive srff(q,s,r);
output q; reg q;
input s,r;
initial q=1'b1;
table
//s rqq+
1 0 : ? : 1 ;
f 0 : 1 :-;
0 r : ? : 0 ;
0 f : 0 :-;
1 1 : ? : 0 ;
endtable
endprimitive
需要强调一下,输入与输出之间用“:”隔离;输出的当前状态q和下一个时刻的输出状态q+也用“:”(在一个时钟节拍之后q变化为q+);隔离输入、输出信号的顺序严格按照程序定义书写。还有就是initial赋初值(这个后文书也会详细介绍,在此请忽略)是为了仿真验证使用的。
还有很多细节没有介绍,真的到了要用的时候,切勿忘了好好阅读标准。一生气,光在那里站着骂老衲,是于事无补的(了不起某家打几个喷嚏。“阿嚏!这是谁?!”)。
这正是:
“底层协议涉猎广,从门进入三极管。芯片规模摩尔律,设计文档装轮船。设计电路有版权,用户原语来保全。上面皆属屠龙术,劝君牛角莫要钻。”