Verilog代码自动缩进和对齐Perl脚本(更新)

Perl 专栏收录该内容
3 篇文章 1 订阅

实验室做FPGA开发时经常用到Verilog,代码规范成为一个问题,于是乎写了一个Perl脚本对代码进行规范化,主要是进行自动缩进和对齐。

代码原理很简单,主要是使用了正则表达式进行匹配和替换。

(新更新的代码增加了增加了变量名长度检测, 增加了module名检测, 对未加begin...end的always进行添加的功能)

代码如下,初学Perl,请读者赐教:

use 5.010;
use File::Basename;

my $filename = 'C:\Users\CvCv\Desktop\Perl_tmp\code.v';#输入文件名
my $outfilename = 'C:\Users\CvCv\Desktop\Perl_tmp\out.v';#输出文件名
my $basename = basename($filename,".v");
#----------------------------------------------------------
#测试文件存在
die "文件$filename不存在!\n" unless -e $filename;
#打开文件
open(VFILE,"<",$filename) || die "打开文件失败!\n";
open(OFILE,">",$outfilename) || die "打开文件失败!\n";
#----------------------------------------------------------
#对文件预处理,begin...end if...else if...begin等在一行的改成两行
#未添加begin...end的always块进行添加
$always_cnt = 0;
my $last_line = "";
while(<VFILE>){
	chomp;#去除行尾的\n
	
	if(/(.*if.*)(begin.*)/i){
		push @content,$1;
		push @content,$2;
		$last_line = $2;
	}
	elsif(/(.*begin.*)(if.*)/i){
		push @content,$1;
		push @content,$2;
		$last_line = $2;
	}
	elsif(/\s*((input|output|reg|wire|(?:output\s+reg))\s*(\[.+\:.+\])?\s*)((?!reg|wire)(?:(\w+)\s*,\s*(\w+)))([,;]?)/){
		#对于单行定义多个变量进行换行处理
		push @content, $1." ".$5.";";
		push @content, $1." ".$6.";";
		$last_line = $2;
	}
	elsif(/^\s*$/){#空行
		#删除空行
		#say $last_line;
	}
	elsif(/always|module|endmodule|assign|initial/i){#匹配到always		
		if($last_line =~ /\s*\S+$/ or $last_line =~ /^$/){
			#上一行不是空格,就添加一个空行
			push @content,"";
		}
		push @content,$_;
		$last_line = $_;
	}
	elsif(/\bif\s*\(/i){#匹配到if
		if($last_line =~ /always/){
			#上一行是always
			$always_cnt = 1;
			push @content,"begin";
		}
		push @content,$_;
		$last_line = $_;
	}
	else{
		push @content,$_;
		$last_line = $_;
	}
}
$always_cnt = 0;
#print join("\n",@content);

#----------------------------------------------------------
#变量定义
$begin_cnt = 0;
$if_cnt = 0;
$autoindent_space = " "x4;#自动缩进的空格数(Tab宽度)
$last_line = "";
$assign_start = 0;
#模块定义开始
$module_def_start = 0;
my $module_cnt = 0;

#==========================================================
#读取并处理文件
#while(<VFILE>){
foreach (@content){
	#print $begin_cnt,$_,"\n";
	$line = $_;
	if($assign_start){
		if(/.*;/){
			$assign_start = 0;
		}
	}
	if(/\s*\b(input|output|reg|wire)\b/i){
		$line =~ s/^\s+//;
		my @result = ($line =~ /\s*(input|output|reg|wire|(?:output\s+reg))\s*(\[.+\:.+\])?\s*((?!reg|wire)\w+)\s*([,;]?)/ig);
		#print length($result[0]),"--@result\n";
		if($#result>0){
			$line = $autoindent_space;
			$line .= $result[0]." "x(20-length($result[0]));
			$line .= $result[1]." "x(20-length($result[1]));
			$line .= $result[2]." "x(20-length($result[2]));
			$line .= $result[3];
			if((my $len = length($result[2]))>20){
				print "变量名过长(实际长度$len>20字符):\t$result[2]\n";
			}
		}
	}
	elsif(/(parameter)?\s*(\w+)\s*\=\s*((?:\d+\'[hbHB][0-9a-fA-F_]+)|(?:\d+))\s*([,;]?)/i){
		$line =~ s/^\s+//;
		my @result = ($line =~ /(parameter)?\s*(\w+)\s*\=\s*((?:\d+\'[hbHB][0-9a-fA-F_]+)|(?:\d+))\s*([,;]?)/ig);
		#print $#result."--@result\n";
		if($#result>0){
			$line = $autoindent_space;
			$line .= $result[0]." "x(20-length($result[0]));
			$line .= $result[1]." "x(35-length($result[1]));
			$line .= "= ".$result[2]." "x(18-length($result[2]));
			$line .= $result[3];
		}
	}	
	elsif(/\s*\b(module|endmodule|assign|initial)\b/i){#匹配到module|always|assign
		$line =~ s/^\s+//;
		if(/\s*\b(assign|initial)\b\s+\w/i){#匹配到assign
			$line =~ s/\s*\b(assign|initial)\b\s+(\w)/$1  $2/i;
			$assign_start = 1;
			#print;
		}
		if(/module\s+(\w+)\s*\(/i){
			#未匹配到分号,表示module输入输出定义多行
			if(!/.*;/){
				$module_def_start = 1;
				$line = "\n//--------------start of module define--------------\n".$line;
			}
			$module_cnt++;
			if($module_cnt>1){
				print "文件存在多个module\n";
			}			
			if($basename ne $1){
				print "module名$1和文件名$basename不一致!\n";
			}
		}		
	}
	elsif(/\bbegin\b/i){#匹配到begin
		my $tmp_space = $autoindent_space x $begin_cnt;
		$begin_cnt++;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/\bend\b/i){#匹配到end
		if($if_cnt>0){
			$if_cnt--;
		}
		my $tmp_space = $autoindent_space x ($begin_cnt-1);
		$begin_cnt>0 && $begin_cnt--;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/if\s*\(/i){#匹配到if
		$if_cnt++;
		my $tmp_space = $autoindent_space x $begin_cnt;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/\belse\s*/i){#匹配到else
		my $tmp_space = $autoindent_space x $begin_cnt;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/always/){
		$always_cnt=1;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/^\s*$/){#匹配到空行
		#say "="x20;
		#always结束的空行(代码中间的空行已经删除)
		if($if_cnt==0 && $begin_cnt==1 && $always_cnt==1){
			#加入always的end
			$line = "end\n";
			$begin_cnt=0;
			$always_cnt=0;
		}
	}
	else{
		if($last_line =~ /(\s+if\s*\()|(\belse\s*)|(^\s*\w+\:\s*)/){#上一行是if/else/case分支
			$if_cnt>0 && $if_cnt--;
			my $tmp_space = $autoindent_space x ($begin_cnt+1);
			$line =~ s/^\s*/$tmp_space/;
		}
		else{
			my $tmp_space = $autoindent_space x $begin_cnt;
			$line =~ s/^\s*/$tmp_space/;
		}
		if($module_def_start)
		{
			if(/.*;/){
				#最后一行module定义
				$line = ($autoindent_space x 4).$line;
				$line .= "\n//--------------end of module define--------------\n";
				$module_def_start = 0;
			}
			else{
				$line = ($autoindent_space x 4).$line;
			}
		}
		if($assign_start){
			#print "*"x5;
			#$always_cnt=0;
			my $tmp_space = $autoindent_space x 2;
			$line =~ s/^\s*/$tmp_space/;
			if(/".*;\s*$"/){
				$assign_start = 0;
			}
			#say $line;
		}
		
	}
	$last_line = $line;
	#say $if_cnt."-".$begin_cnt."-".$always_cnt."--".$line;
	$text.=$line."\n";
}

#关闭文件
close VFILE;
select OFILE;
print $text;
close OFILE;
select STDOUT;
print "-"x40,"\n"."处理完毕,文件输出到$outfilename\n";


==================================================================================

效果预览:




  • 6
    点赞
  • 3
    评论
  • 19
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
iscas2spice spice netlist generation tool -- version 2.2 by Jingye Xu @ VLSI Group, Dept. of ECE, UIC, June, 2008 This tool reads the ISCAS85 benchmark circuit "*.bench" file and translate the file into SPICE netlist using the given technology and the standard cell library. platform: linux x86 sytem Input: ISCAS85 benchmark circuit: *.bench; standard cell library: stdcells.sclb; standard cell models: stdcells.lib; interconnect paramaters: *.int; Output: SPICE netlist: out.sp The whole procedure of the tools can be divided into several steps: 1. Gate replacement: replace the gates that can't be found in the with the gates in the standard cell lib. (break.pl) Output: *.bench, *.bench.bak 2. Generate the GSRC files: generate the GSRC files for the fengshui placer. (gsrcgen.pl) Output: gsrcfile/iscas.* 3. Placement: using the fengshui placement tool to perform the component placement. (fs50) Output: gsrcfile/iscas_fs50.pl 4. Generate ISPD file: tanslate the placement results into ISPD98 format file that can be used as the input of the global router. (gsrc2ispd.pl) Output: gsrcfile/iscas.laby.txt 5. Perform the routing: use the labyrinth global router to perform the routing. (mazeRoute) Output: gsrcfile/output 6. Generate the SPICE netlist: use all the available information to generate the final SPICE netlist. (spicegen.pl) Output: out.sp Usage: iscas2spice.pl Iscas85BenchmarkFile [-C/L/N] options: -C :default value, use the RC model for interconnect -L :use the RLC model for interconnect -N :treat interconnect as short circuit wire This package used the fengshui placement tools and labyrinth global routing tools, for information regarding these two free tools, please vist: http://www.ece.ucsb.edu/~kastner/labyrinth/ http://vlsicad.cs.binghamton.edu/software.html For information regarding this software itself please visit: http://wave.ece.uic.edu/~iscas2spice Many thanks to my advisor Masud H. Chowdhury for his support!
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏

xddc

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值