当前位置:首页 > 工业控制 > 电子设计自动化
[导读]随着集成电路制造技术的发展,对设计提出了更多的挑战,随着设计复杂度的增加,又提出了片上系统(SoC)的概念。为了加速设计收敛,设计重用、可测性设计、可验证性设计和可维护性设计得到了更多重视。本文以VerilogHD

随着集成电路制造技术的发展,对设计提出了更多的挑战,随着设计复杂度的增加,又提出了片上系统(SoC)的概念。为了加速设计收敛,设计重用、可测性设计、可验证性设计和可维护性设计得到了更多重视。本文以VerilogHDL为例,对可维护性设计进行了初步探讨。

1、设计重用与可维护性设计

设计重用是一个很大的概念,严格来讲,可验证性设计和可维护性设计都在设计重用之列。可维护性设计的目的本身就是便于设计重用,便于让后来人读懂前人所写的代码,但设计重用包括的内容更广泛。

设计重用讲的是设计总体风格而不是设计的细节,“it is about forests, rather than trees”。最重要的概念:本地化(locality)――一定要尽量使问题本地化,这样有利于问题的排除。对于大的设计尤为重要。

三条基本原则

尽量采用全同步设计,将输入和输出寄存,这样有利于将时序优化本地化

采用bottom-up验证方法,保证每个子模块的功能是正确的,然后再进行整体验证。

花时间设计一个好的设计规范,力图使这样的规范具有好的体系结构和模块划分,这样有利于本地化的有效实现。

一个好的设计应该包括:完备的文档、好风格的代码、详尽的注释、良好易用的验证环境和鲁棒的脚本。

影响设计重用的障碍本质上说是管理和企业文化;开发和管理内部IP资源是最大的重用挑战。

关于设计重用这里不再讨论,否则就有喧宾夺主之嫌了。

2、关于代码可扩展性的一点讨论

代码可扩展性实际上也包括在设计重用之内。代码可扩展性或称可扩展性设计要求便于向将来新的设计过渡。比如64位的PCI标准出来的时候,现行的32位PCI接口设计模块可以通过比较简单的改动而变为64位,而不需要一切从头再来。一般设计中通过定义参数和宏来便于修改。典型例子就是总线:

`define WORD 16
`define DWORD 32
reg [`WORD-1:0] intruction
reg [`DWORD-1:0] data_bus,addr_bus;
当然代码可扩展性不仅仅包括参数和宏的使用,如下例:
module tri_buf(in,out, ena);
parameter WIDTH=8;
input [WIDTH-1:0] in;
output[WIDTH-1:0] out;
input ena;
assign out= ena?in:’bz;
endmodule

这是一段有潜在问题的代码,Verilog将高位扩展为0来匹配输出,所以当WIDTH>32时,上述代码是有问题的,仿真的时候甚至都看不出来,因此不利于可扩展性。象这样的问题可以用Verilog lint等工具来检查。

3、可读性最重要

可读性最重要。许多设计者有个习惯:追求尽量用短的代码来完成同样的功能,国内许多考试中也要求用少于多少行的代码完成某某功能(很不好的倾向)。对于HDL,我不推荐这样的风格,因为综合工具会帮助你完成优化工作。我的建议是:同样的代码可长可短,不要为了减少行数而影响可读性。如下例:

Module rrarb(request,grant,reset,clk);
Input [1:0] request;
Output[1:0]grant;
Input reset;
Input clk;
Wire winner;
Reg last_winner;
Reg [1:0] grant;
Wire[1:0] next_grant;

Assign next_grant[0]=~reset&(request[0] & (~request[1]|last_winner));
Assugn next_grant[1]=~reset& (request[1] &(~request[0]| ~last_winner));
Assign winner=~reset & ~next_grant[0] &(last_winner | next_grant[1]);
Always @(posedge clk)
Begin
Last_winner=winner;
Grant=next_grant;
End
当request[1:0]=2’b00,时,last_winner会发生什么变化?上面的代码可读性较之下面的代码差很多。
Module rrarb(request,grant,reset,clk);
Input [1:0] request;
Output[1:0]grant;
Input reset;
Input clk;
Wire winner;
Reg last_winner;
Reg [1:0] grant;
Always @(posedge clk)
Begin
If(reset) begin
Grant<=2’b00;
Last_winner<=0;
End
Else begin
Grant<=2’b00;
If(request!=2’b00) begin:find_winner
Reg winner;
Case(request)
2’b01:winner<=0;
2’b10:winner<=1;
2’b11:if (last_winner==1’b0) winner<=1;
else winner<=0;
default:winner<=0;
endcase
grant[winner] <=1’b1;
last_winner<=winner;
end
end
end
endmodule

上述两个代码的综合结果差不多。而且上面第一段代码在always块内采用阻塞赋值的方法也存在潜在问题。

4、要有好的注释风格

要有好的注释风格。减少注释的行数跟节约代码的行数一样,我不推荐。像代码有好坏一样,注释也有好坏之分。比如:

//increment addr
addr<=addr+1;

上例中的注释就是一句废话,因为地址加1是不言自明的。这样的注释反而会影响可读性。好的注释应该给出该段代码的使用目的,它能够给不熟悉这段代码的人以信息。如下例:

//In burst mode,the bytes are written in consecutive addresses.Need to access the next address to verify that the next byte was properly saved.
Addr<=addr+1;

关于如何注释我在设计重用里面讲过,这里不再重复,请参考[2]。

5、应尽量将声明本地化

这种办法有点类似于C++中封装的概念,应尽量保持变量的可见性在必要的范围内,不要产生不必要的交互。
如下例:
integer I;

always
begin
for(I=0;I<32;I=I+1) begin … end
end

always
begin
for(I=15;I>=0;I=I-1) begin … end
end

对于两段代码来讲,I是全局的,他们的不必要的交互会产生不可预料的结果。在verilog里面,你可以将I定义到always块里面,使I只对当前块可见。如下例:

always
begin:block1
integer I;
for(I=0;I<32;I=I+1) begin … end
end

always
begin:block2
integer I;
for(I=15;I>=0;I=I-1) begin … end
end

在Verilog里面其它使变量本地化的方法是采用function 和task。Function和task中定义的变量只对其内部可见。
Task send;
Input [7:0] data;

Reg parity;
Begin

end
endtask
function [31:0] average;
input [31:0] val1;
input[31:0] val2;
reg [32:0] sum;
begin
sum=val1+val2;
average=sum/2;
end
endfunction;

另外,还要提一句关于`define VS parameter。一般设计中都要有一个头文件,里面用`define定义了一些宏。而模块中又有可能用parameter定义一些参数。两者的区别是一个是全局的一个是本地的。设计者可以根据需要进行定义。定义成本地参数避免可以避免同其他模块的变量名字冲突。定义成全局的宏则可以在整个设计的各个文件中使用。千万不可为了方便全部定义成宏。

6、子程序封装

封装有利于程序的可维护性。如果程序中多次用到一段代码,应根据实际情况尽量将它定义为function、task或module。这样做可以减少代码长度,提高可维护行和可验证性。

下面以testbench为例说明。

通常一个SoC设计中,需要首先设计和验证各个子模块,然后才进行系统级验证,因此要多次用到testbench。每个testbench中都要初始化时钟、进行系统复位等。这些多次用到的代码不如写在单独的一个文件(不妨称作basic.v)中,各个testbench只要使用include将他们包括进来就可以直接使用了。

下面是我在最近的863项目中写的basic.v去掉一些注释后的内容,可以直接copy使用。

要求将时钟定义为clk,复位管脚定义为rst,高有效。
//start of basic.v
event ENDSIM;
// CYCLE monitor and end-of-simulation checker.
task monitor_cycles;
input max_cycles;
integer max_cycles;
integer cycles;
begin
cycles = 0;
fork
// Count cycles.
forever begin
@(posedge clk);
cycles = cycles + 1;
end

// Watch for max cycles. If we detect max cycles then throw our testbench ENDSIM event.
//
begin
wait (cycles == max_cycles);
$display ("MAXIMUM CYCLES EXCEEDED!");
->ENDSIM;
end
join
end
endtask
// Reset
task reset;
begin
rst = 1;
#200;
rst = 0;
$display ("End RESET.");
end
endtask

// Drive the clock input
task drive_clock;
begin
clk = 0;
forever begin
#(`CLKLO) clk = 1;
#(`CLKHI) clk = 0;
end
end
endtask

// ************* BASIC CONFIDENCE Test Tasks **************
//
// BASIC CONFIDENCE Test.
//
// This task will fork off all the other necessary tasks to cause reset, drive the clock, etc. etc.
//
//
task clk_rst_gen_and_stop_at;
input cycle_num;
begin
$display ("designed by Chenxi. Email:chenxiee@mails.tsinghua.edu.cn");
fork
// Capture data
capture_data;

// Run the clock
drive_clock;

// Do a reset
reset;
begin
monitor_cycles(cycle_num);
end
// Catch end of simulation event due to max number of cycles or pattern from PIC code.
begin
@(ENDSIM); // Catch the event.
$display ("End of simulation signalled. Killing simulation in a moment.");
#0; // Let anything else see this event...
$stop;
end
join
end
endtask
//end of basiv .v
在testbench中可以直接例化使用。
//somemodule_tb.v
module somemodule_tb;
`include “basic.v”
initial begin
// ** This is our top-level "Basic Confidence" test.

//generatr rst,clk,and stop at 5000 cycles
clk_rst_gen_and_stop_at(5000);

end

endmodule //End of somemodule_tb.v

需要注意的是basic.v不能够单独编译。直接编译testbench就可以了。上述方法也在可综合的代码中使用。
参考文献[1]推荐的另外一种办法是将上述basic.v用模块封装起来。如下例:
module basic;
integer warnings;
integer errors;
initial
begin
warnings=0;
errors=0;
end
task warning;
input[80*8:1] msg;
begin
$write(“Warning at %t: %s”,$time,msg);
warnings=warnings+1;
end
endtask
task terminate;
begin
$write(“Simulation Completedn”);
$stop;
end

endmodule
调用办法:
module somemodule_tb;
initial
begin

if(…) basic.warning(”Unexpected response detected”);

basic.terminate;
end
endmodule

7、结论

本文VerilogHDL为例,从可重用性与可维护性的关系、代码可扩展性设计、尽量增加可读性和使变量本地化、参数(parameter)和宏(`define)的对比以及封装子程序的角度探讨了可维护性设计应遵守的几条基本原则。



参考文献:

[1].PCIdatasheethttp://www.dzsc.com/datasheet/PCI_1201469.html.


来源:ks990次

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭