1 |
2 |
jvillar |
#!/usr/bin/perl -w
|
2 |
|
|
#
|
3 |
|
|
# xdlanalyze.pl - A script to view some statistics about XDL-files
|
4 |
|
|
#
|
5 |
|
|
# Copyright (c) 2006 Andreas Ehliar <ehliar@isy.liu.se>
|
6 |
|
|
# You may copy or modify this program under the terms of the GNU
|
7 |
|
|
# General Public License (version 2 or later)
|
8 |
|
|
#
|
9 |
|
|
# Usage: xdlanalyze.pl foo.xdl [hierarchy levels]
|
10 |
|
|
#
|
11 |
|
|
# Example usage:
|
12 |
|
|
# $ perl xdlanalyze.pl dafk.xdl
|
13 |
|
|
# XDLAnalyze V1.1 by Andreas Ehliar <ehliar@isy.liu.se>
|
14 |
|
|
# Analyzing the file dafk.xdl...................................................
|
15 |
|
|
# +-------------+--------+--------+--------+-----------+--------+--------+
|
16 |
|
|
# | Module | LUTS | FF | RAMB16 | MULT18x18 | IOB | DCM |
|
17 |
|
|
# +-------------+--------+--------+--------+-----------+--------+--------+
|
18 |
|
|
# | / | 64 | | | | 216 | |
|
19 |
|
|
# | cpu | 5065 | 1345 | 12 | 4 | | |
|
20 |
|
|
# | dma0 | 654 | 254 | 1 | | | |
|
21 |
|
|
# | dvga | 816 | 755 | 4 | | | |
|
22 |
|
|
# | eth3 | 2995 | 2337 | 4 | | | |
|
23 |
|
|
# | jpg0 | 1682 | 681 | 2 | 13 | | |
|
24 |
|
|
# | leela | 684 | 552 | 4 | 2 | | |
|
25 |
|
|
# | pia | 9 | | | | | |
|
26 |
|
|
# | pkmc_mc | 219 | 122 | | | | |
|
27 |
|
|
# | rom0 | 111 | 3 | 12 | | | |
|
28 |
|
|
# | sys_sig_gen | | 6 | | | | 2 |
|
29 |
|
|
# | uart2 | 824 | 346 | | | | |
|
30 |
|
|
# | wb_conbus | 618 | 10 | | | | |
|
31 |
|
|
# +-------------+--------+--------+--------+-----------+--------+--------+
|
32 |
|
|
# | Total | 13741 | 6411 | 39 | 19 | 216 | 2 |
|
33 |
|
|
# +-------------+--------+--------+--------+-----------+--------+--------+
|
34 |
|
|
#
|
35 |
|
|
# Example 2 (showing off hierarchical view of the same design)
|
36 |
|
|
# perl xdlanalyze.pl dafk.xdl 1
|
37 |
|
|
# XDLAnalyze V1.1 by Andreas Ehliar <ehliar@isy.liu.se>
|
38 |
|
|
# Analyzing the file dafk.xdl...................................................
|
39 |
|
|
# +-----------------------------+--------+--------+--------+-----------+--------+--------+
|
40 |
|
|
# | Module | LUTS | FF | RAMB16 | MULT18x18 | IOB | DCM |
|
41 |
|
|
# +-----------------------------+--------+--------+--------+-----------+--------+--------+
|
42 |
|
|
# | / | 64 | | | | 216 | |
|
43 |
|
|
# | cpu | 1 | | | | | |
|
44 |
|
|
# | cpu/dwb_biu | 10 | 72 | | | | |
|
45 |
|
|
# | cpu/iwb_biu | 64 | 73 | | | | |
|
46 |
|
|
# | cpu/or1200_cpu | 4441 | 987 | 2 | 4 | | |
|
47 |
|
|
# | cpu/or1200_dc_top | 208 | 40 | 5 | | | |
|
48 |
|
|
# | cpu/or1200_ic_top | 182 | 38 | 5 | | | |
|
49 |
|
|
# | cpu/or1200_immu_top | 11 | 33 | | | | |
|
50 |
|
|
# | cpu/or1200_pic | 32 | 38 | | | | |
|
51 |
|
|
# | cpu/or1200_tt | 116 | 64 | | | | |
|
52 |
|
|
# | dma0 | 617 | 235 | | | | |
|
53 |
|
|
# | dma0/fifo | 37 | 19 | 1 | | | |
|
54 |
|
|
# | dvga | 5 | | | | | |
|
55 |
|
|
# | dvga/regs | 279 | 360 | 3 | | | |
|
56 |
|
|
# | dvga/rend | 174 | 110 | 1 | | | |
|
57 |
|
|
# | dvga/spr | 358 | 285 | | | | |
|
58 |
|
|
# | eth3 | 73 | 51 | | | | |
|
59 |
|
|
# | eth3/Mshreg_WillTransmit_q2 | 1 | | | | | |
|
60 |
|
|
# | eth3/ethreg1 | 368 | 302 | | | | |
|
61 |
|
|
# | eth3/maccontrol1 | 295 | 103 | | | | |
|
62 |
|
|
# | eth3/macstatus1 | 60 | 18 | | | | |
|
63 |
|
|
# | eth3/miim1 | 127 | 74 | | | | |
|
64 |
|
|
# | eth3/rxethmac1 | 311 | 107 | | | | |
|
65 |
|
|
# | eth3/txethmac1 | 369 | 119 | | | | |
|
66 |
|
|
# | eth3/wishbone | 1391 | 1563 | 4 | | | |
|
67 |
|
|
# | jpg0 | 302 | 57 | 2 | | | |
|
68 |
|
|
# | jpg0/dct0 | 599 | 618 | | 13 | | |
|
69 |
|
|
# | jpg0/tmem | 781 | 6 | | | | |
|
70 |
|
|
# | leela | 36 | | | | | |
|
71 |
|
|
# | leela/cam0 | 349 | 291 | 4 | 2 | | |
|
72 |
|
|
# | leela/mc0 | 129 | 25 | | | | |
|
73 |
|
|
# | leela/regs0 | 170 | 236 | | | | |
|
74 |
|
|
# | pia | 9 | | | | | |
|
75 |
|
|
# | pkmc_mc/mem_fpga_board_if | 40 | 1 | | | | |
|
76 |
|
|
# | pkmc_mc/pkmc_mc | 179 | 121 | | | | |
|
77 |
|
|
# | rom0 | 77 | 1 | | | | |
|
78 |
|
|
# | rom0/boot_prog_bram | 34 | 2 | 8 | | | |
|
79 |
|
|
# | rom0/boot_ram | | | 4 | | | |
|
80 |
|
|
# | sys_sig_gen | | 6 | | | | |
|
81 |
|
|
# | sys_sig_gen/del0 | | | | | | 1 |
|
82 |
|
|
# | sys_sig_gen/div0 | | | | | | 1 |
|
83 |
|
|
# | uart2 | 1 | | | | | |
|
84 |
|
|
# | uart2/dbg | 33 | | | | | |
|
85 |
|
|
# | uart2/regs | 725 | 266 | | | | |
|
86 |
|
|
# | uart2/wb_interface | 65 | 80 | | | | |
|
87 |
|
|
# | wb_conbus | 618 | | | | | |
|
88 |
|
|
# | wb_conbus/arb | | 10 | | | | |
|
89 |
|
|
# +-----------------------------+--------+--------+--------+-----------+--------+--------+
|
90 |
|
|
# | Total | 13741 | 6411 | 39 | 19 | 216 | 2 |
|
91 |
|
|
# +-----------------------------+--------+--------+--------+-----------+--------+--------+
|
92 |
|
|
#
|
93 |
|
|
# If you don't want to print all fields, change the @print_order
|
94 |
|
|
# declaration below.
|
95 |
|
|
#
|
96 |
|
|
# Note that the figures will usually not be exactly the same as the
|
97 |
|
|
# figures reported by map. This is partly because map does not count a
|
98 |
|
|
# LUT with a constant output as a LUT, at least not in ISE 8.1.
|
99 |
|
|
#
|
100 |
|
|
# The program will also automatically convert a .ncd-file to a temporary
|
101 |
|
|
# .xdl file before running.
|
102 |
|
|
#
|
103 |
|
|
# This program has been tested on designs targetted at Virtex-2 and
|
104 |
|
|
# Virtex-4 from ISE 8.1 and ISE 8.2 on a Linux based computer. Note
|
105 |
|
|
# that it assumes that your path separator is set to /.
|
106 |
|
|
#
|
107 |
|
|
# Missing features:
|
108 |
|
|
# * Slice count would be nice
|
109 |
|
|
# * Show number of LUTs used as distributed RAM and SRL16
|
110 |
|
|
# * Virtex-5 support
|
111 |
|
|
#
|
112 |
|
|
# NOTE:
|
113 |
|
|
# The synthesizer will probably optimize your design across module boundaries
|
114 |
|
|
# in some cases. This means that your figures cannot be entirely correct.
|
115 |
|
|
|
116 |
|
|
use strict;
|
117 |
|
|
use IO::Handle;
|
118 |
|
|
use IO::File;
|
119 |
|
|
use POSIX qw(tmpnam);
|
120 |
|
|
|
121 |
|
|
|
122 |
|
|
use constant {
|
123 |
|
|
LUTS => 1,
|
124 |
|
|
FF => 2,
|
125 |
|
|
IOB => 3,
|
126 |
|
|
RAMB16 => 4,
|
127 |
|
|
MULT_18X18 => 5,
|
128 |
|
|
DSP48 => 6,
|
129 |
|
|
DCM => 7,
|
130 |
|
|
DCM_ADV => 8,
|
131 |
|
|
BUFG => 9,
|
132 |
|
|
};
|
133 |
|
|
|
134 |
|
|
my @translation = ( "UNKNOWN", "LUTS","FF","IOB","RAMB16","MULT18x18",
|
135 |
|
|
"DSP48", "DCM", "DCM_ADV", "BUFG" );
|
136 |
|
|
|
137 |
|
|
|
138 |
|
|
# Modify this line to include what you want printed and in what order
|
139 |
|
|
my @print_order = ( LUTS, FF, RAMB16, DSP48, MULT_18X18, IOB, DCM,
|
140 |
|
|
DCM_ADV, BUFG );
|
141 |
|
|
|
142 |
|
|
|
143 |
|
|
|
144 |
|
|
########################################################################
|
145 |
|
|
my %themodules;
|
146 |
|
|
my %hierarchical_usageinfo;
|
147 |
|
|
my %usageinfo;
|
148 |
|
|
|
149 |
|
|
# This variable controls how many levels we will keep track of
|
150 |
|
|
my $hierarchical_level = 0;
|
151 |
|
|
|
152 |
|
|
######################################################################
|
153 |
|
|
# Add a component to the statistics
|
154 |
|
|
######################################################################
|
155 |
|
|
sub add_component {
|
156 |
|
|
my $thename = $_[0];
|
157 |
|
|
my $thetype = $_[1];
|
158 |
|
|
|
159 |
|
|
my @temppath = split("/",$thename);
|
160 |
|
|
my @list = ();
|
161 |
|
|
my $currname = $temppath[0];
|
162 |
|
|
my $i;
|
163 |
|
|
|
164 |
|
|
push(@list,$currname);
|
165 |
|
|
|
166 |
|
|
for($i = 1; $i < $#temppath; $i = $i + 1) {
|
167 |
|
|
$currname = "$currname/$temppath[$i]";
|
168 |
|
|
push(@list,$currname);
|
169 |
|
|
}
|
170 |
|
|
|
171 |
|
|
for($i = $hierarchical_level; $i < $#temppath; $i = $i + 1) {
|
172 |
|
|
$currname = pop(@list);
|
173 |
|
|
if($themodules{$currname}) {
|
174 |
|
|
$i = $#temppath;
|
175 |
|
|
}
|
176 |
|
|
}
|
177 |
|
|
|
178 |
|
|
|
179 |
|
|
if($thename =~ /\//) {
|
180 |
|
|
}else{
|
181 |
|
|
# If there is no slash in the name => a component of the top level
|
182 |
|
|
$currname = "/";
|
183 |
|
|
}
|
184 |
|
|
|
185 |
|
|
my %thehash;
|
186 |
|
|
|
187 |
|
|
$hierarchical_usageinfo{$currname}{$thetype}++;
|
188 |
|
|
$usageinfo{$thetype}++;
|
189 |
|
|
|
190 |
|
|
$themodules{$currname} = 1;
|
191 |
|
|
}
|
192 |
|
|
|
193 |
|
|
######################################################################
|
194 |
|
|
# Analyze an XDL file and collect statistics about component
|
195 |
|
|
# usage
|
196 |
|
|
######################################################################
|
197 |
|
|
|
198 |
|
|
sub analyze_file {
|
199 |
|
|
|
200 |
|
|
print "Analyzing the file $_[0]...";
|
201 |
|
|
STDOUT->autoflush(1);
|
202 |
|
|
|
203 |
|
|
open THEFILE, '<', $_[0] or die;
|
204 |
|
|
|
205 |
|
|
my $line = 0;
|
206 |
|
|
while (<THEFILE>){
|
207 |
|
|
|
208 |
|
|
# Progress meter
|
209 |
|
|
$line++;
|
210 |
|
|
if($line == 10000){
|
211 |
|
|
$line = 0;
|
212 |
|
|
print(".");
|
213 |
|
|
STDOUT->autoflush(1);
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
# Quick and dirty parser that does not keep any state.
|
217 |
|
|
# A real parser would remember what kind of instance we are
|
218 |
|
|
# currently inside in order to keep track of more things such
|
219 |
|
|
# as for example slice usage, etc.
|
220 |
|
|
|
221 |
|
|
# Both an F and a G LUT can be on the same line
|
222 |
|
|
# So we can't use elseif here.
|
223 |
|
|
if(/ F:([a-zA-Z0-9_\/\[\]<>\.]+:\#([A-Z]+):D=)/) {
|
224 |
|
|
&add_component($1,LUTS);
|
225 |
|
|
}
|
226 |
|
|
|
227 |
|
|
if(/ G:([a-zA-Z0-9_\/\[\]<>\.]+:\#([A-Z]+):D=)/) {
|
228 |
|
|
&add_component($1,LUTS);
|
229 |
|
|
}
|
230 |
|
|
|
231 |
|
|
|
232 |
|
|
# Both an FFX and a FFY flip flop can be on the same line
|
233 |
|
|
# So we can't use elseif here.
|
234 |
|
|
if(/FFX:([a-zA-Z0-9_\/\[\]<>\.]+:\#[A-Z]+)/) {
|
235 |
|
|
&add_component($1,FF);
|
236 |
|
|
}
|
237 |
|
|
|
238 |
|
|
if(/FFY:([a-zA-Z0-9_\/\[\]<>\.]+:\#[A-Z]+)/) {
|
239 |
|
|
&add_component($1,FF);
|
240 |
|
|
}
|
241 |
|
|
|
242 |
|
|
# Check if there is an instance defined on this line
|
243 |
|
|
if(/^inst/) {
|
244 |
|
|
if(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"IOB\"/){
|
245 |
|
|
&add_component($1,IOB);
|
246 |
|
|
}elsif(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"RAMB16\"/){
|
247 |
|
|
&add_component($1,RAMB16);
|
248 |
|
|
}elsif(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"MULT18X18\"/){
|
249 |
|
|
&add_component($1,MULT_18X18);
|
250 |
|
|
}elsif(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"DSP48\"/){
|
251 |
|
|
&add_component($1,DSP48);
|
252 |
|
|
}elsif(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"DCM\"/){
|
253 |
|
|
# FIXME - Do we need a check for a dummy DCM?
|
254 |
|
|
&add_component($1,DCM);
|
255 |
|
|
}elsif(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"DCM_ADV\"/){
|
256 |
|
|
# Check for unused dummy instantiation of DCM_ADV
|
257 |
|
|
if(! /^inst \"XIL_ML_UNUSED_DCM/){
|
258 |
|
|
&add_component($1,DCM_ADV);
|
259 |
|
|
}
|
260 |
|
|
}elsif(/^inst \"([a-zA-Z0-9_\/\[\]<>\.]+)\" \"BUFG\"/){
|
261 |
|
|
&add_component($1,BUFG);
|
262 |
|
|
}
|
263 |
|
|
# Adding more components here should be easy
|
264 |
|
|
}
|
265 |
|
|
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
print "\n";
|
269 |
|
|
|
270 |
|
|
}
|
271 |
|
|
|
272 |
|
|
######################################################################
|
273 |
|
|
# Print a line consisting of dashes and plus like the marked lines in
|
274 |
|
|
# the following output:
|
275 |
|
|
# --> +-------------------+--------+--------+--------+
|
276 |
|
|
# | Module | LUTS | FF | IOB |
|
277 |
|
|
# --> +-------------------+--------+--------+--------+
|
278 |
|
|
######################################################################
|
279 |
|
|
|
280 |
|
|
sub print_dashes {
|
281 |
|
|
my $firstlen = $_[0];
|
282 |
|
|
my $inst_order = $_[1];
|
283 |
|
|
my $insttype;
|
284 |
|
|
print "+" . "-" x ($firstlen + 2);
|
285 |
|
|
foreach $insttype (@$inst_order) {
|
286 |
|
|
my $maxlen = length($translation[$insttype]);
|
287 |
|
|
$maxlen = $maxlen < 6 ? 6 : $maxlen;
|
288 |
|
|
print "+" . "-" x ($maxlen + 2);
|
289 |
|
|
}
|
290 |
|
|
printf("+\n");
|
291 |
|
|
|
292 |
|
|
}
|
293 |
|
|
|
294 |
|
|
######################################################################
|
295 |
|
|
# Print statistics collected in the %themodules, %usageinfo, and
|
296 |
|
|
# %hierarchical_usageinfo hashes.
|
297 |
|
|
######################################################################
|
298 |
|
|
|
299 |
|
|
sub print_stats {
|
300 |
|
|
|
301 |
|
|
my $firstlen;
|
302 |
|
|
my @thekeys = keys %themodules;
|
303 |
|
|
@thekeys = sort(@thekeys);
|
304 |
|
|
my $i;
|
305 |
|
|
my $name;
|
306 |
|
|
my $foo;
|
307 |
|
|
my @inst_order;
|
308 |
|
|
|
309 |
|
|
# Find maximum length of the first field
|
310 |
|
|
$firstlen = length("Module");
|
311 |
|
|
foreach $i (@thekeys) {
|
312 |
|
|
if($firstlen < length($i)){
|
313 |
|
|
$firstlen = length($i);
|
314 |
|
|
}
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
my $insttype;
|
318 |
|
|
my $maxlen;
|
319 |
|
|
|
320 |
|
|
# Create inst_order so that we only print statistics about components
|
321 |
|
|
# that are actually used in the design.
|
322 |
|
|
foreach $name (@print_order) {
|
323 |
|
|
if($usageinfo{$name}) {
|
324 |
|
|
push(@inst_order,$name);
|
325 |
|
|
}
|
326 |
|
|
}
|
327 |
|
|
|
328 |
|
|
# Print header
|
329 |
|
|
&print_dashes($firstlen,\@inst_order);
|
330 |
|
|
printf("| %- ${firstlen}s ","Module");
|
331 |
|
|
foreach $insttype (@inst_order) {
|
332 |
|
|
printf("| % 6s ", $translation[$insttype]);
|
333 |
|
|
}
|
334 |
|
|
printf("|\n");
|
335 |
|
|
&print_dashes($firstlen,\@inst_order);
|
336 |
|
|
|
337 |
|
|
|
338 |
|
|
# Print hierarchical statistics
|
339 |
|
|
foreach $name (@thekeys) {
|
340 |
|
|
printf("| %- ${firstlen}s ",$name);
|
341 |
|
|
foreach $insttype (@inst_order) {
|
342 |
|
|
$maxlen = length($translation[$insttype]);
|
343 |
|
|
$maxlen = $maxlen < 6 ? 6 : $maxlen;
|
344 |
|
|
if($hierarchical_usageinfo{$name}{$insttype}) {
|
345 |
|
|
printf("| % ${maxlen}d ",$hierarchical_usageinfo{$name}{$insttype});
|
346 |
|
|
}else {
|
347 |
|
|
printf("| % ${maxlen}s "," ");
|
348 |
|
|
}
|
349 |
|
|
}
|
350 |
|
|
printf("|\n");
|
351 |
|
|
}
|
352 |
|
|
|
353 |
|
|
# Print footer with total number of all components
|
354 |
|
|
&print_dashes($firstlen,\@inst_order);
|
355 |
|
|
|
356 |
|
|
printf("| %- ${firstlen}s ","Total");
|
357 |
|
|
foreach $insttype (@inst_order) {
|
358 |
|
|
$maxlen = length($translation[$insttype]);
|
359 |
|
|
$maxlen = $maxlen < 6 ? 6 : $maxlen;
|
360 |
|
|
if($usageinfo{$insttype}){
|
361 |
|
|
printf("| % ${maxlen}d ",$usageinfo{$insttype});
|
362 |
|
|
}else{
|
363 |
|
|
printf("| % ${maxlen}s "," ");
|
364 |
|
|
}
|
365 |
|
|
}
|
366 |
|
|
printf("|\n");
|
367 |
|
|
|
368 |
|
|
&print_dashes($firstlen,\@inst_order);
|
369 |
|
|
}
|
370 |
|
|
|
371 |
|
|
|
372 |
|
|
######################################################################
|
373 |
|
|
# Main program starts here
|
374 |
|
|
######################################################################
|
375 |
|
|
|
376 |
|
|
printf('XDLAnalyze V1.1 by Andreas Ehliar <ehliar@isy.liu.se>'. "\n");
|
377 |
|
|
|
378 |
|
|
if(! $ARGV[0]){
|
379 |
|
|
print STDERR "Usage: xdlanalyze.pl <design.xdl> [hierarchical levels]\n";
|
380 |
|
|
exit 1;
|
381 |
|
|
}
|
382 |
|
|
|
383 |
|
|
if($ARGV[1]) {
|
384 |
|
|
$hierarchical_level = $ARGV[1];
|
385 |
|
|
}
|
386 |
|
|
|
387 |
|
|
# If the input has a .ncd file extension it will be converted to an .xdl file
|
388 |
|
|
if( $ARGV[0] =~ /.ncd$/ ) {
|
389 |
|
|
my $tempname;
|
390 |
|
|
my $fh;
|
391 |
|
|
|
392 |
|
|
printf("Calling xdl -ncd2xdl to convert .ncd file to .xdl file before running analyzer\n");
|
393 |
|
|
|
394 |
|
|
# try new temporary filenames until we get one that didn't already exist as per
|
395 |
|
|
# the perl cookbook
|
396 |
|
|
do { $tempname = tmpnam() . ".xdl" }
|
397 |
|
|
until $fh = IO::File->new($tempname, O_RDWR|O_CREAT|O_EXCL);
|
398 |
|
|
|
399 |
|
|
# Call the xdl tool to convert the file...
|
400 |
|
|
system ("xdl", "-ncd2xdl", $ARGV[0], $tempname) == 0 or die "Couldn't call xdl: $!";
|
401 |
|
|
&analyze_file($tempname);
|
402 |
|
|
|
403 |
|
|
unlink($tempname) or die "Couldn't unlink $tempname : $!";
|
404 |
|
|
|
405 |
|
|
}else {
|
406 |
|
|
&analyze_file($ARGV[0]);
|
407 |
|
|
}
|
408 |
|
|
|
409 |
|
|
|
410 |
|
|
&print_stats;
|
411 |
|
|
|
412 |
|
|
exit 0;
|