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
# - hexadecimal: values must be hexadecimal numbers.
# - boolean: will be convert to a truth value by Perl semantics
# - 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...
# - an array reference listing all valid values (emulates an enum)
# - a code reference to a function that gets the new plus old values
......@@ -166,7 +166,7 @@ logo_end
# - 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).
# - 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.
# - 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
......@@ -420,7 +420,7 @@ BEGIN {
default => "",
phases_opt => [qw(setup download)],
depends_on => 'RST_DUT_IN_EN',
type => 'toplevel_port',
type => 'dut_port',
group => 'reset_to_dut',
order => 40,
},
......
......@@ -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)
# Do validation (and conversation from external->internal representation)
#
......@@ -500,6 +571,11 @@ sub validate_value {
if (defined($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') {
return "Netlist not available" if !defined($nl_ref);
......
......@@ -202,7 +202,7 @@ sub update {
my $const_cnt = @design_widgets;
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) {
......@@ -235,8 +235,8 @@ sub update {
my $autocomplete_choices;
if (defined $type) {
if ($type eq 'toplevel_port') {
$autocomplete_choices = $toplevel_port_choices;
if ($type eq 'dut_port') {
$autocomplete_choices = $dut_port_choices;
} elsif ($type eq 'lfsrpoly') {
$orig_ref = \$val;
}
......@@ -562,7 +562,7 @@ sub _populate_widget {
$entry = $config_frame->Entry();
$entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_toplevel_port_entry, $self, $entry, $k, 1],
'-validatecommand' => [\&_validate_design_entry, $self, 1, $entry, $k],
);
$entry->grid(
-row => $row,
......@@ -570,13 +570,13 @@ sub _populate_widget {
'-sticky' => 'ew'
);
} elsif (defined($type) && $type eq 'toplevel_port') {
} elsif (defined($type) && $type eq 'dut_port') {
# entry for a DUT port name
$entry = $config_frame->CompleteEntry();
$entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_toplevel_port_entry, $self, $entry, $k, 0],
'-validatecommand' => [\&_validate_design_entry, $self, 1, $entry, $k],
);
$entry->grid(
-row => $row,
......@@ -1347,71 +1347,6 @@ sub validate_duplicate_nets {
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)
# prompt the user to select a net name
sub _select_net_dialog {
......
Markdown is supported
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