本帖最后由 mdykj33 于 2015-11-21 09:35 编辑
5.3 组合逻辑组合逻辑一般可以分成三类:门级逻辑、选择器和比较器、运算逻辑等。 5.2.1组合逻辑verilog代码Verilog的程序代码,组合逻辑的代码结构如下: always@(*) begin 代码语句; end
或者是assign 代码语句;
代码中@后是敏感列表,当括号内的条件满足时,就执行一次。括号内的“*”,表示代码语句中所有信号有变化。结合起来就是:当代码语句中的信号有变化时,就执行一次。这与组合逻辑 电路的功能是对应的。组合逻辑也是信号变化,输出立刻变化。 有很多代码的敏感列表里列出所有信号,如always@(a or b or c),建议不要这样写,容易把信号给遗漏,从而导致不希望的电路出现。 明德扬建议初学者前面章节中不要用assign语句,这样全部代码都是always结构。
5.2.2 门级逻辑 分类 | | | | | | | | | reg A,B; always@(*)begin B=A; end |
|
| | | reg[3:0] A,B; always@(*)begin B=A; end |
| 当A和B是n位时,实际就有n根线。但为看图方便,我们通常只画出一根线表示 | | | reg[3:0] A; reg[2:0] B; always@(*)begin B=A>>2; end |
| | | | reg[3:0] A; reg[2:0] B; always@(*)begin B={A[2],A[3],A[0]}; end |
| | | | | reg A,B; always@(*)begin B=~A; end |
|
| | | reg[1:0] A,B; always@(*)begin B=~A; end |
| 如果A和B都是n位,实际电路就是有n个反相器。画电路图时可画一个来简化。 | | | | reg A,B; always@(*)begin C=A&&B; end |
| 注意:FPGA支持多输入的与门,例如四输入与门,输入可为ABCD ,输出为E ,当ABCD 同时为1 时,E 为1 | | | reg[2:0] A,B,C; always@(*)begin C=A&&B; end |
| 多位信号之间的逻辑与,很容易引起歧义,设计最好不要用多位数的逻辑与。如果要实现上面功能,建议代码改为如下: always@(*)begin C=(A!=0)&&(B!=0); end
| | | reg[2:0] A,B,C; always@(*)begin C=A&B; end |
|
| | | reg[2:0] A; always@(*)begin C=&A; end |
|
| | | | reg A,B; always@(*)begin C=A||B; end |
| 注意:FPGA支持多输入的与门,例如四输入与门,输入可为ABCD,输出为E,当ABCD同时为1时,E为1 | | | reg[2:0] A,B,C; always@(*)begin C=A||B; end |
| 多位信号之间的逻辑或,很容易引起歧义。最好不要用多位的逻辑或。如果要实现相同功能,建议改为如下: always@(*)begin C=(A!=0)&&(B!=0); end
| | | reg[2:0] A,B,C; always@(*)begin C=A&B; end |
|
| | | reg[2:0] A; always@(*)begin C=&A; end |
|
|
此外还有同或门、与非门、或非门等等,但画电路图时比较少用。同学们需要记清楚上述电路示意图,这是后面画图练习的基础。
5.2.3选择器和比较器 分类 | | | | | | | | | always@(*)begin case(S) 2’b00 : C=D0; 2’b01 : C=D1; 2’b10 : C=D2; default : C= D3; endcase |
|
| | | always@(*)begin C = D[S]; endcase |
| | | | always@(*)begin if(S==0) C=D0; else if(S==2’b01) C=D1; else C=D2; end |
| 请注意此处用到了相等比较器和选择器。请掌握这种if else代码的画法。 | | | | always@(*)begin if(A==B) C=1; else C=0; end |
|
| | | always@(*)begin if(A>B) C=1; else C=0; end |
|
| | | always@(*)begin if(A>=B) C=1; else C=0; end |
|
| | | |
|
| | | always@(*)begin if(A<=B) C=1; else C=0; end |
|
|
5.2.4运算逻辑 日常生活中,最常用的运算逻辑是加、减、乘、除、求余。FPGA也有对应的加(+)、减(-)、乘(*)、除(/)、求余(%)的运算符。 分类 | | | | | | | always@(*)begin C =A+B; endcase |
| 本质上,运算逻辑都是由与门、或门等门逻辑搭建起来的电路,例如1位的加法就是S= A ^B;Cout= A&&B。
| | | always@(*)begin C =A-B; endcase |
| | | always@(*)begin C =A*B; endcase |
| 在二进制运算中,乘法运算实质上就是加法运算,例如1111*111 = (1111) + (11110) +(111100)。所以乘法器会比加法器消耗的资源多。 | | | always@(*)begin C =A/B; endcase |
| 二进制运算中,除法和求余涉及到加法、减法和移位等运算,所以除法和求余电路资源都非常大,在设计时要尽力避免除法和求余。如果一定要用到除法,尽量让除数为2的n次方,如2,4,8,16等。因为a/2实质就是a向右移1位;a/4实质就是a向右移2位。移位运算是不消耗资源的。 | | | always@(*)begin C =A%B; endcase |
|
更加复杂的运算逻辑,如LOG、SIN、COS等,是没有直接电路对应的,一般是调IP核,或者自己设计。 总结 1. 电路示意图是画电路的基础,同学们务必能根据代码画出电路示意图。 2. 注意如果信号是多位的,但示意图一般画1位,但我们应该清楚示意图背后表示的位数。位数越多,其资源肯定越大。 3. 代码和电路是一一对应的。我们编写的代码,一定要求有电路对应,没有电路对应的代码,即使编写出来也没用。 4. 以上是列出的常用电路,是可以直接综合的。我们就是以上面电路为基础,像搭积木一样,搭建起整个项目。
以上文章出自明德扬点拨FPGA高手进阶,版权归明德扬所有,如需转载,请注明明德扬,谢谢!
|