projects/scripts: Add gtwizard scripts
parent
62dc310794
commit
86d754ae85
|
@ -0,0 +1,935 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# This script is meant to be used together with gtwizard_generator.tcl
|
||||
# It parses and provides as output a list of unique parameters to a provided GT wizard configuration
|
||||
# Must be called from the project folder, where the IP instance is (*.gen/sources_1/ip)
|
||||
#
|
||||
################################################################################
|
||||
use strict;
|
||||
use warnings;
|
||||
# use bigint;
|
||||
|
||||
################################################################################
|
||||
## Check the status of the required modules
|
||||
my @modules = qw (
|
||||
Cwd
|
||||
Data::Dumper
|
||||
);
|
||||
|
||||
for(@modules) {
|
||||
eval "use $_";
|
||||
if ($@) {
|
||||
warn "Module not found : $_ \n Please install it!" if $@;
|
||||
}
|
||||
}
|
||||
|
||||
sub print_hash {
|
||||
|
||||
my ($hash_ref) = @_;
|
||||
|
||||
foreach my $key (keys %$hash_ref) {
|
||||
print " $key : $$hash_ref{$key}\n ";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## SUBROUTINES
|
||||
################################################################################
|
||||
# Search for the COMMON and CHANNEL attributes from the generated files
|
||||
# Required parameters : $_ - file name
|
||||
################################################################################
|
||||
sub get_attribute_name {
|
||||
|
||||
my ($pfile) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
|
||||
# Try to open the file
|
||||
open(READFILE, "<$pfile") or die print "@[$myname] Can not open file called $pfile for reading.\n";
|
||||
|
||||
my $xcvr_params_str = join('', <READFILE>);
|
||||
my @xcvr_params;
|
||||
|
||||
# remove comments //anything
|
||||
my $comment_regex = qr/^\s*\/{2}.*\n/mp;
|
||||
my $subst = '';
|
||||
$xcvr_params_str = $xcvr_params_str=~s/$comment_regex/$subst/rg;
|
||||
|
||||
# return the attribute block from the *_[COMMON|CHANNEL] instance
|
||||
# Ultrascale/Ultrascale+ version
|
||||
# if ($xcvr_params_str =~ m/#\(((\n(.*\),\n){2,}).*\)\n)/) {
|
||||
# Version that works for both 7 series and Ultrascale/Ultrascale+
|
||||
# This regex searches for the IP instance in the verilog code. In 7 series there are spaces at the begining of the line, while for Ultrascale there are not. After that searches for the name of the instance followed by spaces (0 or more) and a #. The next characters are maybe a \n followed by spaces and (. Going forward, it accepts \n followed by anything as long as it ends with '),'. Or a space followed by anything. The '?' is there to make the regex be non-greedy. The group after ( is searched for at least 2 times and must be followed by a ')\n'. This regex matches . with \n becouse of the /m at the end.
|
||||
my $regex = qr/^\s*[A-Z1-9_]*\s*#\n?\s*\((((\n(.*\),\n)|(\s.*?)){2,}).*\)\n)/mp;
|
||||
if ($xcvr_params_str =~ /$regex/ ) {
|
||||
|
||||
@xcvr_params = split ("\n", $1);
|
||||
|
||||
# the first element is not valid
|
||||
splice(@xcvr_params, 0, 1);
|
||||
} else {
|
||||
print "@[$myname] No match in $pfile, check regexp!\n";
|
||||
}
|
||||
close(READFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
|
||||
|
||||
# parse out the attribute names
|
||||
foreach my $i (0..$#xcvr_params) {
|
||||
# remove leading white space
|
||||
$xcvr_params[$i] =~ s/^\s+//;
|
||||
|
||||
# remove trailing text, keep just the first word
|
||||
$xcvr_params[$i] =~ s/\s+.*$//;
|
||||
|
||||
# remove leading dot character
|
||||
$xcvr_params[$i] =~ s/^\.//;
|
||||
}
|
||||
return @xcvr_params;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Mine the COMMON and CHANNEL attributes into a list
|
||||
# Required parameters : $1 - file name
|
||||
# $2 - transceiver type (e.g. GTHE4_COMMON)
|
||||
# $3 - parameter name list - reference array
|
||||
################################################################################
|
||||
sub get_attribute_value {
|
||||
|
||||
my ($pfile, $xcvr_type, $param_list) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
|
||||
my %params;
|
||||
|
||||
my $path = Cwd::cwd();
|
||||
|
||||
# Try to open the file
|
||||
open(READFILE, "<$pfile") or die print "@[$myname] Can not open file called $pfile for reading at $path\n";
|
||||
|
||||
my $xcvr_params_str = join('', <READFILE>);
|
||||
|
||||
# remove comments //anything
|
||||
my $comment_regex = qr/^\s*\/{2}.*\n/mp;
|
||||
my $subst = '';
|
||||
$xcvr_params_str = $xcvr_params_str=~s/$comment_regex/$subst/rg;
|
||||
|
||||
foreach my $param (@$param_list) {
|
||||
if ((uc($xcvr_type) eq "GTXE2_GT") or (uc($xcvr_type) eq "GTXE2_COMMON")) {
|
||||
my $regex = qr/^\s*[A-Z1-9_]*\s*#\n?\s*\((((\n(.*\),\n)|(\s.*?)){2,}).*\)\n)/mp;
|
||||
if ($xcvr_params_str =~ /$regex/ ) {
|
||||
my $new_xcvr_params_str = $1;
|
||||
|
||||
if ($new_xcvr_params_str =~ m/($param.*\n)/i) {
|
||||
my $value = $1;
|
||||
# remove the leading attribute name and \s and '('
|
||||
$value =~ s/^.*\(//;
|
||||
|
||||
# remove the trailing '),\n'
|
||||
$value =~ s/\).*$//;
|
||||
|
||||
# save the attribute into the hash
|
||||
chomp($value);
|
||||
$params{$param} = $value;
|
||||
# print "$value -> ";
|
||||
# print "$params{$param}\n"
|
||||
} else {
|
||||
print "@[$myname] WARNING: Can not find $param\n";
|
||||
}
|
||||
}
|
||||
} elsif ($xcvr_params_str =~ m/($xcvr_type\_$param.*\n)/i) {
|
||||
my $value = $1;
|
||||
$value =~ s/${xcvr_type}_//;
|
||||
# remove the leading attribute name and \s and '('
|
||||
$value =~ s/^.*\(//;
|
||||
|
||||
# remove the trailing '),\n'
|
||||
$value =~ s/\).*$//;
|
||||
|
||||
# save the attribute into the hash
|
||||
chomp($value);
|
||||
$params{$param} = $value;
|
||||
} else {
|
||||
print "@[$myname] WARNING: Can not find $xcvr_type\_$param\n";
|
||||
}
|
||||
|
||||
}
|
||||
close(READFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
return %params;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Save the attribute hash into a file
|
||||
# Required parameters : $1 - file name
|
||||
# $2 - parameter hash - reference
|
||||
################################################################################
|
||||
sub save_to_file {
|
||||
|
||||
my ($pfile, $params_ref) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
|
||||
# Try to open file for write
|
||||
open(WRITEFILE, ">$pfile") or die print "@[$myname] Can not open file called $pfile for writing.\n";
|
||||
|
||||
foreach my $key (sort keys %$params_ref){
|
||||
print WRITEFILE ".$key ($$params_ref{$key}),\n";
|
||||
}
|
||||
close(WRITEFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Update util_adxcvr_xc[m|h] with the generated attributes
|
||||
# Required parameters : $1 - file name and location of the util_adxcvr_xcm.v
|
||||
# $2 - GT type, valid values {GTXE2, GTHE3, GTHE4}
|
||||
# $3 - generated parameter hash - reference
|
||||
################################################################################
|
||||
sub xcvr_diff {
|
||||
|
||||
my ($pfile, $gt_type, $params_ref) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
|
||||
# Try to open file for read
|
||||
if (not open(READFILE, "<$pfile")) {
|
||||
print "WARNING@[$myname] : Can not update $pfile ...\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
my @File = "";
|
||||
while (my $fline = <READFILE>) {
|
||||
push(@File, $fline);
|
||||
}
|
||||
|
||||
# Find the GT's attributes location in the file
|
||||
my $gt_paramblock_start = 0;
|
||||
my $gt_paramblock_end = 0;
|
||||
for my $i (0 .. $#File) {
|
||||
if ($File[$i] =~ m/\b$gt_type/i) {
|
||||
$gt_paramblock_start = $i;
|
||||
}
|
||||
if ($File[$i] =~ m/\bi_$gt_type/i) {
|
||||
$gt_paramblock_end = $i;
|
||||
}
|
||||
}
|
||||
close(READFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
|
||||
## Update the attributes with the generated values
|
||||
for my $i ($gt_paramblock_start..$gt_paramblock_end) {
|
||||
if ($File[$i] =~ m/\.\w*/) { ## it match a word which starts with a dot
|
||||
my $param = $File[$i];
|
||||
$param =~ s/^\s*\.//;
|
||||
$param =~ s/\s*\(.*$//;
|
||||
chomp($param);
|
||||
if (exists $$params_ref{$param}) {
|
||||
$File[$i] =~ s/\(.*?\)/\($$params_ref{$param}\)/;
|
||||
} else {
|
||||
## print "@[$myname] WARNING : Parameter $param does not exist in the generated GT instance!\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Try to open file for write
|
||||
open(WRITEFILE, ">$pfile") or die print "@[$myname] Can not open file called $pfile for writing.\n";
|
||||
|
||||
foreach my $line (@File){
|
||||
print WRITEFILE $line;
|
||||
}
|
||||
close(WRITEFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
|
||||
## save the diff between the current and updated XCVR files
|
||||
my $file_name = $pfile;
|
||||
$file_name =~ s/^.*\///;
|
||||
$file_name =~ s/\.v$//;
|
||||
|
||||
my $check_git = `git status`;
|
||||
if ($check_git =~ m/On branch/i) {
|
||||
system "git diff $pfile > $file_name.diff";
|
||||
system "git checkout -- $pfile";
|
||||
} else {
|
||||
print "WARNING: ADI's util_xcvr's can not be updated, because the current direcotry is NOT an HDL repository!\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Parse out the default value of a GT instance
|
||||
# Required parameters : $1 - file name and location of the util_adxcvr_xc[m|h].v
|
||||
# $2 - GT type, valid values {GTXE2, GTHE3, GTHE4}
|
||||
################################################################################
|
||||
sub xcvr_default {
|
||||
|
||||
my ($pfile, $gt_type) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
my %parameters;
|
||||
my %default_attributes;
|
||||
|
||||
# Try to open file for read
|
||||
if (not open(READFILE, "<$pfile")) {
|
||||
print "WARNING@[$myname] : Can not update $pfile ...\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Save file into an array, also save all parameters into a hash
|
||||
my @File = "";
|
||||
while (my $fline = <READFILE>) {
|
||||
push(@File, $fline);
|
||||
if ($fline =~ m/\bparameter\b/i) {
|
||||
my @param = split '=', $fline;
|
||||
(my $param_name) = $param[0] =~ m/\b\w*\s+$/g;
|
||||
$param_name =~ s/^\s+|\s+$//g;
|
||||
my $param_value = $param[1];
|
||||
$param_value =~ s/,.*$//;
|
||||
$param_value =~ s/^\s+|\s+$//g;
|
||||
$parameters{$param_name} = $param_value;
|
||||
}
|
||||
}
|
||||
|
||||
# Find the GT's attributes location in the file
|
||||
my $gt_paramblock_start = 0;
|
||||
my $gt_paramblock_end = 0;
|
||||
for my $i (0 .. $#File) {
|
||||
if ($File[$i] =~ m/\b$gt_type/i) {
|
||||
$gt_paramblock_start = $i;
|
||||
}
|
||||
if ($File[$i] =~ m/\bi_$gt_type/i) {
|
||||
$gt_paramblock_end = $i;
|
||||
}
|
||||
}
|
||||
close(READFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
|
||||
## Find all the attribute and save it into a hash
|
||||
for my $i ($gt_paramblock_start..$gt_paramblock_end) {
|
||||
if ($File[$i] =~ m/\.\w*/) { ## it match a word which starts with a dot
|
||||
my $param = $File[$i];
|
||||
my $value = $File[$i];
|
||||
# parse out the parameter name
|
||||
$param =~ s/^\s*\.//;
|
||||
$param =~ s/\s*\(.*$//;
|
||||
chomp($param);
|
||||
# parse out the value name
|
||||
$value =~ s/^.*\(//;
|
||||
$value =~ s/\).*$//;
|
||||
chomp($value);
|
||||
## if it's a module parameter switch to its value
|
||||
if (exists $parameters{$value}) {
|
||||
$value = $parameters{$value};
|
||||
}
|
||||
## convert to hex only if it's a binary number, leave it as it is otherwise
|
||||
my $old_value = $value;
|
||||
$value =~ s/^.*b//;
|
||||
if ($value =~ /^[0-1]+$/) {
|
||||
$value = sprintf('0x%X', oct("0b$value"));
|
||||
$default_attributes{$param} = $value;
|
||||
} else {
|
||||
$default_attributes{$param} = $old_value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return \%default_attributes;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Generate the required DRP sequence for software
|
||||
# Required parameters : $1 - util_xcvr diff file
|
||||
# $2 - parameter hash - reference
|
||||
# $3 - target file name
|
||||
################################################################################
|
||||
sub gen_drp_cmd {
|
||||
|
||||
my ($pfile_rd, $xcvr_params_ref, $pfile_wr) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
#my $t3 = Text::SimpleTable::AutoWidth->new( captions => [qw/ DRP_register Value_binary Value_hex /] );
|
||||
my %drp_access;
|
||||
|
||||
# Try to open file for read
|
||||
open(READFILE, "<$pfile_rd") or die print "@[$myname] Can not open file called $pfile_rd for reading.\n";
|
||||
my @File = "";
|
||||
while (my $fline = <READFILE>) {
|
||||
if ($fline =~ m/^\+\s+/) {
|
||||
push(@File, $fline);
|
||||
}
|
||||
}
|
||||
close(READFILE) or die print "@[$myname] Can not close file called $pfile_rd.\n";
|
||||
|
||||
# Try to open file for write
|
||||
open(WRITEFILE, ">$pfile_wr") or die print "@[$myname] Can not open file called $pfile_wr for writing.\n";
|
||||
|
||||
# Parse the differences and check if the attribute is valid
|
||||
for my $i (0 .. $#File) {
|
||||
my $param_name = $File[$i];
|
||||
#print "$param_name\n";
|
||||
$param_name =~ s/^\+\s*\.//;
|
||||
$param_name =~ s/\s+.*$//;
|
||||
chomp($param_name);
|
||||
#print "$param_name\n\n";
|
||||
|
||||
my $param_value = $File[$i];
|
||||
$param_value =~ s/^.*\(//;
|
||||
$param_value =~ s/\).*$//;
|
||||
chomp($param_value);
|
||||
#print "$param_value\n";
|
||||
## ignore all attributes which are related to unused features and
|
||||
## double check attribute validity
|
||||
if ($param_name =~ /^(?!ES_)(?!PCIE_)(?!TXPI_)(?!TX_PI_BIASSET)/) {
|
||||
if (exists $$xcvr_params_ref{$param_name}) {
|
||||
my $param_value_hex = $param_value;
|
||||
$param_value_hex =~ s/^.*'b//;
|
||||
## convert to hex only if it's a binary number, leave it as it is otherwise
|
||||
if ($param_value_hex =~ /^[0-1]+$/) {
|
||||
$param_value_hex = sprintf('0x%X', oct("0b$param_value_hex"));
|
||||
}
|
||||
#$t3->row($param_name, $param_value, $param_value_hex);
|
||||
print WRITEFILE "$param_name - $param_value - $param_value_hex\n";
|
||||
$drp_access{$param_name} = $param_value_hex;
|
||||
} else {
|
||||
if ($param_name ne "") {
|
||||
print "@[$myname] WARNING : Parameter $param_name does not exist from $pfile_rd!\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#print WRITEFILE $t3->draw;
|
||||
print WRITEFILE "\n";
|
||||
close(WRITEFILE) or die print "@[$myname] Can not close file called $pfile_wr.\n";
|
||||
|
||||
return \%drp_access;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Parse all the PLL dividers into a file
|
||||
# Required parameters : $1 - name of the file
|
||||
# $2 - generated common parameter hash - reference
|
||||
# $3 - generated channel parameter hash - reference
|
||||
#
|
||||
# Return value - a hash with the PLL dividers for further processing
|
||||
#
|
||||
################################################################################
|
||||
sub parse_pll_dividers {
|
||||
|
||||
my ($pfile, $cm_params_ref, $ch_params_ref) = @_;
|
||||
my $myname = (caller(0))[3];
|
||||
|
||||
## Hash for storing all the PLL dividers
|
||||
my %pll_dividers = (
|
||||
"QPLL0_FBDIV" => 0,
|
||||
"QPLL0_FBDIV_G3" => 0,
|
||||
"QPLL0_REFCLK_DIV" => 0,
|
||||
"QPLL0CLKOUT_RATE" => 0,
|
||||
"QPLL1_FBDIV" => 0,
|
||||
"QPLL1_FBDIV_G3" => 0,
|
||||
"QPLL1_REFCLK_DIV" => 0,
|
||||
"QPLL1CLKOUT_RATE" => 0,
|
||||
"CPLL_FBDIV" => 0,
|
||||
"CPLL_FBDIV_45" => 0,
|
||||
"CPLL_REFCLK_DIV" => 0,
|
||||
"RXOUT_DIV" => 0,
|
||||
"TXOUT_DIV" => 0,
|
||||
"RX_CLK25_DIV" => 0,
|
||||
"TX_CLK25_DIV" => 0
|
||||
);
|
||||
my %used_pll_dividers;
|
||||
|
||||
# Update the PLL divider hash
|
||||
foreach my $pll_dividers_key (keys %pll_dividers) {
|
||||
if (exists $$cm_params_ref{$pll_dividers_key}) {
|
||||
$used_pll_dividers{$pll_dividers_key} = $$cm_params_ref{$pll_dividers_key};
|
||||
}
|
||||
if (exists $$ch_params_ref{$pll_dividers_key}) {
|
||||
$used_pll_dividers{$pll_dividers_key} = $$ch_params_ref{$pll_dividers_key};
|
||||
}
|
||||
}
|
||||
|
||||
# Try to open file for write
|
||||
open(WRITEFILE, ">$pfile") or die print "@[$myname] Can not open file called $pfile for writing.\n";
|
||||
|
||||
foreach my $pll_dividers_key (keys %used_pll_dividers) {
|
||||
print WRITEFILE "$pll_dividers_key = $used_pll_dividers{$pll_dividers_key}\n";
|
||||
}
|
||||
|
||||
close(WRITEFILE) or die print "@[$myname] Can not close file called $pfile.\n";
|
||||
|
||||
return \%used_pll_dividers;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Parse the generated file returned by the GT Wizard of a given configuration
|
||||
# and return all the GT attribute and its values
|
||||
# Required parameters : $1 - XCVR type
|
||||
# $2 - GT Instance type (expected values: 'CHANNEL' or 'COMMON')
|
||||
# $3 - the path to util_adxcvr_xc[m|h]
|
||||
#
|
||||
################################################################################
|
||||
sub parse_gt_attribute {
|
||||
|
||||
my $myname = (caller(0))[3];
|
||||
my ($xcvr_type, $xcvr_ins_type, $hdl_path) = @_;
|
||||
|
||||
## arrays and hashes for the attributes
|
||||
my @xcvr_attribute_names;
|
||||
my %xcvr_attribute;
|
||||
|
||||
if (uc($xcvr_type) eq "GTXE2"){
|
||||
## common and gt
|
||||
my $fp_xcvr_wrapper = `find . -iname '*$xcvr_type*_$xcvr_ins_type.v' -print0 -quit`;
|
||||
#chomp($fp_xcvr_wrapper);
|
||||
|
||||
## hdl's repo util_adxcvr files -- we need this for comparison and default values
|
||||
$xcvr_ins_type = lc($xcvr_ins_type);
|
||||
my $xcvr_path;
|
||||
if ($xcvr_ins_type eq "gt") {
|
||||
$xcvr_path = "${hdl_path}/library/xilinx/util_adxcvr/util_adxcvr_xch.v";
|
||||
|
||||
} elsif ($xcvr_ins_type eq "common") {
|
||||
$xcvr_path = "${hdl_path}/library/xilinx/util_adxcvr/util_adxcvr_xcm.v";
|
||||
} else {
|
||||
die print "@[$myname] Invalid instance type. Expected values are GT or COMMON.\n";
|
||||
}
|
||||
|
||||
if (($fp_xcvr_wrapper eq "") && ($xcvr_ins_type eq "common")) {
|
||||
## print "NOTE : QPLL is not used in this configuration ...\n";
|
||||
} else {
|
||||
|
||||
# extract all the attributes
|
||||
# TODO: get name from the fp_xcvr_wrapper file
|
||||
my $ls = `pwd`;
|
||||
@xcvr_attribute_names = get_attribute_name ($fp_xcvr_wrapper);
|
||||
%xcvr_attribute = get_attribute_value ($fp_xcvr_wrapper, "$xcvr_type\_$xcvr_ins_type", \@xcvr_attribute_names);
|
||||
|
||||
# save into a file
|
||||
save_to_file("$xcvr_ins_type.txt", \%xcvr_attribute);
|
||||
|
||||
# create a git diff for comparison
|
||||
xcvr_diff($xcvr_path, $xcvr_type, \%xcvr_attribute);
|
||||
|
||||
}
|
||||
} else{
|
||||
## find the COMMON and CHANNEL instances
|
||||
my $fp_xcvr = `find . -iname '*$xcvr_type\_$xcvr_ins_type.v' -print0 -quit`;
|
||||
my $fp_xcvr_wrapper = `find . -iname '*gt*_$xcvr_ins_type\_wrapper.v' -print0 -quit`;
|
||||
|
||||
## hdl's repo util_adxcvr files -- we need this for comparison and default values
|
||||
$xcvr_ins_type = lc($xcvr_ins_type);
|
||||
my $xcvr_path;
|
||||
if ($xcvr_ins_type eq "channel") {
|
||||
$xcvr_path = "${hdl_path}/library/xilinx/util_adxcvr/util_adxcvr_xch.v";
|
||||
|
||||
} elsif ($xcvr_ins_type eq "common") {
|
||||
$xcvr_path = "${hdl_path}/library/xilinx/util_adxcvr/util_adxcvr_xcm.v";
|
||||
} else {
|
||||
die print "@[$myname] Invalid instance type. Expected values are CHANNEL or COMMON.\n";
|
||||
}
|
||||
|
||||
if (($fp_xcvr eq "") && ($xcvr_ins_type eq "common")) {
|
||||
## print "NOTE : QPLL is not used in this configuration ...\n";
|
||||
} else {
|
||||
|
||||
# extract all the attributes
|
||||
@xcvr_attribute_names = get_attribute_name ($fp_xcvr);
|
||||
%xcvr_attribute = get_attribute_value ($fp_xcvr_wrapper, "$xcvr_type\_$xcvr_ins_type", \@xcvr_attribute_names);
|
||||
|
||||
# save into a file
|
||||
save_to_file("$xcvr_ins_type.txt", \%xcvr_attribute);
|
||||
|
||||
# create a git diff for comparison
|
||||
xcvr_diff($xcvr_path, $xcvr_type, \%xcvr_attribute);
|
||||
|
||||
}
|
||||
}
|
||||
return \%xcvr_attribute;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Parse the generated file returned by the GT Wizard of a given configuration
|
||||
# Required parameters : $1 - XCVR type
|
||||
# $2 - the path to the HDL repository
|
||||
#
|
||||
# Return value - a hash with the DRP registers for further processing
|
||||
#
|
||||
################################################################################
|
||||
sub parse_gt {
|
||||
|
||||
my ($xcvr_type, $hdl_path) = @_;
|
||||
my %gt_drp_access;
|
||||
|
||||
my $xcvr_common;
|
||||
my $xcvr_channel;
|
||||
|
||||
## hash references for the attribute hash
|
||||
if (uc($xcvr_type) eq "GTXE2"){
|
||||
## common and gt
|
||||
$xcvr_common = parse_gt_attribute($xcvr_type, "common", $hdl_path);
|
||||
$xcvr_channel = parse_gt_attribute($xcvr_type, "gt", $hdl_path);
|
||||
|
||||
} else{
|
||||
$xcvr_common = parse_gt_attribute($xcvr_type, "common", $hdl_path);
|
||||
$xcvr_channel = parse_gt_attribute($xcvr_type, "channel", $hdl_path);
|
||||
}
|
||||
|
||||
## create the drp hash with info related to common and channel attributes and
|
||||
## PLL dividers
|
||||
if (keys %{ $xcvr_common }) {
|
||||
$gt_drp_access{'common'} = gen_drp_cmd("util_adxcvr_xcm.diff", $xcvr_common, "common_drp_access.txt");
|
||||
}
|
||||
$gt_drp_access{'channel'} = gen_drp_cmd("util_adxcvr_xch.diff", $xcvr_channel, "channel_drp_access.txt");
|
||||
$gt_drp_access{'pll_dividers'} = parse_pll_dividers("pll_div.txt", $xcvr_common, $xcvr_channel);
|
||||
|
||||
## prune out all the PLL dividers from the common/channel hash
|
||||
foreach my $key (keys %{ $gt_drp_access{'pll_dividers'}}) {
|
||||
if (exists $gt_drp_access{'channel'}{$key}) {
|
||||
delete $gt_drp_access{'channel'}{$key};
|
||||
}
|
||||
if (exists $gt_drp_access{'common'}{$key}) {
|
||||
delete $gt_drp_access{'common'}{$key};
|
||||
}
|
||||
}
|
||||
|
||||
return \%gt_drp_access;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Print a table in a CSV supported format
|
||||
# Required parameters : $1 - DRP hash reference
|
||||
# $1 - File name
|
||||
#
|
||||
# Return value - None
|
||||
#
|
||||
################################################################################
|
||||
sub print_table {
|
||||
|
||||
my ($gt_drp_ref, $gt_defcommon_ref, $gt_defchannel_ref, $file_name) = @_;
|
||||
my @gt_configs;
|
||||
my @gt_attributes;
|
||||
my %gt_drp_buf;
|
||||
|
||||
## save all configuration into an array
|
||||
foreach my $config_key (keys %{ $gt_drp_ref }) {
|
||||
push(@gt_configs, $config_key);
|
||||
}
|
||||
|
||||
## save all attributes into an array
|
||||
foreach my $config_key (keys %{ $gt_drp_ref }) {
|
||||
foreach my $type_key (keys %{ $$gt_drp_ref{$config_key} }) {
|
||||
if ($type_key ne 'pll_dividers') {
|
||||
foreach my $attribute_key (keys %{ $$gt_drp_ref{$config_key}{$type_key} }) {
|
||||
my $exist = 0;
|
||||
foreach (@gt_attributes) {
|
||||
if ($_ eq $attribute_key) {
|
||||
$exist = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if (not $exist) {
|
||||
push (@gt_attributes, $attribute_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## open file
|
||||
open(MYTABLE, ">$file_name.csv") or die print "Can not open file called $file_name.csv for writing.\n";
|
||||
|
||||
print MYTABLE "Attribute_names,\t";
|
||||
print MYTABLE "Default_value,\t";
|
||||
|
||||
## print the header
|
||||
foreach my $config_key (keys %{ $gt_drp_ref }) {
|
||||
print MYTABLE "$config_key,\t";
|
||||
}
|
||||
print MYTABLE "\n";
|
||||
|
||||
## populate the CSV table
|
||||
for my $i (0 .. $#gt_attributes) {
|
||||
print MYTABLE "$gt_attributes[$i],\t";
|
||||
my $default_value = "";
|
||||
if (exists $$gt_defcommon_ref{$gt_attributes[$i]}) {
|
||||
$default_value = $$gt_defcommon_ref{$gt_attributes[$i]};
|
||||
## convert the default value to a 0xhhhh format
|
||||
$default_value = lc($default_value);
|
||||
$default_value =~ s/^\d*\'h/0x/gi;
|
||||
print MYTABLE "$default_value,\t";
|
||||
} elsif (exists $$gt_defchannel_ref{$gt_attributes[$i]}) {
|
||||
$default_value = $$gt_defchannel_ref{$gt_attributes[$i]};
|
||||
## convert the default value to a 0xhhhh format
|
||||
$default_value = lc($default_value);
|
||||
$default_value =~ s/^\d*\'h/0x/gi;
|
||||
print MYTABLE "$default_value,\t";
|
||||
} else {
|
||||
print MYTABLE ",\t";
|
||||
}
|
||||
|
||||
for my $j (0 .. $#gt_configs) {
|
||||
my $is_exist = 0;
|
||||
my $normalized;
|
||||
my $value;
|
||||
foreach my $type_key (keys %{ $$gt_drp_ref{$gt_configs[$j]}}) {
|
||||
if ((exists $$gt_drp_ref{$gt_configs[$j]}{$type_key}{$gt_attributes[$i]}) and ($$gt_drp_ref{$gt_configs[$j]}{$type_key}{$gt_attributes[$i]})) {
|
||||
$value = $$gt_drp_ref{$gt_configs[$j]}{$type_key}{$gt_attributes[$i]};
|
||||
$normalized = $value;
|
||||
$normalized =~ s/^\d*\'h/0x/gi;
|
||||
# print "$normalized : $default_value\n";
|
||||
#if (oct(lc($value)) != oct(lc($default_value))) {
|
||||
#if ((lc($$gt_drp_ref{$gt_configs[$j]}{$type_key}{$gt_attributes[$i]})) eq ($default_value)) {
|
||||
if ($normalized ne $default_value){
|
||||
print MYTABLE "$normalized,\t";
|
||||
} else {
|
||||
print MYTABLE ",\t";
|
||||
}
|
||||
$is_exist = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
## if the current attribute does not have a value in the current configuration
|
||||
if ($is_exist == 0) {
|
||||
print MYTABLE ",\t";
|
||||
}
|
||||
}
|
||||
print MYTABLE "\n";
|
||||
}
|
||||
close(MYTABLE) or die print "Can not close file called $file_name.csv.\n";
|
||||
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Prune out all the entries which are present in every configuration with the
|
||||
# same value.
|
||||
# Required parameters : $1 - GT DRP hash generated by the parser
|
||||
#
|
||||
################################################################################
|
||||
sub prune_drp_access {
|
||||
|
||||
my ($gt_drp_ref) = @_;
|
||||
|
||||
my %gt_generic_drp;
|
||||
my $is_generic;
|
||||
|
||||
## select a random configuration
|
||||
my @gt_drp_ref_keys = keys %$gt_drp_ref;
|
||||
my $ref_conf = $gt_drp_ref_keys[rand @gt_drp_ref_keys];
|
||||
|
||||
foreach my $gt_ref_conf_type_key (keys %{ $$gt_drp_ref{$ref_conf} }) {
|
||||
foreach my $gt_ref_conf_attribute_key (keys %{ $$gt_drp_ref{$ref_conf}{$gt_ref_conf_type_key} }) {
|
||||
$is_generic = 1;
|
||||
foreach my $gt_drp_config_key (keys %{ $gt_drp_ref }) {
|
||||
|
||||
if ($gt_drp_config_key ne $ref_conf) {
|
||||
if (exists $$gt_drp_ref{$gt_drp_config_key}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key}) {
|
||||
if ($$gt_drp_ref{$gt_drp_config_key}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key} eq '') {
|
||||
delete $$gt_drp_ref{$gt_drp_config_key}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key};
|
||||
}
|
||||
## check if a given attribute value is the same in all the configurations
|
||||
elsif ($$gt_drp_ref{$ref_conf}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key} ne
|
||||
$$gt_drp_ref{$gt_drp_config_key}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key}) {
|
||||
$is_generic = 0;
|
||||
}
|
||||
} else {
|
||||
## if it does not exists, can not be generic
|
||||
$is_generic = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($is_generic) {
|
||||
# Store it into another hash
|
||||
$gt_generic_drp{'gt_global'}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key} = $$gt_drp_ref{$ref_conf}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key};
|
||||
|
||||
## Delete the attribute from the \%gt_drp_ref
|
||||
foreach my $gt_drp_config_key (keys %{ $gt_drp_ref }) {
|
||||
delete $$gt_drp_ref{$gt_drp_config_key}{$gt_ref_conf_type_key}{$gt_ref_conf_attribute_key};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \%gt_generic_drp;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Generate a value distribution hash for each variable
|
||||
#
|
||||
# E.g. attribute_name -> %existing_values -> @configuration
|
||||
#
|
||||
# Required parameters : $1 - GT DRP hash generated by the parser
|
||||
#
|
||||
################################################################################
|
||||
sub drp_value_distribution {
|
||||
|
||||
my ($gt_drp_ref) = @_;
|
||||
my %gt_drp_dist;
|
||||
|
||||
foreach my $config_key (keys %{ $gt_drp_ref }) {
|
||||
foreach my $type_key (keys %{ $$gt_drp_ref{$config_key} }) {
|
||||
foreach my $attribute_key (keys %{ $$gt_drp_ref{$config_key}{$type_key} }) {
|
||||
my $value = $$gt_drp_ref{$config_key}{$type_key}{$attribute_key};
|
||||
## store a new configuration name to a (attribute,value) pair
|
||||
push (@{ $gt_drp_dist{$attribute_key}{$value} }, $config_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## sort the arrays with the GT configuration to improve readability
|
||||
foreach my $attribute_key (keys %gt_drp_dist) {
|
||||
foreach my $value (keys %{ $gt_drp_dist{$attribute_key} }) {
|
||||
my @sorted = sort @{ $gt_drp_dist{$attribute_key}{$value} };
|
||||
@{ $gt_drp_dist{$attribute_key}{$value} } = @sorted;
|
||||
}
|
||||
}
|
||||
|
||||
return \%gt_drp_dist;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Generate a VCO frequency distribution hash for each variable
|
||||
#
|
||||
# E.g. attribute_name -> %VCO_freq -> @attribute_value
|
||||
#
|
||||
# Required parameters : $1 - GT DRP hash generated by the parser
|
||||
#
|
||||
################################################################################
|
||||
sub uniq {
|
||||
my %seen;
|
||||
grep !$seen{$_}++, @_;
|
||||
}
|
||||
|
||||
sub drp_vcof_distribution {
|
||||
|
||||
my ($gt_drp_ref, $gt_default_ref) = @_;
|
||||
my %gt_drp_dist;
|
||||
|
||||
foreach my $config_key (keys %{ $gt_drp_ref }) {
|
||||
foreach my $type_key (keys %{ $$gt_drp_ref{$config_key} }) {
|
||||
if ($type_key ne 'pll_dividers') {
|
||||
foreach my $attribute_key (keys %{ $$gt_drp_ref{$config_key}{$type_key} }) {
|
||||
my @words = split /_/, $config_key;
|
||||
my $lane_rate;
|
||||
if ($words[4]) {
|
||||
$lane_rate = "$words[2].$words[3]";
|
||||
} else {
|
||||
$lane_rate = $words[2];
|
||||
}
|
||||
if ($$gt_drp_ref{$config_key}{'pll_dividers'}{'RXOUT_DIV'}) {
|
||||
my $vcof = ($lane_rate * $$gt_drp_ref{$config_key}{'pll_dividers'}{'RXOUT_DIV'}) / 2;
|
||||
my $value = $$gt_drp_ref{$config_key}{$type_key}{$attribute_key};
|
||||
# my %conf_with_value;
|
||||
# $conf_with_lane_ratevalue{$value} = $config_key;
|
||||
## store a new configuration name to a (attribute,value) pair
|
||||
## push (@{ $gt_drp_dist{$attribute_key}{$vcof} }, $value);
|
||||
## push (@{ $gt_drp_dist{$attribute_key}{$vcof} }, %conf_with_value);
|
||||
# print "$vcof\n";
|
||||
push (@{ $gt_drp_dist{$attribute_key}{$vcof}{$value} }, $config_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## sort the arrays with the GT configuration to improve readability
|
||||
foreach my $attribute_key (keys %gt_drp_dist) {
|
||||
# foreach my $vcof (keys %{ $gt_drp_dist{$attribute_key} }) {
|
||||
# my @sorted = sort @{ $gt_drp_dist{$attribute_key}{$vcof} };
|
||||
# my @uniq = uniq(@sorted);
|
||||
# @{ $gt_drp_dist{$attribute_key}{$vcof} } = @uniq;
|
||||
# }
|
||||
## add the default value to each attribute
|
||||
if (exists $$gt_default_ref{'common'}{$attribute_key}) {
|
||||
$gt_drp_dist{$attribute_key}{'default'} = $$gt_default_ref{'common'}{$attribute_key}
|
||||
}
|
||||
if (exists $$gt_default_ref{'channel'}{$attribute_key}) {
|
||||
$gt_drp_dist{$attribute_key}{'default'} = $$gt_default_ref{'channel'}{$attribute_key}
|
||||
}
|
||||
}
|
||||
|
||||
return \%gt_drp_dist;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# MAIN program
|
||||
################################################################################
|
||||
|
||||
## Hash for storing all the DRP register values
|
||||
my %gt_drp;
|
||||
my %gt_default;
|
||||
|
||||
## Valid transceiver types are: GTHE3, GTHE4, GTYE3, GTYE4
|
||||
my $xcvr_type = $ARGV[0];
|
||||
|
||||
## Check the ADI_HDL_DIR environment variable, exist if it does not exist
|
||||
my $hdl_path = "";
|
||||
if (defined $ENV{ADI_HDL_DIR}) {
|
||||
$hdl_path = $ENV{ADI_HDL_DIR};
|
||||
} else {
|
||||
# print `pwd`;
|
||||
my $curr_dir = `pwd`;
|
||||
my $new_str = chop($curr_dir);
|
||||
my $relative_path = "/../../../../../..";
|
||||
$hdl_path = $curr_dir.$relative_path;
|
||||
# print "ERROR: ADI_HDL_DIR is undefined! Please define this environment variable.\n";
|
||||
# exit;
|
||||
}
|
||||
|
||||
## Currently only GTXE2, GTHE3, GTYE3, GTHE4 and GTYE4 is supported
|
||||
print "NOTE: To parse the generated GT IP, change directory to *.gen/sources_1/ip/ ...\n";
|
||||
if (not defined $xcvr_type) {
|
||||
die "ERROR Need to define an XCVR type. (GTXE2, GTHE3, GTHE4, GTYE3, GTYE4)";
|
||||
} elsif ((uc($xcvr_type) ne "GTHE3") and (uc($xcvr_type) ne "GTHE4") and (uc($xcvr_type) ne "GTYE3") and (uc($xcvr_type) ne "GTYE4") and (uc($xcvr_type) ne "GTXE2")) {
|
||||
die "ERROR Wrong XCVR type, should be GTXE2, GTHE3, GTHE4, GTYE3, GTYE4";
|
||||
}
|
||||
|
||||
## save the default values into $gt_drp->'default'
|
||||
$gt_default{'common'} = xcvr_default("$hdl_path/library/xilinx/util_adxcvr/util_adxcvr_xcm.v", $xcvr_type);
|
||||
$gt_default{'channel'} = xcvr_default("$hdl_path/library/xilinx/util_adxcvr/util_adxcvr_xch.v", $xcvr_type);
|
||||
|
||||
## iterate through all the configurations
|
||||
my @gt_config_list = `ls`;
|
||||
foreach my $gt_config (@gt_config_list) {
|
||||
chomp($gt_config);
|
||||
$gt_config =~ s/^\s+|\s+$//g;
|
||||
if (-d $gt_config) {
|
||||
chdir $gt_config;
|
||||
$gt_drp{$gt_config} = parse_gt($xcvr_type, $hdl_path);
|
||||
chdir "../";
|
||||
}
|
||||
}
|
||||
|
||||
## prune the DRP access which is generic for all the configuration
|
||||
my $gt_generic_drp = prune_drp_access(\%gt_drp);
|
||||
|
||||
open(WRITEFILE, ">$xcvr_type\_cfng.txt") or die print "Can not open file called $xcvr_type\_cfng.txt for writing.\n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE "Unique configuration/attribute values\n";
|
||||
print WRITEFILE "The following attribute/value pairs are unique for one or more configuration\n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE Dumper(%gt_drp);
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE "Common configuration/attribute values\n";
|
||||
print WRITEFILE "The following attribute/value pairs are the same for each configuration \n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE Dumper(%{ $gt_generic_drp });
|
||||
close(WRITEFILE) or die print "Can not close file called daq2_gthe4.txt.\n";
|
||||
|
||||
print_table(\%gt_drp, $gt_default{'common'}, $gt_default{'channel'}, "table_unique");
|
||||
print_table($gt_generic_drp, $gt_default{'common'}, $gt_default{'channel'}, "table_common");
|
||||
|
||||
# create a hash table which reflects the value distribution of each DRP attribute
|
||||
# in function of lane rates and reference clock
|
||||
my $gt_drp_var_dist = drp_value_distribution(\%gt_drp);
|
||||
|
||||
open(WRITEFILE, ">$xcvr_type\_var_dist.txt") or die print "Can not open file called $xcvr_type\_var_dist.txt for writing.\n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE "Value distribution of each DRP attribute in function of lane rates\n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE Dumper(%{ $gt_drp_var_dist });
|
||||
close(WRITEFILE) or die print "Can not close file called $xcvr_type\_var_dist.txt.\n";
|
||||
|
||||
# create a hash table which reflects the value distribution of each DRP attribute
|
||||
# in function of VCO frequency
|
||||
my $gt_drp_vco_dist = drp_vcof_distribution (\%gt_drp, \%gt_default);
|
||||
|
||||
open(WRITEFILE, ">$xcvr_type\_vco_dist.txt") or die print "Can not open file called $xcvr_type\_vco_dist.txt for writing.\n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE "Value distribution of each DRP attribute in function of VCO frequency\n";
|
||||
print WRITEFILE "========================================================================\n";
|
||||
print WRITEFILE Dumper(%{ $gt_drp_vco_dist });
|
||||
close(WRITEFILE) or die print "Can not close file called $xcvr_type\_vco_dist.txt.\n";
|
||||
|
|
@ -0,0 +1,531 @@
|
|||
###############################################################################
|
||||
# CPLL - generate reference clocks for a given Lane Rate
|
||||
#
|
||||
# Attributes: NOTE lane rate should be define in kHz
|
||||
#
|
||||
# Return: the result will be in millihertz
|
||||
# E.g. set value_MHz [format "%.7f" [expr $value / 1e9]]
|
||||
#
|
||||
###############################################################################
|
||||
proc cpll_ref_clk_gen { lane_rate } {
|
||||
|
||||
#
|
||||
# fLineRate = (REF_CLK * (FBDIV * FBDIV_45) / REFCLK_DIV) / OUT_DIV
|
||||
#
|
||||
|
||||
set out_div_l { 1 2 4 8 }
|
||||
set refclk_div_l { 1 2 }
|
||||
set fbdiv_l { 1 2 3 4 5 }
|
||||
set fbdiv_45_l { 4 5 }
|
||||
set pllclkout_l ""
|
||||
set ref_clk_l ""
|
||||
|
||||
## Calculate the VCO
|
||||
for {set i 0} {$i < [llength $out_div_l]} {incr i} {
|
||||
## to get the right resolution which is liked by the Wizard we have to upscale
|
||||
## the value of the Lane Rate
|
||||
set pll_out [expr [expr [expr $lane_rate * 1e6] * [lindex $out_div_l $i]] / 2]
|
||||
if { ($pll_out >= [expr 2 * 1e12]) && ($pll_out <= [expr 6.25 * 1e12]) } {
|
||||
lappend pllclkout_l $pll_out
|
||||
}
|
||||
}
|
||||
|
||||
## Calculate the reference clock
|
||||
for {set i 0 } {$i < [llength $pllclkout_l]} {incr i} {
|
||||
for {set j 0} {$j < [llength $refclk_div_l]} {incr j} {
|
||||
for {set k 0} {$k < [llength $fbdiv_l]} {incr k} {
|
||||
for {set l 0} {$l < [llength $fbdiv_45_l]} {incr l} {
|
||||
set ref_clk [expr [expr [lindex $pllclkout_l $i] * [lindex $refclk_div_l $j]] / [expr [lindex $fbdiv_l $k] * [lindex $fbdiv_45_l $l]]]
|
||||
if {[lsearch $ref_clk_l [expr $ref_clk / 1e9]] < 0} {
|
||||
## Apperantly the Wizard support a maximum 800 MHz reference clock
|
||||
if { $ref_clk <= [expr 8 * 1e11] } {
|
||||
lappend ref_clk_l [expr $ref_clk / 1e9]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [lsort -real $ref_clk_l]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# QPLL - generate reference clocks for a given Lane Rate - does not support
|
||||
# fractional-N
|
||||
#
|
||||
# Attributes: lane rate should be define in kHz
|
||||
#
|
||||
# Return: the result will be in millihertz
|
||||
# E.g. set value_MHz [format "%.7f" [expr $value / 1e9]]
|
||||
#
|
||||
###############################################################################
|
||||
proc qpll_ref_clk_gen { gt_type lane_rate } {
|
||||
|
||||
#
|
||||
# fLineRate = ((REF_CLK * FBDIV) / (REFCLK_DIV * 2)) * 2 / OUT_DIV
|
||||
#
|
||||
|
||||
## OUT_DIV has a wider range in case of GTYs
|
||||
if {[string equal $gt_type GTYE3] || [string equal $gt_type GTYE4]} {
|
||||
set out_div_l { 1 2 4 8 16 32}
|
||||
} else {
|
||||
set out_div_l { 1 2 4 8 16 }
|
||||
}
|
||||
set refclk_div_l { 1 2 3 4 }
|
||||
## NOTE: At GTYE3|4 the range is 16-160
|
||||
set fbdiv_l { 16 20 32 40 60 64 66 75 80 84 90 96 100 112 120 125 150 160 }
|
||||
set pllclkout_l ""
|
||||
set ref_clk_l ""
|
||||
|
||||
## Calculate the VCO
|
||||
for {set i 0} {$i < [llength $out_div_l]} {incr i} {
|
||||
## to get the right resolution which is accepted by the Wizard we have to upscale
|
||||
## the value of the Lane Rate
|
||||
set pll_out [expr [expr [expr $lane_rate * 1e6] * [lindex $out_div_l $i]] / 2]
|
||||
if { ($pll_out >= [expr 4.9 * 1e12]) && ($pll_out <= [expr 8.1875 * 1e12]) } {
|
||||
lappend pllclkout_l $pll_out
|
||||
}
|
||||
}
|
||||
|
||||
## Calculate the reference clock
|
||||
for {set i 0 } {$i < [llength $pllclkout_l]} {incr i} {
|
||||
for {set j 0} {$j < [llength $refclk_div_l]} {incr j} {
|
||||
for {set k 0} {$k < [llength $fbdiv_l]} {incr k} {
|
||||
set ref_clk [expr [expr [expr [lindex $pllclkout_l $i] * [lindex $refclk_div_l $j]] * 2] / [lindex $fbdiv_l $k]]
|
||||
if {[lsearch $ref_clk_l [expr $ref_clk / 1e9]] < 0} {
|
||||
## Apperantly the Wizard support a maximum 800 MHz reference clock
|
||||
if { $ref_clk <= [expr 8 * 1e11] } {
|
||||
lappend ref_clk_l [expr $ref_clk / 1e9]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [lsort -real $ref_clk_l]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
##
|
||||
## This script can be used to generate multiple GTHE[3|4] PHY with the GT wizard
|
||||
## for further examination.
|
||||
## The script should be used in tandem with the gtwiz_parser.pl and must be called
|
||||
## inside a Ultrascale or Ultrascale+ project.
|
||||
##
|
||||
###############################################################################
|
||||
proc ad_gth_generator { {lane_rate_l {}} {pll_type {}} {ref_clk_l {}} } {
|
||||
|
||||
set prj_name [get_property NAME [current_project]]
|
||||
|
||||
## Currently supporting both GTH and GTY's, expected boards are ZCU102/KCU105/VCU108/VCU118
|
||||
#TODO: define this switch to be generic and support all Ultrascale/Ultrascale+ devices
|
||||
|
||||
set board [string range [get_property PART [current_project]] 0 6]
|
||||
switch $board {
|
||||
"xc7z045" {
|
||||
set gt_type GTXE2
|
||||
# set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
# set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
"xc7k325" {
|
||||
set gt_type GTXE2
|
||||
# set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
# set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
"xc7z020" {
|
||||
set gt_type GTXE2
|
||||
# set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
# set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
"xc7vx48" {
|
||||
set gt_type GTXE2
|
||||
# set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
# set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
"xc7vx69" {
|
||||
# set gt_type GTXE2
|
||||
# set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
# set ref_clk "clk1"
|
||||
# set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
puts "ERROR ad_gth_generator: Unsupported device."
|
||||
return 1
|
||||
}
|
||||
"xcku040" {
|
||||
set gt_type GTHE3
|
||||
set channel_enable [list X0Y16 X0Y17 X0Y18 X0Y19]
|
||||
set ref_clk "clk1"
|
||||
set ref_clk_source [list X0Y16 $ref_clk X0Y17 $ref_clk X0Y18 $ref_clk X0Y19 $ref_clk]
|
||||
}
|
||||
"xcvu095" {
|
||||
set gt_type GTYE3
|
||||
set channel_enable [list X0Y16 X0Y17 X0Y18 X0Y19]
|
||||
set ref_clk "clk1"
|
||||
set ref_clk_source [list X0Y16 $ref_clk X0Y17 $ref_clk X0Y18 $ref_clk X0Y19 $ref_clk]
|
||||
}
|
||||
"xczu9eg" {
|
||||
set gt_type GTHE4
|
||||
set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
"xcvu9p-" {
|
||||
set gt_type GTYE4
|
||||
set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
"xcvu37p" {
|
||||
set gt_type GTYE4
|
||||
# ??
|
||||
set channel_enable [list X0Y15 X0Y14 X0Y13 X0Y12]
|
||||
set ref_clk "clk1"
|
||||
# ??
|
||||
set ref_clk_source [list X0Y15 $ref_clk X0Y14 $ref_clk X0Y13 $ref_clk X0Y12 $ref_clk]
|
||||
}
|
||||
|
||||
default {
|
||||
puts "ERROR ad_gth_generator: Unsupported device."
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
## define the PLL's min and max range in GHz
|
||||
|
||||
set pll_min_range ""
|
||||
set pll_max_range ""
|
||||
|
||||
switch $pll_type {
|
||||
CPLL {
|
||||
set pll_min_range 0.5
|
||||
set pll_max_range 12.5
|
||||
}
|
||||
QPLL {
|
||||
if {[string equal $gt_type GTXE2]} {
|
||||
set pll_min_range 0.5
|
||||
set pll_max_range 10.3125
|
||||
} else {
|
||||
puts "Invalid PLL type -- $pll_type"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
QPLL0 {
|
||||
set pll_min_range 0.6125
|
||||
set pll_max_range 16.375
|
||||
}
|
||||
QPLL1 {
|
||||
set pll_min_range 0.5
|
||||
set pll_max_range 13.0
|
||||
}
|
||||
default {
|
||||
puts "Invalid PLL type -- $pll_type"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
set inst_num 0
|
||||
foreach lane_rate $lane_rate_l {
|
||||
|
||||
## make sure that the lane rate is inside the valid range
|
||||
if { ($lane_rate < $pll_min_range) || ($lane_rate > $pll_max_range)} {
|
||||
## TODO: remove the lane rate from the list so that it is not dragged though the parsing script
|
||||
## remove the invalid lane rate from the list
|
||||
## set lane_rate_l [lreplace $lane_rate_l [lsearch $lane_rate] [lsearch $lane_rate]]
|
||||
puts "NOTE: $lane_rate is out of $pll_type range. Skipping it..."
|
||||
continue
|
||||
} else {
|
||||
## generate the reference clock list for each lane rate
|
||||
if { [llength $ref_clk_l] == 0 } {
|
||||
switch -glob $pll_type {
|
||||
CPLL {
|
||||
set ref_clk_l [cpll_ref_clk_gen [expr $lane_rate * 1e6]]
|
||||
}
|
||||
QPLL* {
|
||||
set ref_clk_l [qpll_ref_clk_gen $gt_type [expr $lane_rate * 1e6]]
|
||||
}
|
||||
default {
|
||||
Something went wrong with $pll_type
|
||||
}
|
||||
}
|
||||
puts "NOTE: [llength $ref_clk_l] different reference clock were generated. \n $ref_clk_l"
|
||||
} else {
|
||||
## use the reference clock
|
||||
}
|
||||
|
||||
foreach ref_clk $ref_clk_l {
|
||||
|
||||
set lane_rate_txt [string replace $lane_rate [string first . $lane_rate] [string first . $lane_rate] "_"]
|
||||
set ref_clk_txt [lindex [split $ref_clk "."] 0]
|
||||
|
||||
## format the ref_clk to be wizard compatible - precision must be max
|
||||
## 7 digit with no trailing zeros
|
||||
set ref_clk [format "%.7f" $ref_clk]
|
||||
set ref_clk_float [split $ref_clk .]
|
||||
if {[lindex $ref_clk_float 1] == 0} {
|
||||
set ref_clk [lindex $ref_clk_float 0]
|
||||
} else {
|
||||
scan [lindex $ref_clk_float 1] "%1d%1d%1d%1d%1d%1d%1d" a b c d e f g
|
||||
set float_l [list $a $b $c $d $e $f $g]
|
||||
while {[lindex $float_l [expr [llength $float_l] - 1]] == 0} {
|
||||
set l_index [expr [llength $float_l] - 1]
|
||||
set float_l [lreplace $float_l $l_index $l_index]
|
||||
}
|
||||
set ref_clk [lindex $ref_clk_float 0].[join $float_l ""]
|
||||
}
|
||||
|
||||
set ip_name "$gt_type\_$pll_type\_$lane_rate_txt\_$ref_clk_txt"
|
||||
incr inst_num
|
||||
|
||||
## check if it is 7series or ultrascale/ultrascale+
|
||||
|
||||
if {[string equal $gt_type GTXE2]} {
|
||||
## 7 series
|
||||
## create a GT instance with the wizard, if already exist skip it
|
||||
if {[lsearch [get_ips] $ip_name] == -1} {
|
||||
|
||||
set float_clk [format "%.3f" [expr {$ref_clk}]]
|
||||
|
||||
create_ip -name gtwizard -vendor xilinx.com -library ip -version 3.6 -module_name $ip_name
|
||||
|
||||
set_property -dict [list \
|
||||
CONFIG.identical_protocol_file {JESD204} \
|
||||
CONFIG.identical_val_tx_reference_clock $float_clk \
|
||||
CONFIG.identical_val_rx_reference_clock $float_clk \
|
||||
CONFIG.gt0_val_rx_reference_clock $float_clk \
|
||||
CONFIG.gt0_val_tx_reference_clock $float_clk \
|
||||
CONFIG.identical_val_tx_line_rate $lane_rate \
|
||||
CONFIG.identical_val_rx_line_rate $lane_rate \
|
||||
CONFIG.gt0_val_rx_line_rate $lane_rate \
|
||||
CONFIG.gt0_val_tx_line_rate $lane_rate \
|
||||
CONFIG.gt_val_tx_pll $pll_type \
|
||||
CONFIG.gt0_usesharedlogic {1} \
|
||||
CONFIG.advanced_clocking {true} \
|
||||
CONFIG.gt_val_drp {false} \
|
||||
CONFIG.gt0_val_drp_clock {100} \
|
||||
CONFIG.gt_val_drp_clock {60} \
|
||||
CONFIG.gt0_val_tx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt0_val_rx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt1_val_tx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt1_val_rx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt2_val_tx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt2_val_rx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt3_val_tx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt3_val_rx_refclk {REFCLK1_Q0} \
|
||||
CONFIG.gt4_val_tx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt4_val_rx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt5_val_tx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt5_val_rx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt6_val_tx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt6_val_rx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt7_val_tx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt7_val_rx_refclk {REFCLK1_Q1} \
|
||||
CONFIG.gt8_val_tx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt8_val_rx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt9_val_tx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt9_val_rx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt10_val_tx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt10_val_rx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt11_val_tx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt11_val_rx_refclk {REFCLK1_Q2} \
|
||||
CONFIG.gt12_val_tx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt12_val_rx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt13_val_tx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt13_val_rx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt14_val_tx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt14_val_rx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt15_val_tx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt15_val_rx_refclk {REFCLK1_Q3} \
|
||||
CONFIG.gt0_val_rxusrclk {RXOUTCLK} \
|
||||
CONFIG.gt0_val_decoding {8B/10B} \
|
||||
CONFIG.gt0_val_encoding {8B/10B} \
|
||||
CONFIG.gt0_val_tx_data_width {32} \
|
||||
CONFIG.gt0_val_tx_int_datawidth {40} \
|
||||
CONFIG.gt0_val_rx_data_width {32} \
|
||||
CONFIG.gt0_val_rx_int_datawidth {40} \
|
||||
CONFIG.gt0_val_port_rxchariscomma {true} \
|
||||
CONFIG.gt0_val_port_rxcharisk {true} \
|
||||
CONFIG.gt0_val_align_pcomma_value {0101111100} \
|
||||
CONFIG.gt0_val_align_mcomma_value {1010000011} \
|
||||
CONFIG.gt0_val_align_comma_enable {1111111111} \
|
||||
] [get_ips $ip_name]
|
||||
|
||||
puts "\n IP generated \n"
|
||||
|
||||
## generate output products and run synthesis
|
||||
generate_target all [get_files \
|
||||
$prj_name.srcs/sources_1/ip/$ip_name/$ip_name.xci]
|
||||
catch { config_ip_cache -export [get_ips -all $ip_name] }
|
||||
export_ip_user_files -of_objects [get_files $prj_name.srcs/sources_1/ip/$ip_name/$ip_name.xci] -no_script -sync -force -quiet
|
||||
create_ip_run [get_files -of_objects [get_fileset sources_1] $prj_name.srcs/sources_1/ip/$ip_name/$ip_name.xci] -force
|
||||
## Synthesis is optional - the generated files already contains all the
|
||||
## attributes
|
||||
## launch_runs -jobs 8 "$ip_name\_synth_1"
|
||||
} else {
|
||||
puts "NOTE: $ip_name does already exist."
|
||||
}
|
||||
|
||||
} else {
|
||||
## Ultrascale/Ultrascale+
|
||||
|
||||
## create a GT instance with the wizard, if already exist skip it
|
||||
if {[lsearch [get_ips] $ip_name] == -1} {
|
||||
|
||||
create_ip -name gtwizard_ultrascale -vendor xilinx.com -library ip -version 1.7 -module_name $ip_name
|
||||
|
||||
## TODO: double check if this configuration is OK for JESD204B
|
||||
if {[string equal $gt_type GTYE3] || [string equal $gt_type GTYE4]} {
|
||||
set gt_preset GTY-JESD204
|
||||
} else {
|
||||
set gt_preset GTH-JESD204
|
||||
}
|
||||
|
||||
set_property -dict [list \
|
||||
CONFIG.preset $gt_preset \
|
||||
CONFIG.CHANNEL_ENABLE $channel_enable \
|
||||
CONFIG.TX_MASTER_CHANNEL [lindex $channel_enable 0] \
|
||||
CONFIG.RX_MASTER_CHANNEL [lindex $channel_enable 0] \
|
||||
CONFIG.TX_REFCLK_SOURCE $ref_clk_source \
|
||||
CONFIG.RX_REFCLK_SOURCE $ref_clk_source \
|
||||
CONFIG.TX_LINE_RATE $lane_rate \
|
||||
CONFIG.TX_PLL_TYPE $pll_type \
|
||||
CONFIG.TX_REFCLK_FREQUENCY $ref_clk \
|
||||
CONFIG.TX_DATA_ENCODING {8B10B} \
|
||||
CONFIG.TX_INT_DATA_WIDTH {40} \
|
||||
CONFIG.RX_LINE_RATE $lane_rate \
|
||||
CONFIG.RX_PLL_TYPE $pll_type \
|
||||
CONFIG.RX_REFCLK_FREQUENCY $ref_clk \
|
||||
CONFIG.RX_DATA_DECODING {8B10B} \
|
||||
CONFIG.RX_INT_DATA_WIDTH {40} \
|
||||
CONFIG.RX_EQ_MODE {LPM} \
|
||||
CONFIG.RX_COMMA_P_ENABLE {true} \
|
||||
CONFIG.RX_COMMA_M_ENABLE {true} \
|
||||
CONFIG.RX_COMMA_MASK {1111111111} \
|
||||
] [get_ips $ip_name]
|
||||
|
||||
puts "\n IP generated \n"
|
||||
|
||||
## generate output products and run synthesis
|
||||
generate_target all [get_files \
|
||||
$prj_name.srcs/sources_1/ip/$ip_name/$ip_name.xci]
|
||||
catch { config_ip_cache -export [get_ips -all $ip_name] }
|
||||
export_ip_user_files -of_objects [get_files $prj_name.srcs/sources_1/ip/$ip_name/$ip_name.xci] -no_script -sync -force -quiet
|
||||
create_ip_run [get_files -of_objects [get_fileset sources_1] $prj_name.srcs/sources_1/ip/$ip_name/$ip_name.xci] -force
|
||||
## Synthesis is optional - the generated files already contains all the
|
||||
## attributes
|
||||
## launch_runs -jobs 8 "$ip_name\_synth_1"
|
||||
} else {
|
||||
puts "NOTE: $ip_name does already exist."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
##
|
||||
## This script combines the previous one with the gtwiz_parser.pl, as they are meant to work.
|
||||
## It generates a PHY configuration with GT wizard, that is parsed afterwards.
|
||||
## That results in a list of parameters that are specific to the configuration, but different from the default one.
|
||||
## This output should then overwrite the existing instance in the system_bd.tcl.
|
||||
## The output products can be found at <project_name>.gen/sources_1/ip (*_cfng.txt)
|
||||
## It must be called inside a Ultrascale or Ultrascale+ project.
|
||||
## Wiki documentation: wiki.analog.com/resources/fpga/docs/xgt_wizard
|
||||
##
|
||||
###############################################################################
|
||||
proc get_diff_params { {lane_rate_l {}} {pll_type {}} {ref_clk_l {}} {keep_ip "true"} } {
|
||||
|
||||
## Get the gt_type for the board
|
||||
set board [string range [get_property PART [current_project]] 0 6]
|
||||
switch $board {
|
||||
"xc7z045" {
|
||||
set gt_type GTXE2
|
||||
}
|
||||
"xc7k325" {
|
||||
set gt_type GTXE2
|
||||
}
|
||||
"xc7z020" {
|
||||
set gt_type GTXE2
|
||||
}
|
||||
"xc7vx48" {
|
||||
set gt_type GTXE2
|
||||
}
|
||||
"xc7vx69" {
|
||||
#set gt_type GTHE2
|
||||
puts "ERROR ad_gth_generator: Unsupported device."
|
||||
return 1
|
||||
}
|
||||
"xcku040" {
|
||||
set gt_type GTHE3
|
||||
}
|
||||
"xcvu095" {
|
||||
set gt_type GTYE3
|
||||
}
|
||||
"xczu9eg" {
|
||||
set gt_type GTHE4
|
||||
}
|
||||
"xcvu9p-" {
|
||||
set gt_type GTYE4
|
||||
}
|
||||
"xcvu37p" {
|
||||
set gt_type GTYE4
|
||||
}
|
||||
|
||||
default {
|
||||
puts "ERROR ad_gth_generator: Unsupported device."
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
set current_dir [pwd]
|
||||
set project_name [get_property NAME [current_project]]
|
||||
|
||||
## Generate configurations
|
||||
ad_gth_generator $lane_rate_l $pll_type $ref_clk_l
|
||||
|
||||
## Call parser script gtwiz_parser.pl
|
||||
cd $project_name\.gen/sources_1/ip
|
||||
# exec $::env(ADI_HDL_DIR)/projects/scripts/gtwiz_parser.pl $gt_type
|
||||
# catch exception for the next line. If it catches something, come back to $current_dir
|
||||
if { [catch { exec ../../../../../scripts/gtwiz_parser.pl $gt_type } e] } {
|
||||
cd $current_dir
|
||||
puts "Some error has occured: \n$e";
|
||||
} else {
|
||||
exec ../../../../../scripts/gtwiz_parser.pl $gt_type
|
||||
cd $current_dir
|
||||
|
||||
## if keep_ip not true, remove from the project the generated IPs and delete them
|
||||
if {$keep_ip ne "true"} {
|
||||
foreach lane_rate $lane_rate_l {
|
||||
foreach ref_clk $ref_clk_l {
|
||||
set lane_rate_txt [string replace $lane_rate [string first . $lane_rate] [string first . $lane_rate] "_"]
|
||||
set ref_clk_txt [lindex [split $ref_clk "."] 0]
|
||||
|
||||
## Get the paths to generated IP so that it can be removed
|
||||
set src_path $current_dir/$project_name\.srcs/sources_1/ip
|
||||
set gen_path $current_dir/$project_name\.gen/sources_1/ip
|
||||
set ip_name [eval exec ls $src_path | grep $gt_type\_$pll_type\_$lane_rate_txt\_$ref_clk_txt]
|
||||
set ip_path_src $src_path\/$ip_name
|
||||
set ip_path_gen $gen_path\/$ip_name
|
||||
set xci_file $ip_path_src/$ip_name\.xci
|
||||
|
||||
## Remove the generated IP after the differences were written
|
||||
export_ip_user_files -of_objects [get_files $xci_file] -no_script -reset -force -quiet
|
||||
remove_files -fileset $ip_name $xci_file
|
||||
file delete -force $ip_path_src
|
||||
file delete -force $ip_path_gen
|
||||
}
|
||||
}
|
||||
} else {
|
||||
puts "\ngenerated files can be find at $project_name\.gen/sources_1/ip"
|
||||
}
|
||||
|
||||
|
||||
puts "\nconfiguration file for the tranciever is $project_name\.gen/sources_1/ip/$gt_type\_cfng.txt"
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue