5.1.3 Net and Register
一个reg变量只能在一个always语句中赋值 。
向量有效位顺序的定义一般是从大数到小数。
尽管定义有效位的顺序很自由, 但如果采用毫无规则的定义势必会给作者和读代码的人带来困惑, 如Data[-4 :0] ,则LSB[0][-1][-2][-3][-4]MSB ,或 Data[0 :4] ,则LSB[4][3][2][1][0]MSB, 这两种情况的定义都不太好 ,推荐 Data[4 :0] 这种格式的定义。
对net和register类型的输出要做声明 (在PORT中)。如果一个信号名没做声明 Verilog将假定它为一位宽的wire变量。
线网的多种类型 。寄存器的类型。
5.1.4 Expressions
用括号来表示执行的优先级。尽管操作符本身有优先顺序, 但用括号来表示优先级对读者更清晰, 更有意义。
If ((alpha < beta) && (gamma >= delta)).... 比下面的表达更合意 。
If (alpha < beta && gamma >= delta)...
用一个函数(function)来代替表达式的多次重复
如果代码中发现多次使用一个特殊的表达式 ,那么就用一个函数来代替。这样在以后的版本升级时更便利 ,这种概念在做行为级的代码设计时同样使用 ,经常使用的一组描述可以写到一个任务(task)中 。
5.1.5 IF 语句
向量比较时 比较的向量要相等。
当比较向量时 ,verilog将对位数小的向量做 0 扩展以使它们的长度相匹配 ,它的自动扩展为隐式的。建议采用显示扩展 ,这个规律同样适用于向量同常量的比较。
Reg Abc [7:0]; Reg Bca [3:0]; ......
If (Abc = = {4’b0, Bca})begin .......
If (Abc = = 8’b0) begin
每一个If 都应有一个else 和它相对应。
在做硬件设计时 ,常要求条件为真时执行一种动作而条件为假时执行另一动作,即使认为条件为假不可能发生。没有else可能会使综合出的逻辑和RTL级的逻辑不同。如果条件为假时不进行任何操作,则用一条空语句.
always @(Cond) begin
if (Cond) DataOut <= DataIn;
End // Else 以上语句DataOut会综合成锁存器.
应注意If ..else if ...else if ...else 的优先级
如果变量在If-else 或case 语句中做非完全赋值, 则应给变量一个缺省值 ,即,
V1 = 2’b00; V2 = 2’b00; V3 = 2’b00;
If (a = = b) begin V1 = 2’b01; //V3 is not assigned
V2 = 2’b10;
End Else if (a = = c) begin
V2 = 2’b10; //V1 is not assigned
V3 = 2’b11;
End Else ;;
5.1.6 case 语句
case语句通常综合成一级多路复用器 (图的右边部分), 而if-then-else则综合成优先编码的串接的多个多路复用器, 如图的左边部分。通常 ,使用case 语句要比if语句快 ,优先编码器的结构仅在信号的到达有先后时使用。条件赋值语句也能综合成多路复用器, 而case 语句仿真要比条件赋值语句快。
所有的Case 应该有一个default case 允许空语句 Default : ;
5.1.7 Writing functions
在function的最后给function赋值.
Function CompareVectors; // (Vector1, Vector2, Length)
Input [199:0] Vector1, Vector2;
Input [31:0] Length; //local variables
Integer i;
Reg Equal;
Begin
i = 0;
Equal = 1;
While ((i
If (Vector1[i] !== Vector2[i])
Equal = 0;
Else ;
End
i = i + 1;
End CompareVectors = Equal;
End Endfunction //compareVectors
函数中避免使用全局变量 否则容易引起HDL行为级仿真和门级仿真的差异 如
function ByteCompare input [15:0] Vector1
input [15:0] Vector2 input [7:0] Length begin
if (ByteSel) // compare the upper byte
else // compare the lower byte
end endfunction // ByteCompare 中使用了全局变量ByteSel, 可能无意在别处修改了 ,导致错误结果。最好直接在端口加以定义 。注意 函数与任务的调用均为静态调用。
5.1.8 Assignment
Verilog 支持两种赋值 :过程赋值(procedural) 和连续赋值(continuous)。过程赋值用于过程代码 initial, always, task or function)中给reg 和 integer变量 time ealtimereal赋值, 而连续赋值一般给wire 变量赋值。
Always @(敏感表 敏感表要完整 如果不完整 将会引起仿真和综合结果不一致 always @(d or Clr) if (Clr) q = 1'b0; else if (e) q = d; 以上语句在行为级仿真时e的变化将不会使仿真器进入该进程,导致仿真结果错误
Assign/deassign 仅用于仿真加速 仅对寄存器有用 。
Force/release 仅用于debug 对寄存器和线网均有用 。
避免使用Disable。
对任何reg赋值用非阻塞赋值代替阻塞赋值 reg 的非阻塞赋值要加单位延迟 ,但异步复位可加可不加 。
=与 =的区别
Always @(posedge Clk or negedge Rst_) Begin
If (!Rst_) // prioritize the “if conditions” in if statement
Begin
Rega <= 0; //non_blocking assignment
Regb <= 0;
End Else if (Soft_rst_all)
Begin
Rega <= #u_dly 0; //add unit delay
Regb <= #u_dly 0;
End Else if (Load_init)
Begin
Rega <= #u_dly init_rega;
Regb <= #u_dly init_regb;
End Else Begin
Rega <= #u_dly Rega << 1;
Regb <= #u_dly St_1;
End End // end Rega, Regb assignment.
5.1.9 Combinatorial Vs Sequential Logic
如果一个事件持续几个时钟周期 设计时就用时序逻辑代替组合逻辑 。如
Wire Ct_24_e4; //it ccarries info. Last over several clock cycles
Assign Ct_24_e4 = (count8bit[7:0] >= 8’h24)
& (count8bit[7:0] <= 8’he4); 那么这种设计将综合出两个8 比特的加法器 而且会产生毛刺 对于这样的电路 要采用时序设计 代码如下
Reg Ct_24_e4;
Always @(poseddge Clk or negedge Rst_) Begin
If (!Rst_) Ct_24_e4 <= 1’b0;
Else if (count8bit[7:0] = = 8’he4)
Ct_24_e4 <= #u_dly 1’b0;
Else if (count8bit[7:0] = = 8’h23)
Ct_24_e4 <= #u_dly 1’b1;
Esle ; //内部总线不要悬空 在default状态 要把它上拉或下拉.
Wire OE_default;
Assign OE_default = !(oe1 | oe2 | oe3);
Assign bus[31:0] = oe1 ? Data1[31:0] :
oe2 ? Data2[31:0] :
oe3 ? Data3[31:0] :
oe_default ? 32’h0000_0000 :
32’hzzzz_zzzz;
5.1.10Macros
为了保持代码的可读性 常用 “ `define ” 做常数声明。
把“define”放在一个独立的文件中 参数 parameter 必须在一个模块中定义 不要传替参数到模块 仿真测试向量例外 “define”可以在任何地方定义 要把所有的“define”定义在一个文件中 在编译原代码时首先要把这个文件读入 如果希望宏的作用域仅在一个模块中 就用参数来代替。
5.1.11Comments
对更新的内容更新要做注释。
在语法块的结尾做标记。
//style 1
If (~OE_ && (state != PENDING)) begin .... End // if enable = = ture and ready //style 2 --- identical lables on begin and end
If (~OE_ && (state != PENDING)) begin //drive data
.... End //drive data // Comment end
Function Calcparity //Data, ParityErr .... Endfunction // Calcparity
每一个模块都应在模块开始处做模块级的注释 参考前面标准模块头 。
在模块端口列表中出现的端口信号 都应做简要的功能描述。
5.1.12 FSM
VerilogHDL状态机的状态分配 VerilogHDL描述状态机时必须由parameter分配好状态,这与VHDL不同 VHDL状态机状态可以在综合时分配产生。
组合逻辑和时序逻辑分开用不同的进程。组合逻辑包括状态译码和输出 时序逻辑则是状态寄存器的切换。
必须包括对所有状态都处理 不能出现无法处理的状态 使状态机失控 。
Mealy机的状态和输入有关,而Moore机的状态转换和输入无关。
Mealy 状态机的例子如下:
... reg CurrentState, NextState, Out1;
Parameter S0=0,S1=1; always @(posedge Clk or negedge Rst_) // state vector flip-flops (sequential)
if (!Reset) CurrentState = S0;
else CurrentState <= #u_dly NextState;
always @(In1 or In2 or CurrentState)
// output and state vector decode (combinational)
case (CurrentState)
S0: begin
NextState <= #u_dly S1;
Out1 <= #u_dly 1'b0; end
S1: if (In1) begin
NextState <= #u_dly S0;
Out1 <= #u_dly In2;
end else begin
NextState <= #u_dly S1;
Out1 <= #u_dly !In2;
end
endcase endmodule
编辑:黄飞
评论
查看更多