Commit 8d94ba84 authored by Stefan Tauner's avatar Stefan Tauner
Browse files

Validate top ports like everything else

 - move necessary validation functions into Settings.pm
 - check against FIJI ports too
parent ab04af7b
...@@ -157,7 +157,7 @@ logo_end ...@@ -157,7 +157,7 @@ logo_end
# - hexadecimal: values must be hexadecimal numbers. # - hexadecimal: values must be hexadecimal numbers.
# - boolean: will be convert to a truth value by Perl semantics # - boolean: will be convert to a truth value by Perl semantics
# - net: name of a net from the input netlist # - net: name of a net from the input netlist
# FIXME: complete docs # FIXME: complete docs (e.g., dut_port, external_port)
# - values (optional) used to restrict valid values. Can be... # - values (optional) used to restrict valid values. Can be...
# - an array reference listing all valid values (emulates an enum) # - an array reference listing all valid values (emulates an enum)
# - a code reference to a function that gets the new plus old values # - a code reference to a function that gets the new plus old values
...@@ -166,7 +166,7 @@ logo_end ...@@ -166,7 +166,7 @@ logo_end
# - phases_opt (optional) list of phases (subset of "setup", "instrument", "download") # - 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). # where no value must be present in input (e.g. ID is only necessary while downloading).
# - depends_on (optional) specifies the key of another constant. # - depends_on (optional) specifies the key of another constant.
# The respective constant is only relevant (and thuse required as input) # The respective constant is only relevant (and thus required as input)
# if the value of the referenced constant is true. # if the value of the referenced constant is true.
# - group (optional) specifies how to group this value in output. Value will not be displayed if undef # - group (optional) specifies how to group this value in output. Value will not be displayed if undef
# - order (optional) specifies how to sort this value in output group # - order (optional) specifies how to sort this value in output group
...@@ -420,7 +420,7 @@ BEGIN { ...@@ -420,7 +420,7 @@ BEGIN {
default => "", default => "",
phases_opt => [qw(setup download)], phases_opt => [qw(setup download)],
depends_on => 'RST_DUT_IN_EN', depends_on => 'RST_DUT_IN_EN',
type => 'toplevel_port', type => 'dut_port',
group => 'reset_to_dut', group => 'reset_to_dut',
order => 40, order => 40,
}, },
......
...@@ -459,6 +459,77 @@ sub _set_defaults { ...@@ -459,6 +459,77 @@ sub _set_defaults {
} }
} }
# @method _validate_port_entry
# Checks if a port name is valid.
#
# @param map_ref reference to FIJI Settings mappings
# @param nl_ref reference to a FIJI::netlist (for validation of nets, drivers etc. only)
# @param k key identifying the respective setting
# @param new the proposed value
# @param consts_ref reference to related settings hash
sub _validate_port_entry {
my $logger = get_logger("");
my ($map_ref, $nl_ref, $k, $new, $consts_ref) = @_;
my $ok = 0;
return "Netlist not available" if !defined($nl_ref);
return "Port name is empty" if ($new eq "");
# We have to avoid names of other FIJI entries
# (e.g. RST_EXT_IN_NAME could conflict with TRIG_EXT_IN_NAME)...
my @other_fiji_ports;
foreach my $map_key (keys %{$map_ref}) {
my $type = $map_ref->{$map_key}->{'type'};
# Gather entries of type dut_port and external_port only
next if !($type eq 'dut_port' || $type eq 'external_port');
# Ignore disabled entries
next if _disabled_via_dependency($map_ref, $consts_ref, $map_key);
# Push all remaining entries excluding the one under validation
push(@other_fiji_ports, $consts_ref->{$map_key}) if $map_key ne $k;
}
return "Port name $new is already used for another FIJI port" if _is_in_list(\@other_fiji_ports, $new);
# Additionally, we need to check against the top level ports of the DUT that will get passed on to FIJI's top.
my $dut_ports = $nl_ref->get_toplevel_port_names;
# For external ports originating in FIJI itself they need to be neither used by the DUT nor other FIJI elements, thus
# ok = not in ext_ports and not in dut_ports
if ($map_ref->{$k}->{'type'} eq 'external_port') {
return "Port name $new already exists as DUT port" if _is_in_list($dut_ports, $new);
# In the case of elements connecting to existing DUT ports (type dut_port),
# the latter need to exist in the DUT but are not allowed to be used for other purposes of FIJI. Thus:
# ok = not in ext_ports and in dut_ports
} elsif ($map_ref->{$k}->{'type'} eq 'dut_port') {
return "Port name $new does not refer to a DUT port" if not _is_in_list($dut_ports, $new);
} else {
my $msg = sprintf("Internal error: unknown type %s (used in %s)", $map_ref->{$k}->{'type'}, $k);
$logger->fatal($msg);
return $msg;
}
return undef;
}
sub _is_in_list {
my ($valid_list_ref, $new) = @_;
my $logger = get_logger("");
if (!ref($valid_list_ref)) {
return 1;
}
my @complete_matches = ();
my @prefix_matches = ();
# this is not implemented using grep because of
# https://rt.cpan.org/Public/Bug/Display.html?id=112427
for my $entry (@{$valid_list_ref}) {
push (@complete_matches, $entry) if ($entry =~ m/^\Q$new\E$/);
push (@prefix_matches,$entry) if ($entry =~ m/^\Q$new\E$/);
}
$logger->trace("'$new' matches " . scalar(@complete_matches) . " nets completely and is a prefix of " . scalar(@prefix_matches));
return @complete_matches == 1;
}
## @function validate_value (%$map_ref, $nl_ref, $k, $$v_ref, $dep_ref, $consts_ref, $log_func) ## @function validate_value (%$map_ref, $nl_ref, $k, $$v_ref, $dep_ref, $consts_ref, $log_func)
# Do validation (and conversation from external->internal representation) # Do validation (and conversation from external->internal representation)
# #
...@@ -500,6 +571,11 @@ sub validate_value { ...@@ -500,6 +571,11 @@ sub validate_value {
if (defined($msg)) { if (defined($msg)) {
return $msg; return $msg;
} }
} elsif (($map_ref->{$k}->{'type'} eq 'external_port') || ($map_ref->{$k}->{'type'} eq 'dut_port')) {
my $msg = _validate_port_entry($map_ref, $nl_ref, $k, $orig, $consts_ref);
if (defined($msg)) {
return $msg;
}
} elsif ($map_ref->{$k}->{'type'} eq 'driver') { } elsif ($map_ref->{$k}->{'type'} eq 'driver') {
return "Netlist not available" if !defined($nl_ref); return "Netlist not available" if !defined($nl_ref);
......
...@@ -202,7 +202,7 @@ sub update { ...@@ -202,7 +202,7 @@ sub update {
my $const_cnt = @design_widgets; my $const_cnt = @design_widgets;
my $net_choices = defined($self->{'nets'}) ? $self->{'nets'} : []; my $net_choices = defined($self->{'nets'}) ? $self->{'nets'} : [];
my $toplevel_port_choices = defined($self->{'netlist'}) ? $self->{'netlist'}->get_toplevel_port_names("i") : []; my $dut_port_choices = defined($self->{'netlist'}) ? $self->{'netlist'}->get_toplevel_port_names("i") : [];
for (my $i = 0 ; $i < $const_cnt ; $i += 3) { for (my $i = 0 ; $i < $const_cnt ; $i += 3) {
...@@ -235,8 +235,8 @@ sub update { ...@@ -235,8 +235,8 @@ sub update {
my $autocomplete_choices; my $autocomplete_choices;
if (defined $type) { if (defined $type) {
if ($type eq 'toplevel_port') { if ($type eq 'dut_port') {
$autocomplete_choices = $toplevel_port_choices; $autocomplete_choices = $dut_port_choices;
} elsif ($type eq 'lfsrpoly') { } elsif ($type eq 'lfsrpoly') {
$orig_ref = \$val; $orig_ref = \$val;
} }
...@@ -562,7 +562,7 @@ sub _populate_widget { ...@@ -562,7 +562,7 @@ sub _populate_widget {
$entry = $config_frame->Entry(); $entry = $config_frame->Entry();
$entry->configure( $entry->configure(
'-validate' => 'key', '-validate' => 'key',
'-validatecommand' => [\&_validate_toplevel_port_entry, $self, $entry, $k, 1], '-validatecommand' => [\&_validate_design_entry, $self, 1, $entry, $k],
); );
$entry->grid( $entry->grid(
-row => $row, -row => $row,
...@@ -570,13 +570,13 @@ sub _populate_widget { ...@@ -570,13 +570,13 @@ sub _populate_widget {
'-sticky' => 'ew' '-sticky' => 'ew'
); );
} elsif (defined($type) && $type eq 'toplevel_port') { } elsif (defined($type) && $type eq 'dut_port') {
# entry for a DUT port name # entry for a DUT port name
$entry = $config_frame->CompleteEntry(); $entry = $config_frame->CompleteEntry();
$entry->configure( $entry->configure(
'-validate' => 'key', '-validate' => 'key',
'-validatecommand' => [\&_validate_toplevel_port_entry, $self, $entry, $k, 0], '-validatecommand' => [\&_validate_design_entry, $self, 1, $entry, $k],
); );
$entry->grid( $entry->grid(
-row => $row, -row => $row,
...@@ -1347,71 +1347,6 @@ sub validate_duplicate_nets { ...@@ -1347,71 +1347,6 @@ sub validate_duplicate_nets {
return $rv; return $rv;
} }
# @method _validate_toplevel_port_entry
# checks if a name exists or does not exist in the toplevel's ports
# @param $widget The widget activating the callback
# @param $name The settings key
# @param $excl 1 if the port must not exist, 0 if it must exist
# @param $new The new port name
#
sub _validate_toplevel_port_entry {
my $logger = get_logger("");
my ($self, $widget, $name, $excl, $new) = @_;
my $ok = 0;
if (defined(DESIGNMAP->{$name}->{'depends_on'})) {
my $dep_ref = \$self->{'settings'}->{'design'}->{DESIGNMAP->{$name}->{'depends_on'}};
$self->_indicate_warning($widget, 0, DESIGNMAP, $name);
# don't validate if this entry is disabled
$self->{'settings_validation_results'}->{$name} = 1;
$logger->debug("Don't validate $name as it is disabled.") if ($$dep_ref == 0);
return 1 if ($$dep_ref == 0);
}
my $msg;
# must not be in toplevel port names
if (defined $self->{'netlist'}) {
# validate_against_list returns 1 if the value is found
# XORing excl with this result =>
# 1 if exists and excl == 0 or not exists and excl == 1
# 0 if exists and excl == 1 or not exists and excl == 0
# FIXME: also check for names of other FIJI entries
# (e.g. RST_EXT_IN_NAME could conflict with TRIG_EXT_IN_NAME)
$ok = $excl ^ ($self->_validate_against_list($widget, $self->{'netlist'}->get_toplevel_port_names, $new));
$self->{'settings'}->{'design'}->{$name} = $new;
$msg = "Port name $new already exists as DUT port" if (!$ok && $excl);
$msg = "Port name $new does not refer to a DUT port" if (!$ok && !$excl);
$ok = $ok & ($new ne "");
$msg = "Port name is empty" if ($new eq "");
} else {
$msg = "Cannot validate port name (yet). No netlist loaded.";
}
$logger->warn($msg) if defined($msg);
$self->_indicate_warning($widget, (!$ok), DESIGNMAP, $name, $msg);
$self->{'settings_validation_results'}->{$name} = $ok;
return 1; # always allow the new value and show the user what happened.
}
sub _validate_against_list {
my ($self, $widget, $valid_list_ref, $new) = @_;
my $logger = get_logger("");
if (!ref($valid_list_ref)) {
return 1;
}
my @complete_matches = ();
my @prefix_matches = ();
# this is not implemented using grep because of
# https://rt.cpan.org/Public/Bug/Display.html?id=112427
for my $entry (@{$valid_list_ref}) {
push (@complete_matches, $entry) if ($entry =~ m/^\Q$new\E$/);
push (@prefix_matches,$entry) if ($entry =~ m/^\Q$new\E$/);
}
$logger->trace("'$new' matches " . scalar(@complete_matches) . " nets completely and is a prefix of " . scalar(@prefix_matches));
return @complete_matches == 1; # || $prefix_matches > 0;
}
## @method _select_net_dialog(idx) ## @method _select_net_dialog(idx)
# prompt the user to select a net name # prompt the user to select a net name
sub _select_net_dialog { sub _select_net_dialog {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment