blob: 60dbda2d7828d71f4d616cc7b1be9ef1fa9d17a8 [file] [log] [blame] [edit]
#!/usr/bin/perl
# simple Clock Tree Syntheizer
# By: M. Shalan, Dec 2019
#
# usage: ./cts.pl <netlist.v> <fanout> <clock_net_name>
#
# You need to set the following variables based on the PDK/CSL
# root_clkbuf : CT root buffer type
# clkbuf : CT branching buffer type
# clkbuf_in : Buffer input pin name
# clkbuf_out : Buffer output pin name
#
# Copyright (c) Efabless Corporation. All rights reserved.
# See LICENSE file in the project root for full license information.
#
use POSIX;
use Switch;
my $leaves;# = $ARGV[0];
my $vlg_fn = $ARGV[0];
my $fanout = $ARGV[1];
my $clk_net = $ARGV[2];
my $root_clkbuf = $ARGV[3];
my $clkbuf = $ARGV[4];
my $clkbuf_in = $ARGV[5];
my $clkbuf_out = $ARGV[6];
unless (-e $vlg_fn) {
print "$vlg_fn File Doesn't Exist!";
exit 0;
}
$leaves = `grep "($clk_net)" $vlg_fn | wc -l`;
my $levels = logb($leaves, $fanout);
# This array holds the number of buffers @ each level
#@buffs = (0) x ($levels + 1);
@buffs = (0) x 20;
$buffs[0] = $leaves;
@vlg_wires = ();
@vlg_cells = ();
%def_nets;
@def_comp = ();
# Verilog o/p
my $cell_cnt = 0;
for my $l (1..$levels-1) {
$l1 = $l - 1;
$inst = "_CTS_buf_".$l."_";
$owire = "clk_$l1"."_";
$iwire = "clk_$l"."_";
for(my $i = 0; $i < $leaves; $i+=($fanout**$l)){
$ii = floor($i/($fanout**($l+1))) * ($fanout**($l+1));
my $cell_nm = "$inst".$i;
push @vlg_cells, "$clkbuf $cell_nm ( .$clkbuf_in($iwire$ii), .$clkbuf_out($owire$i) );\n";
push @vlg_wires, "wire $owire$i;\n";
$buffs[$l]++;
$cell_cnt++;
}
print "\n";
}
my $root_net = "clk_".($levels-1)."_0";
push @vlg_cells, "$root_clkbuf _CTS_root ( .$clkbuf_in($clk_net), .$clkbuf_out($root_net) );\n";
push @vlg_wires, "wire clk_".($levels-1)."_0;\n";
# Insert the newly created wires and buufers into the netlist
open(FH, '<', $vlg_fn) or die $!;
my $flag = 0;
my $ff_cnt = 0;
while(<FH>){
switch ($flag){
case 0 { $flag = 1 if($_ =~ /wire/); print $_}
case 1 {
if(!($_ =~ /wire/) && !($_ =~ /input/) && !($_ =~ /output/)) {
$flag = 2;
print "\n// CTS added wires\n";
print @vlg_wires;
print "\n// CTS added buffers\n";
print @vlg_cells;
print "\n";
print $_;
} else {
print $_;
}
}
case 2 {
if($_ =~ /\($clk_net\)/) {
my $clk_wire_name = "clk_0_".int($ff_cnt / $fanout) * $fanout;
#print "$clk_wire_name \n";
$_ =~ s/$clk_net/$clk_wire_name/g;
#print $_;
$ff_cnt++;
}
print $_;
}
}
}
close(FH);
sub logb {
my $n = shift;
my $b = shift;
return ceil(log($n)/log($b));
}