Commit 0c9547b4 authored by Stefan Tauner's avatar Stefan Tauner
Browse files

Big refinement of FIJI settings validation

 - validate nets and respective drivers like everything else
 - load the netlist earlier (in the user scripts) to make it available while
   loading settings
 - add a FIJI::Netlist parameter to respective FIJI::Settings's functions
 - add a new type 'driver' for FIU elements to distinguish its string
   representation from nets'
 - add new net validation function to FIJI::Netlist
 - use this to make net and FIU validation more generic to simplify FIJISettingsViewer
 - refine and correct handling of the tool phases
 - distinguish fatal errors, missing fields and less important anomalies when
   validating settings depending on the phase etc
 - notify user about validation problems in more detailed messages and tooltips
 - refine FIJI::VHDL to not load settings all the time and receive parameters
   directly instead of via hashes
 - use a global constant ONLY_LOAD in fiji_setup instead of a local variable
 - add a 'show_warning' function to ease opening warning dialogs
 - various other usability/GUI-related improvements
 - allow the deletion of nets
parent 6caa4313
......@@ -160,7 +160,8 @@ logo_end
# FIXME: complete docs
# - values (optional) used to restrict valid values. Can be...
# - an array reference listing all valid values (emulates an enum)
# - a code reference to a function that gets the new and old values and
# - a code reference to a function that gets the new plus old values
# (as well as the value of the dependency if there is one) and
# returns true if the new value is allowed, or false otherwise.
# - phases_opt (optional) list of phases (subset of "setup", "instrument", "download")
# where no value must be present in input (e.g. ID is only necessary while downloading).
......@@ -301,6 +302,7 @@ BEGIN {
ini_name => "LFSR_POLY",
default => 0x2D,
type => 'lfsrpoly',
unit => 'hex',
depends_on => 'LFSR_WIDTH',
values => sub {
my ($val, $old, $top) = @_;
......@@ -316,6 +318,7 @@ BEGIN {
ini_name => "LFSR_SEED",
default => 0xCAFE,
type => 'hexadecimal',
unit => 'hex',
depends_on => 'LFSR_WIDTH',
values => sub {
my ($val, $old, $top) = @_;
......@@ -331,8 +334,9 @@ BEGIN {
description => "Use external reset",
help => "If enabled, the FIJI logic can be reset using an FPGA pin.",
ini_name => "RST_EXT_EN",
default => 0,
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'reset_external',
order => 10,
},
......@@ -366,8 +370,9 @@ BEGIN {
description => "Enable DUT-to-FIJI reset",
help => "If enabled, a net in the DUT is used as a reset source for the FIJI logic.",
ini_name => "RST_DUT_OUT_EN",
default => 0,
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'reset_from_dut',
forbidden_by => 'RST_DUT_IN_EN',
order => 10,
......@@ -379,7 +384,7 @@ BEGIN {
depends_on => 'RST_DUT_OUT_EN',
type => 'net',
default => "",
phases_opt => ['setup'],
phases_opt => [qw(setup download)],
group => 'reset_from_dut',
order => 30,
},
......@@ -401,8 +406,9 @@ BEGIN {
description => "Enable FIJI-to-DUT reset",
help => "If enabled, the DUT will be reset from the FIJI logic.",
ini_name => "RST_DUT_IN_EN",
default => 0,
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'reset_to_dut',
forbidden_by => 'RST_DUT_OUT_EN',
order => 10,
......@@ -412,6 +418,7 @@ BEGIN {
help => "The specified DUT reset input will be connected\n to the FIJI logic's reset output.",
ini_name => "RST_DUT_IN_NAME",
default => "",
phases_opt => [qw(setup download)],
depends_on => 'RST_DUT_IN_EN',
type => 'toplevel_port',
group => 'reset_to_dut',
......@@ -451,16 +458,17 @@ BEGIN {
description => "Enable DUT-to-FIJI trigger",
help => "If enabled, a signal in the DUT can be selected to trigger fault injection operations.\n" . "Once a pattern is downloaded with the INTERNAL trigger enabled, the FIJI logic waits for\n" . "an inactive-to-active transition on this signal before starting to count down duration t1.",
ini_name => "TRIG_DUT_EN",
default => 0,
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'trigger',
order => 10,
},
TRIG_DUT_ACT => {
description => "Active level of DUT-to-FIJI trigger",
ini_name => "TRIG_DUT_ACT",
help => "Select the signal level to trigger fault injection.",
ini_name => "TRIG_DUT_ACT",
type => 'bit',
values => [qw(0 1)],
phases_opt => ['setup'],
......@@ -475,7 +483,7 @@ BEGIN {
help => "Select the net in the DUT which shall be used to trigger fault injection operations.",
ini_name => "TRIG_DUT_NAME",
default => "",
phases_opt => ['setup'],
phases_opt => [qw(setup download)],
depends_on => 'TRIG_DUT_EN',
type => 'net',
group => 'trigger',
......@@ -487,8 +495,9 @@ BEGIN {
description => "Enable external trigger",
help => "If enabled, an I/O port can be selected to trigger fault injection operations.\n" . "Once a pattern is downloaded with the EXTERNAL trigger enabled, the FIJI logic waits for \n" . "an inactive-to-active transition on this port before starting to count down duration t1. \n" . "The port is synchronized to the FIJI logic's clock, thus introducing a few clock cycles delay.",
ini_name => "TRIG_EXT_EN",
default => 0,
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'trigger',
order => 40,
},
......@@ -521,6 +530,7 @@ BEGIN {
ini_name => "FD_1_EN",
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'fault_detect',
order => 10,
},
......@@ -530,7 +540,7 @@ BEGIN {
ini_name => "FD_1_NAME",
type => 'net',
default => "",
phases_opt => ['setup'],
phases_opt => [qw(setup download)],
depends_on => 'FD_1_EN',
group => 'fault_detect',
order => 20,
......@@ -553,6 +563,7 @@ BEGIN {
ini_name => "FD_2_EN",
type => 'boolean',
default => 0,
phases_opt => ['setup'],
group => 'fault_detect',
order => 40,
},
......@@ -562,7 +573,7 @@ BEGIN {
ini_name => "FD_2_NAME",
type => 'net',
default => "",
phases_opt => ['setup'],
phases_opt => [qw(setup download)],
depends_on => 'FD_2_EN',
group => 'fault_detect',
order => 50,
......@@ -688,7 +699,7 @@ BEGIN {
general_control => {
title => "General settings",
subtitle => "",
description => "Settings concerning miscellanous features of FIJI",
description => "Settings concerning miscellaneous features of FIJI",
order => 10,
},
clock => {
......@@ -720,6 +731,7 @@ use constant DISPLAYGROUPS_FIU_KEY => 'fius';
# - hexadecimal: values must be hexadecimal numbers.
# - boolean: will be convert to a truth value by Perl semantics
# - net: hierarchical path of a net from the input netlist
# - driver: driver-specific hierarchical path of a net from the input netlist
# - values (optional) used to restrict valid values. Can be...
# - an array reference listing all valid values (emulates an enum)
# - a code reference to a function that gets the new and old values and
......@@ -743,7 +755,7 @@ BEGIN {
default => "",
type => 'net',
help => "String representation of the instrumented net.",
phases_opt => [qw(setup)],
phases_opt => [qw(setup download)], # Either FIU or net name is strongly recommended during download
},
FIU_DRIVER_TYPE => {
ini_name => "DRIVER_TYPE",
......@@ -754,9 +766,9 @@ BEGIN {
FIU_DRIVER_PATH => {
ini_name => "DRIVER_PATH",
default => "",
type => 'net',
type => 'driver',
help => "String representation of a driver.",
phases_opt => [qw(setup)],
phases_opt => [qw(setup download)], # Either FIU or net name is strongly recommended during download
},
FIU_MODEL => {
ini_name => "FAULT_MODEL",
......@@ -799,7 +811,7 @@ use constant FIUMAP => \%fiumap;
# The respective constant is only relevant (and thuse required as input)
# if the value of the referenced constant is true.
# - order (optional) specifies how to sort this value in output group
# - default (optional) default value if not given in file and not determinable otherwise,
# - default (optional) default value if not given in file and not determinable otherwise.
# Can either be a scalar or a function pointer expecting a FIJI settings reference.
# - help (optional) short help text, e.g. to be displayed via Tk:Balloon
# The respective constant may not be enabled if the value
......
......@@ -32,7 +32,7 @@ use Clone 'clone';
use threads;
use threads::shared;
# FIXME: fix documentation
# FIXME: fix documentation, possibly refine settings_from_file and existing_settings
## @function public new ($testsname,%$existing_tests,$cfgname,%$existing_cfg)
#
# @param testsname (optional) Name of a FIJI::Tests configuration file
......@@ -82,11 +82,12 @@ sub settings_from_file {
my $logger = get_logger("");
my $rv;
my ($self, $cfgname) = @_;
my ($fiji_settings, $warn) = FIJI::Settings->new("download", $cfgname);
my ($fiji_settings, $errors, $warnings) = FIJI::Settings->new('download', $cfgname); # fixme
if (!defined($fiji_settings)) {
$rv = $warn;
$rv = $errors;
} else {
$logger->warn($warn) if defined $warn;
$logger->warn($errors) if defined $errors;
$logger->warn($warnings) if defined $warnings;
$rv = $self->{'fiji_settings'} = $fiji_settings;
}
return $rv;
......
......@@ -81,6 +81,9 @@ sub read_file {
$logger->info("Reading in netlist from file \"$filename\".");
eval {
# Stop croak and friends from printing stuff to stderr
# FIXME: how to capture the messages?
$SIG{__WARN__} = sub {};
$self->{'nl'}->read_file(filename => $filename); # read Verilog file
$self->{'nl'}->link(); # Read in any sub-modules
};
......@@ -125,8 +128,8 @@ sub get_toplevel_module {
my @m = $self->{'nl'}->top_modules_sorted;
my $n = @m;
return $m[0] if ($n == 1);
return "More than one toplevel module present in netlist." if ($n > 1);
return "No toplevel module found.";
return "More than one toplevel module present in netlist" if ($n > 1);
return "No toplevel module found";
}
## @method public get_nets ()
......@@ -791,39 +794,61 @@ sub instrument_net {
return undef;
}
## @method public validate_net($net_path)
# @brief Check if the given net path is valid (i.e., referring to an existing net)
#
# @param net_path The hierarchical path of the net, separated by HIERSEP
#
# @returns STRING if an error occurred
# @returns undef if successful
sub validate_net {
my ($self, $net_path,) = @_;
if ($net_path eq "") {
return "Net path is empty";
}
my $net_descriptor = $self->get_netdescriptor_from_path($net_path);
if (ref($net_descriptor) ne "HASH") {
return $net_descriptor;
}
return undef;
}
## @method public validate_driver($net_path, $driver_path, $driver_type)
# @brief Check if the given driver is valid for the given net
#
# Check if the driver specified by $driver_type and $driver_path
# is actually connected to the net specified by $net_path
#
# @param net_path The hierarchical path of the net, separeted by HIERSEP
# @param net_path The hierarchical path of the net, separated by HIERSEP
# @param driver_path The hierarchical path of the driver object, separated by HIERSEP
# @param driver_type The type of the driver object, one of {PIN, PORT, ASSIGN}
#
# @returns STRING if an error occurred
# @returns undef if successfull
sub _validate_driver {
# @returns undef if successful
sub validate_driver {
my $logger = get_logger("");
my ($self, $net_path, $driver_path, $driver_type) = @_;
return "Net path is empty" if (!defined($net_path) || ($net_path eq ""));
return "Driver path is empty" if (!defined($driver_path) || ($driver_path eq ""));
return "Driver type is empty" if (!defined($driver_type) || ($driver_type eq ""));
my $connection_object = $self->get_connection_object($driver_path, $driver_type);
my $connections = {};
$self->_get_net_connections_from_path($net_path, $connections);
return "Specified driver not found in netlist" if (!defined $connection_object);
goto FAIL if (!defined $connection_object);
my $connections = {};
my $rv = $self->_get_net_connections_from_path($net_path, $connections);
return $rv if defined($rv);
my @in_drivers = grep { $_ == $connection_object } @{$connections->{'drivers'}};
my @in_connections = grep { $_ == $connection_object } @{$connections->{'connected'}};
goto FAIL if (@in_drivers == 0 && @in_connections == 0);
return "Driver \"$driver_path\" exists in netlist but is not connected to net \"$net_path\" at all" if (@in_drivers == 0 && @in_connections == 0);
return undef;
FAIL:
my $msg = "No possible driver found";
$logger->error($msg);
return $msg;
}
## @function private _select_driver($connected,$net)
......@@ -936,11 +961,9 @@ sub get_connection_object {
my $logger = get_logger("");
my ($self, $connection_path, $connection_type) = @_;
my $rv;
my $SEP = HIERSEP;
my @path_elements = _split_path($connection_path);
my $rv;
if ($connection_type eq "PIN") {
if (@path_elements == 3) {
......@@ -985,6 +1008,9 @@ sub get_connection_object {
$rv = $assign;
}
}
} else {
$logger->error("Unknown connection type \"$connection_type\"!");
return undef;
}
$logger->warn("Could not find $connection_type \"$connection_path\"!") if !defined($rv);
return $rv;
......@@ -1002,6 +1028,8 @@ sub get_connection_object {
# connection_hashref->{'driven'} contains a list of driven cells
# connection_hashref->{'connected'} contains a list cells connected to the
# net but driver/driven cannot be decided
# @returns STRING if an error occurred
# @returns undef if successful
sub _get_net_connections_from_path {
my $logger = get_logger("");
my ($self, $net_path, $connection_hashref, $sorted) = @_;
......@@ -1107,6 +1135,9 @@ sub _handle_connection_statement {
# @param bit one bit of the net to check for connections (optional, only useful for vectored nets)
# @param driver_path the path to the driver of this net (optional but depends on driver_type)
# @param driver_type the type of the driver (can be PIN, PORT, ASSIGN) (optional but depends on driver_path)
#
# @returns STRING if an error occurred
# @returns undef if successful
sub _get_net_connections {
my $logger = get_logger("");
my ($self, $net, $connection_hashref, $bit, $driver_path, $driver_type) = @_;
......@@ -1351,7 +1382,7 @@ sub _extract_netpath_elements {
my ($self, $netpath, $netpath_elements) = @_;
if (!defined($netpath) || "$netpath" eq "") {
return "Can not parse an empty net.";
return "Can not parse an empty net";
}
my $hiersep = HIERSEP;
......@@ -1373,10 +1404,11 @@ sub _extract_netpath_elements {
for ($i = 1; $i < @net_split-1; $i++) {
my $cell = $mod->find_cell($net_split[$i]);
if (!(defined $cell && $cell->isa("Verilog::Netlist::Cell"))) {
return "Could not find cell ".$net_split[$i]." in $netpath in netlist $self->{'filename'}'";
return "Could not find cell ".$net_split[$i]." in $netpath in netlist $self->{'filename'}";
}
$mod = $cell->submod();
}
my $mod_name = $mod->name;
my $netstring_elements = $self->_extract_netstring_elements($net_split[$i]);
......@@ -1385,10 +1417,9 @@ sub _extract_netpath_elements {
my $net = $mod->find_net($netstring_elements->{'net_name'});
if (!(defined $net && $net->isa("Verilog::Netlist::Net"))) {
return "Could not find net ".$netstring_elements->{'net_name'}." in $netpath in netlist $self->{'filename'}'";
return "Could not find net ".$netstring_elements->{'net_name'}." in $mod_name in netlist $self->{'filename'}";
}
my $mod_name = $mod->name;
my $net_string = $net_split[$i];
if (defined($netpath_elements)) {
......@@ -1415,7 +1446,7 @@ sub _extract_netstring_elements {
my ($self, $net_string, $net_descriptor) = @_;
if (!defined($net_string) || "$net_string" eq "") {
return "Can not parse an empty net.";
return "Can not parse an empty net";
}
$net_string =~ /(~)?(.*?)(\[([^:]+)(:(.*))?\])?$/;
......@@ -1451,7 +1482,7 @@ sub get_netdescriptor_from_path {
my $netpath_elements = $self->_extract_netpath_elements($netpath);
if (!defined($netpath_elements)) {
return "$netpath is not a valid net path.";
return "$netpath is not a valid net path";
}
if (ref($netpath_elements) ne "HASH") {
......@@ -1477,7 +1508,7 @@ sub get_netdescriptor_from_path {
if (defined($net->lsb) || defined($net->msb)) {
# must contain a net range, i.e. have msb and lsb set...
if (!defined($lsb) || !defined($msb)) {
return sprintf("Net '%s%s%s' in netlist %s has a defined pin range but requested net does not.", $mod->name, HIERSEP, $net_name, $self->{'filename'});
return sprintf("Net '%s%s%s' in netlist %s has a defined pin range but requested net does not", $mod->name, HIERSEP, $net_name, $self->{'filename'});
}
if (-1 == _offset_of_bit_in_netrange($msb, $net)) {
return sprintf("Bit [%s] is not in net '%s%s%s' in netlist %s", $msb, $mod->name, HIERSEP, $net_name, $self->{'filename'});
......
......@@ -37,18 +37,20 @@ use FIJI qw(:all);
## @var @base_resources stores the resource count for default config
my @base_resources;
## @function public new ($phase, $fiji_ini_file, $existing_settings)
## @function public new ($phase, $fiji_ini_file, $existing_settings, $nl_ref)
# Create a new settings instance.
#
# \param phase Tool flow phase the settings need to be compatible with.
# \param fiji_ini_file (optional) Path to the configuration file to read.
# \param existing_settings (optional) A reference to reuse and return
# with values read from file. Any contained data will be cleared.
# \returns The new settings instance (or undef in the case of an error)
# and a diagnostic string describing the reason why it could not be created (undef if successful)
sub new ($;$$) {
# @param phase Tool flow phase the settings need to be compatible with.
# @param fiji_ini_file (optional) Path to the configuration file to read.
# @param existing_settings (optional) A reference to reuse and return with values read from file.
# Any contained data will be cleared.
# @param nl_ref A reference to a FIJI::netlist (for validation of nets and drivers only)
# @returns A list comprising a) The new settings instance (or undef in the case of an error),
# b) a diagnostic string describing the reason why it could not be created (undef if successful),
# c) a diagnostic string describing any anomalies of \c $fiji_ini_file that did not hinder creation.
sub new {
my $logger = get_logger("");
my ($class, $phase, $fiji_ini_file, $existing_settings) = @_;
my ($class, $phase, $fiji_ini_file, $existing_settings, $nl_ref) = @_;
my $fiji_settings_ref;
......@@ -70,12 +72,12 @@ sub new ($;$$) {
return (undef, $msg);
}
my $warn;
my ($errors, $warnings);
# If there is a file given, try to read it. Else just create a default instance.
if (defined($fiji_ini_file)) {
($fiji_settings_ref, $warn) = read_settingsfile($phase, $fiji_ini_file, $fiji_settings_ref);
($fiji_settings_ref, $errors, $warnings) = read_settingsfile($phase, $fiji_ini_file, $fiji_settings_ref, $nl_ref);
if (!defined($fiji_settings_ref)) {
return (undef, $warn);
return (undef, $errors, $warnings);
}
$fiji_settings_ref->{'filename'} = $fiji_ini_file;
} else {
......@@ -87,7 +89,7 @@ sub new ($;$$) {
@base_resources = _est_resources(DESIGNMAP->{'FREQUENCY'}->{'default'}, DESIGNMAP->{'BAUDRATE'}->{'default'}, DESIGNMAP->{'TIMER_WIDTH'}->{'default'}, DESIGNMAP->{'RST_DUT_IN_DUR'}->{'default'}, DESIGNMAP->{'LFSR_WIDTH'}->{'default'}, 1, "logarithmic");
return ($fiji_settings_ref, $warn);
return ($fiji_settings_ref, $errors, $warnings);
}
sub _export_value {
......@@ -192,7 +194,7 @@ sub save ($) {
return undef;
}
## @function public read_settingsfile ($phase, $fiji_ini_file)
## @function public read_settingsfile ($phase, $fiji_ini_file, $existing_settings, $nl_ref)
# @brief Load the FIJI Settings file containing design and FIU constants.
#
# @param phase Tool flow phase the settings stored in the given file
......@@ -203,12 +205,16 @@ sub save ($) {
# - at least one FIU block named "FIU<number>" where "<number>"
# is a strictly increasing integer starting with 0 containing
# the constants for the respective FIU, see \ref _sanitize_fiu
# @param existing_settings (optional) A reference to reuse and return with values read from file.
# Any contained data will be cleared.
# @param nl_ref A reference to a FIJI::netlist (for validation of nets and drivers only)
#
# @returns a reference to the hash containing the read constants (or undef in the case of an error)
# and a diagnostic string describing the reason why it could not be created (undef if successful)
# @returns A list comprising a) a reference to the hash containing the read constants (or undef in the case of an error),
# b) a diagnostic string describing the reason why it could not be created (undef if successful),
# c) a diagnostic string describing any anomalies of \c $fiji_ini_file that did not hinder creation.
sub read_settingsfile ($$$) {
my $logger = get_logger("");
my ($phase, $fiji_ini_file, $existing_settings) = @_;
my ($phase, $fiji_ini_file, $existing_settings, $nl_ref) = @_;
my $fiji_ini;
eval { $fiji_ini = new FIJI::ConfigSorted($fiji_ini_file) }; # pesky library tries to die on syntax errors
if (!defined($fiji_ini)) {
......@@ -263,32 +269,33 @@ sub read_settingsfile ($$$) {
$fiji_settings_ref->{'fius'} = [];
# sanitize and validate read design constants
$design_ref = _sanitize_design($design_ref, $phase);
my ($errors, $warnings);
($design_ref, $errors, $warnings) = _sanitize_design($design_ref, $phase, $nl_ref);
if (!ref($design_ref)) {
$logger->error($design_ref);
return (undef, $design_ref);
$logger->error($errors);
return (undef, $errors, $warnings);
}
my $fiu_num = 0;
my $dup = {};
my $warn;
# loop over all read fius
my $error;
# Loop over all read FIUs
while (1) {
my $fiu_name = "FIU" . $fiu_num;
my $fiu_ref = $fiji_ini->get_block($fiu_name);
my $fiu_id = "FIU" . $fiu_num;
my $fiu_ref = $fiji_ini->get_block($fiu_id);
if (!(%$fiu_ref)) {
last;
}
$fiu_ref = _rename_import(FIUMAP, $fiu_ref);
if (!defined($design_ref)) {
my $msg = "FIU constants of $fiu_name do not match the FIJI Settings naming scheme.";
if (!defined($fiu_ref)) {
my $msg = "FIU constants of $fiu_id do not match the FIJI Settings naming scheme.";
$logger->error($msg);
return (undef, $msg);
}
my $tmp_fiu = {};
_set_defaults(FIUMAP, $tmp_fiu, $phase);
_set_defaults(FIUMAP, $tmp_fiu, $phase, $design_ref, $fiu_num);
# overwrite default entries
foreach my $k (keys(%{$fiu_ref})) {
......@@ -296,57 +303,124 @@ sub read_settingsfile ($$$) {
}
$fiu_ref = $tmp_fiu;
$fiu_ref = _sanitize_fiu($fiu_ref, $phase);
my ($fiu_errors, $fiu_warnings);
($fiu_ref, $fiu_errors, $fiu_warnings) = _sanitize_fiu($fiu_ref, $phase, $nl_ref);
if (!ref($fiu_ref)) {
my $msg = "(Some) constants for $fiu_name in FIJI Settings are invalid.";
my $msg = "";
$msg .= "$errors\n" if defined($errors);
$msg .= "Fatal problems sanitizing $fiu_id:\n$fiu_errors";
$logger->error($msg);
return (undef, $msg);
return (undef, $msg, $warnings);
}
my $name_str = $fiu_id;
$name_str .= " (".$fiu_ref->{'FIU_NAME'} . ")" if (defined($fiu_ref->{'FIU_NAME'}) && $fiu_ref->{'FIU_NAME'} ne "");
if (defined($fiu_errors)) {
$errors = "" if !defined($errors);
$errors .= "$name_str:\n$fiu_errors";
}
# Test for multiple instrumentations of a single net
my $netname = $fiu_ref->{'FIU_NET_NAME'};
if (defined($netname) && length($netname) > 0) {
if (defined $dup->{$netname}) {
my $msg = "More than one FIU attached to $netname";
$logger->warn($msg);
$warn .= $msg;
} else {
$dup->{$fiu_ref->{'FIU_NET_NAME'}} = 1;
}
if (defined($fiu_warnings)) {
$warnings = "" if !defined($warnings);
$warnings .= "$name_str:\n$fiu_warnings";
}
$fiji_settings_ref->{'fius'}->[$fiu_num] = $fiu_ref;
$fiu_num++;
$logger->trace("Read in $fiu_name from FIJI Settings file successfully.");
$logger->trace("Read in $fiu_id from FIJI Settings file successfully.");
}
if ($fiu_num == 0) {
my $msg = "No FIU blocks in config file \"$fiji_ini_file\". Synthesis would fail.";
my $msg = "No FIU blocks in config file. Synthesis would fail.";
$logger->warn($msg);
$warn .= $msg;
if ($phase eq 'instrument') {
$errors = "" if !defined($errors);
$errors .= "$msg\n";
} else {
$warnings = "" if !defined($warnings);
$warnings .= "$msg\n";
}
}
# FIU_NUM is optional in the Settings file... if it was set check that
# it corresponds to the number of FIU<number> blocks.
if (defined($design_ref->{'FIU_NUM'}) && $design_ref->{'FIU_NUM'} != $fiu_num) {
my $msg = FIU_NUM->{'ini_name'} . " does not match the numbers of FIU blocks found.";
$logger->error($msg);
return (undef, $msg);
my $msg = FIU_NUM->{'ini_name'} . " does not match the numbers of FIU blocks found (and loaded).";
$logger->warn($msg);
$warnings = defined($warnings) ? "$warnings\n" : "";
$warnings .= "$msg\n";
} else {
$design_ref->{'FIU_NUM'} = $fiu_num; # assume the best if FIU_NUM constant is not given
}
splice(@{$fiji_settings_ref->{'fius'}}, $fiu_num);
$logger->info("Successfully read in design constants and $fiu_num FIU definitions from FIJI Settings file \"$fiji_ini_file\".");
return ($fiji_settings_ref, $warn);
my $dups = $fiji_settings_ref->determine_duplicate_fiu_nets();
my @dup_nets = keys(%{$dups});
if (scalar(@dup_nets) > 0) {
my $msg = "More than one FIU is attached to the following net(s):\n";
for my $dup (@dup_nets) {
$msg .= "$dup is attached to FIUs " . join(", ", @{$dups->{$dup}}) . "\n";
}
chomp($msg);
if ($phase eq 'instrument') {
$logger->error($msg);
if (defined($errors)) {
$errors .= "\n$msg\n";
} else {