一、不期待的锁存器出现的原因
1 case语句或if语句中对变量赋值不完整
2 当条件操作符(? : )以反馈的形式实现时
3 对于always语句内部定义的局部变量,如果也是在不完整的条件分支(if或者case)语句中赋值,也会综合出锁存器
4 如果一个局部变量在同一个条件分支中,先被赋值,然后马上被引用,那么就不会为此局部变量综合出锁存器
always @ ( latch or din )begin
reg temp;
if( latch )begin
temp = din;
dout = temp;
end
end
endmoduloe
5 如果一个全局变量在不完整的条件分支语句中,先被引用然后再被赋值,那么会为这个变量综合出锁存器
二、循环语句的综合
对于静态循环语句,如果循环内部的赋值语句之间不存在相互依赖性,则这些语句可以展开为并行执行语句,且语句执行的先后顺序不会影响到最终的结果。
for语句静态循环描述的无符号乘法器,采用移位加的组合逻辑来实现,在时钟频率不太高的情况下乘法器完全可以正常工作。如果系统工作频率很高,那么就得采取别的措施了。从而提高系统运行速度。
module mult(
input [3:0] data1,
input [3:0] data2,
output reg [7:0] dout
);
reg [7:0] temp;
always @ ( data1 or data2 )begin:Lable
integer k;
temp = {4'h0,data1};
dout = 0;
for( k=0;k<4;k=k+1)begin
if( data2[k] ) dout = dout + temp;
temp = temp << 1;
end
end
endmoduloe
非静态循环是指循环的次数是由运算中的某个变量决定,而不是由编译器决定。quartus15与Vivado2017我都用代码尝试了,是可以的。vivado里好像不支持while语句(待验证)。下面是用while语句非静态循环描述的无符号二进制乘法器。不管另一个乘数data2为何值,都要循环移位4次(乘数的数据位宽)。但下边的算法是一旦乘数高位全为0,则整个乘法运算结束。
module ba(
input clk,
input [3:0] data1,
input [3:0] data2,
output reg [7:0] dout,
output reg [2:0] shift_count
);
reg [7:0] data1reg;
reg [7:0] data2reg;
always @ ( posedge clk )begin
data1reg = {4'h0,data1};
data2_reg = data2;
dout = 0;
while( |data2reg )begin
if( data2reg[0] ) dout = dout + data1reg;
data1reg = data1reg << 1;
data2reg = data2reg >> 1;
shift_count = shift_count + 1;
end
end
endmodule
三、阻塞与非阻塞的综合
对于阻塞赋值语句,赋值语句左边的变量在下一条顺序语句执行前进行赋值操作。但是对于非阻塞赋值语句,赋值语句先计算赋值表达式的值,在仿真周期结束的时候将该值赋给左边的变量(所有非阻塞语句同时赋值)。
看下例:
module jichu(
input clk,
input din,
output reg regand,
output reg regor,
output reg regxor
);
always @ ( posedge clk )begin
regxor = regxor ^ din;
regor <= regxor | din;
regand<= regor & din;
end
endmodule
阻塞和非阻塞语句的最主要区别在其后引用它的语句的电路结构上:
对于阻塞语句,其综合出的组合逻辑的输出,被馈送到其后引用它的语句的组合逻辑的输入端,也即后面的语句引用其新值。
对于非阻塞语句,其综合出的触发器的输出,被馈送到其后引用它的语句的组合逻辑的输入端,也即后面的语句引用其旧值。
在边沿敏感周期行为always顺序块中使用阻塞、非阻塞赋值语句,只对其后引用其值的语句产生影响。不管是阻塞还是非阻塞赋值语句,若在该语句之前对其值(除纯粹的临时变量)进行引用,则只能引用其上个时钟周期赋予的旧值。在边沿敏感的周期行为always块语句中,若变量被某条语句引用上个时钟周期赋的值(旧值),则该变量综合出的触发器的输出端被馈送到引用它的语句的输入端;若变量被某条语句引用当前时钟周期赋的值(新值),则该变量综合出的组合逻辑的输出端被馈送到引用它的语句的输入端。
四、函数的综合
在verilog hdl语句中,函数代表了纯组合逻辑。函数综合的时候,被展开成了内联的代码。任何在函数中定义的局部变量都被当做纯粹的临时变量,仅被综合成导线。
下面给出了一个函数的实例,函数Parity完成对输入数据的奇偶检验,若1的个数为1为奇数则输出1,否则输出为0。
module top(
input [3:0] datain,
output wire odd_even
);
function Parity;
input [3:0] din;
integer i;
begin
Parity = 0;
for( i=0;i<4;i=i+1)
if(din[i]) Parity = Parity+1;
end
endfunction
assign odd_even = Parity(datain);
endmodule
在上例中,函数Parity被综合工具展开成内联的代码,具有如下形式:
Parity = 0;
if( Din[0] ) Parity = Parity + 1;
if( Din[1] ) Parity = Parity + 1;
if( Din[2] ) Parity = Parity + 1;
if( Din[3] ) Parity = Parity + 1;
五、任务的综合
任务既可以用来表示组合逻辑也可以表示时序逻辑。例如,任务在边沿敏感周期行为always语句中被调用,则任务的输出参数被综合成触发器。与函数调用类似,任务调用在综合在综合时也会被展开成内联的代码,所以不会为其保留层次结构(hierarchy)。
下例给出了任务调用实例,任务BitXOR完成了俩个4位二进制数的按位异或运算。因为任务在钟控的always语句中被调用,所以其输出参数被综合成触发器,代表了时序逻辑。
module TaskApp(
input clk,
input [3:0] A,
input [3:0] B,
output reg [3:0] DataOut
);
task BitXor;
input [3:0] Din1,Din2;
output [3:0] Dout;
integer i;
begin
for( i=0;i<=3;i=i+1 )
Dout[i] = Din1[i]^Din2[i];
end
endtask
always @ ( posedge clk )
BitXor(A,B,DataOut);
endmodule
上例中的任务在综合时被展开成如下的内联代码:
DataOut[0] = A[0]^B[0];
DataOut[1] = A[1]^B[1];
DataOut[2] = A[2]^B[2];
DataOut[3] = A[3]^B[3];
六、case相关
generate用法
为什么有generate语句?
在设计中,很多情况下需要编写很多结构相同但是参数不同的赋值语句或者逻辑语句,如果在参数量很大的的情况下,原本的列举就会显得心有余而力不足。c语言中常用for语句来解决此类问题,verilog则为我们提供了generate语句。
generate语句允许细化时间(Elaboration-time)的选取或者某些语句的重复。这些语句可以包括模块实例引用的语句、连续赋值语句、always语句、initial语句和门级实例引用语句等。细化时间是指仿真开始前的一个阶段,此时所有的设计模块已经被链接到一起,并完成层次的引用。
可以使用在generate语句中的类型主要有:
module(模块)
UDP(用户自定义原语)
门级原语
连续赋值语句
initial或always语句
基本结构
genvar 循环变量名;
generate
// generate循环语句
// generate 条件语句
// generate 分支语句
// 嵌套的generate语句
endgenerate
定义genvar,作为generate中的循环变量。
generate语句中定义的for语句,必须要有begin,为后续增加标签做准备。
begin必须要有名称,也就是必须要有标签,因为标签会作为generate循环的实例名称。(IEEE SV 2017原文说可以不加标签,那样就不能层次化的方式引用,只有一句的循环体可不加begin-end! Generate blocks in loop generate constructs can be named or unnamed, and they can consist of only one item, which need not be surrounded by begin-end keywords.)
generate-loop循环语句
generate-conditional条件语句
generate允许对语句进行条件选择,即将条件选择加入到generate中的for循环中,只例化条件成立时对应的语句或者module。generate-if中的条件只能是静态变量,如 genvar,parameter 等,可以这样想,Verilog是要综合为固定的硬件电路的,不能因为条件不同而综合的电路结构变化,所以静态变量才能保证电路结构相同。
generate-case分支语句
generate-case分支语句与generate-条件语句类似,只不过将原来的分支语句换做了case语句。
参考 https://blog.csdn.net/weixin_44544687/article/details/107793235?