5.2 代码编写中容易出现的问题
for (i=0;i<4;i=i+1) begin Sig1 = Sig2; DataOut[i] = DataIn[i]; end
for-loop中第一条语句始终不变,浪费运算时间.
z = (cond) ? (a + b) : (c + d);
必须使用两个加法器; 而等效的条件if-then-else语句则可以资源共享 如
if (Cond) z = a + b; else z = c + d;
只要加法器的输入端复用,就可以实现加法器的共享,使用一个加法器实现。
module COUNT (AndBits, Clk, Rst); Output Andbits; Input Clk, Rst; Reg AndBits; //internal reg Reg [2:0] Count; always @(posedge Clk) begin begin if (Rst) Count <= #u_dly 0; else Count <= #u_dly Count + 1; End //end if AndBits <= #u_dly & Count; End //end always endmodule
在进程里的变量都综合成触发器了,有4个;
module COUNT (AndBits, Clk, Rst); Output AndBits; Input Clk, Rst; Reg AndBits; //internal reg Reg [2:0] Count; always @(posedge Clk) begin //synchronous if (Rst) Count <= #u_dly 0; else Count <= #u_dly Count + 1; End //end always always @(Count) begin //asynchronous AndBits = & Count; End //end always Endmodule //end COUNT
组合逻辑单开,只有3个触发器.
module COUNT (Z, Enable, Clk, Rst); Output [2:0] Z; Input Rst, Enable, Clk; reg [2:0] Z; always @(posedge Clk) begin if (Rst) begin Z <= #u_dly 1'b0; end else if (Enable == 1'b1) begin If (Z == 3'd7) begin Z <= #u_dly 1'b0; End else begin Z <= #u_dly Z + 1'b1; end End Else ; End //end always Endmodule //end COUNT
是同步逻辑,而下例则使用了组合逻辑作时钟,以及异步复位.实际的运用中要加以避免.
module COUNT (Z, Enable, Clk, Rst); Output [2:0] Z; Input Rst, Enable, Clk; Reg [2:0] Z; //internal wire wire GATED_Clk = Clk & Enable; always @(posedge GATED_Clk or posedge Rst) begin if (Rst) begin Z <= #u_dly 1'b0; end else begin if (Z == 3'd7) begin Z <= #u_dly 1'b0; end else begin Z <= #u_dly Z + 1'b1; end End //end if End //end always Endmodule //end module
c = a &b; 等效于 c[3:0] = a[3:0] & b[3:0]; 等效于 c[3] = a[3] & b[3]; c[2] = a[2] & b[2]; c[1] = a[1] & b[1]; c[0] = a[0] & b[0]; 等效于 for ( i=0; i<=3; i = i + 1) c[i] = a[i] & b[i];可以选择简洁的写法.
always @(Cond) begin if (Cond) DataOut <= DataIn end
使用门控时钟(Gated clock)不利于移植 ,可能引起毛刺, 带来时序问题 ,同时对扫描链的形成带来问题。门控钟在低功耗设计中要用到 ,但通常不要在模块级代码中使用 。可以借助于Power compiler来生成 ,或者在顶层产生。
在设计中最好使用同步设计。如果要使用内部时钟 ,可以考虑使用多个时钟。因为使用内部时钟的电路要加到扫描链中比较麻烦,降低了可测性, 也不利于使用约束条件来综合。
模块中所有的寄存器最好同时复位。如果要使用内部复位, 最好将其相关逻辑放在单独的模块中, 这样可以提高可阅读性。
将这些信号的产生放在顶层的一个独立模块, 这样所有的子模块分别使用单一的时钟和复位信号。一般情况下内部门控时钟可以用同步置数替代。
/* *\ Filename ﹕ Author ﹕ Description ﹕ Called by ﹕ Revision History ﹕mm/dd/yy Revision 1.0 Email ﹕ M@sz.huawei.com.cn Company ﹕ Huawei Technology .Inc Copyright(c) 1999, Huawei Technology Inc, All right reserved \* */ Module module_name( Output_ports, //comment ; port description Input_ports, //comment ; port description Io_ports, //comment ; port descripttion Clk_port, //comment ; port description Rst_port //comment ; port description ); //port declarations Output [31:;0] Dataout; Input [31:0] Datain; Inout Bi_dir_signal; Input input1, Input2; //interrnal wire/reg declarations Wire [31:0] internal_data; Reg output_enable; //module instantiations , Self-build module Module_name1 Uinstance_name1(...); Module_name2 Uinstance_name2(...); // TSC4000 cell DTC12 V1 (.Clk(Clk), .CLRZ(Clr), .D(Data), .Q(Qout)); //continuous assignment Assign Data_out = out_enable ? Internal_data : 32’hz; //always block Always @(input2) Begin ... End //function and task definitions Functiom [function_type] function_name; Declarations_of_inputs; [declarations_of_local_variables]; Begin Behavirol_statement; Function_name = function_express; End Endfunction //end function_name Endmodule //end module_name
下面是一个格雷码的测试模块, module TB_GRAY; reg Clock; reg Reset; wire [7:0] Qout; integer fout; //输出文件指针 parameter CYC = 20; GRAY DUT(.Clock(Clock),.Reset(Reset),.Qout(Qout)); initial begin Clock = 1'b0; Reset =1'b1; #(5*CYC) Reset = 1'b0; #(5*CYC) Reset = 1'b1; #(5000*CYC) $fclose(fout); $finish; end initial begin $shm_open("GRAY.shm"); $shm_probe("AS"); fout=$fopen("gray.dat"); end always #CYC Clock = ~ Clock; //输出数据到文件gray.dat always @(posedge Clock) begin $fwrite(fout,"%d %b\n",Qout,Qout); end endmodule
在testbench中避免使用绝对的时间,如#20,#15或#(CYC+15)等,应该在文件前面使用parameter定义一些常量,使得时间的定义象#(CYC+OFF0)的形式,便于修改。
观测结果可以输出到波形文件GRAY.shm ,或数据文件gray.dat 。生成波形文件可以用simwave观测结果 ,比较直观。而生成数据文件则既可以快速定位 ,也可以通过编写的小程序工具对它进行进一步的处理。
对大的设计的顶层仿真 ,一般不要对所有信号跟踪, 波形文件会很大, 仿真时间延长,可以有选择的观测一些信号。