Commit fc5e2cf2 authored by Stefan Tauner's avatar Stefan Tauner
Browse files

FIJI scripts: partial rewrite of FIJI Settings handling

 - get rid of backend store in FIJISettingsViewer
 - simplify overall function design and data structures
 - re-validate GUI elements on new data (settings or net lists)
 - warn before overwriting existing file in all cases
 - fix preliminary autocomplete (some remaining pre-existintg bugs in CompleteEntry.p)
parent 11f11613
......@@ -12,6 +12,7 @@ use Log::Log4perl qw(get_logger :easy);
use Verilog::Netlist;
sub new ($) {
my ($class) = @_;
......@@ -26,11 +27,12 @@ sub new ($) {
return $self;
}
sub read_file ($) {
my $logger = get_logger();
my ($self, $filename) = @_;
eval {
$self->{'nl'}->read_file(filename=>$filename); # read vqm file
$self->{'nl'}->read_file(filename => $filename); # read Verilog file
$self->{'nl'}->link(); # Read in any sub-modules
};
......@@ -39,16 +41,22 @@ sub read_file ($) {
return 1;
}
$logger->info("Successfully read in netlist from file \"$filename\".");
return 0;
}
# returns an array with all net names
#
# possible future extension:
# returns a hash with array of...
# - the 'names' of all nets
# - the 'paths' of all nets (TODO)
# - the 'metadata' of all nets (i.e. what VP's module->nets() returns) (TODO. needed? - it's huge)
sub get_nets ($) {
my ($self) = @_;
my $nets_ref = {'metadata' => [], 'names' => []};
# my $nets_ref = {'metadata' => [], 'names' => [], 'nets' => []};
my $nets_ref = [];
foreach my $mod ($self->{'nl'}->top_modules_sorted) {
$self->_get_subnets($nets_ref, $mod);
}
......@@ -59,8 +67,7 @@ sub get_nets ($) {
sub _get_subnets ($$) {
my ($self, $nets_ref, $mod) = @_;
foreach my $n ($mod->nets) {
# push($nets_ref->{'metadata'}, $n);
push(@{$nets_ref->{'names'}}, $n->name);
push(@{$nets_ref}, $n->name);
}
foreach my $cell ($mod->cells_sorted) {
......
......@@ -11,7 +11,6 @@ use warnings;
use Scalar::Util 'blessed';
use Log::Log4perl qw(get_logger);
use Scalar::Util "looks_like_number";
use Clone qw(clone);
use Config::Simple;
use FIJI qw(:all);
......@@ -21,11 +20,8 @@ use FIJI qw(:all);
#
# \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) An instance to reuse and return
# after overwriting existing values with defaults and any values
# read from file. Existing values will not be validated.
# Superfluous elements not present in the existing hash will be
# removed, e.g. FIUs.
# \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 a string describing the reason
# why it could not be created.
sub new ($;$$) {
......@@ -33,29 +29,34 @@ sub new ($;$$) {
my ($class, $phase, $fiji_ini_file, $existing_settings) = @_;
my $fiji_settings_ref;
# if there are no existing settings yet, create some with default values
# if there is no existing settings instance yet, create one
if (!defined($existing_settings)) {
$fiji_settings_ref = {};
$fiji_settings_ref->{'design'} = {};
_set_defaults(DESIGNMAP, $fiji_settings_ref->{'design'}, $phase);
$fiji_settings_ref = bless($fiji_settings_ref, $class);
if (!ref($fiji_settings_ref) || !UNIVERSAL::can($fiji_settings_ref,'can')) {
my $msg = "Could not bless FIJI::Settings class from \"$fiji_ini_file\".";
$logger->error($msg);
return $msg;
} else {
$fiji_settings_ref = $existing_settings;
}
if (!blessed($fiji_settings_ref) || !$fiji_settings_ref->isa("FIJI::Settings")) {
my $msg;
if (!defined($existing_settings)) {
$msg = "Could not create FIJI::Settings instance.";
} else {
$fiji_settings_ref = _clone($existing_settings);
$msg = "Given settings are not of type FIJI::Settings.";
}
$logger->error($msg);
return $msg;
}
# If there is a file given, try to read it. Else just add an empty FIUs array.
# If there is a file given, try to read it. Else just create a default instance.
if (defined($fiji_ini_file)) {
$fiji_settings_ref = read_settingsfile($phase, $fiji_ini_file, $fiji_settings_ref);
if (!ref($fiji_settings_ref)) {
return $fiji_settings_ref; # actually an error message
}
} else {
$fiji_settings_ref->{'FIUs'} = ();
$fiji_settings_ref->{'design'} = {};
_set_defaults(DESIGNMAP, $fiji_settings_ref->{'design'}, $phase);
$fiji_settings_ref->{'FIUs'} = [];
}
return $fiji_settings_ref;
}
......@@ -93,7 +94,6 @@ sub save ($) {
my $fiu_cnt = 0;
foreach my $key (keys %{$self}) {
my $val = $self->{$key};
$logger->debug(sprintf("Key: %s, type: %s, value: %s", $key, ref(\$val), $val));
if (ref(\$val) eq "REF") {
if (ref($val) eq "HASH") {
if ($key eq "design") {
......@@ -114,8 +114,14 @@ sub save ($) {
# Copy value to new hash with external naming.
$ini_fiu->{$ini_name} = $fiu->{$k};
# Convert value to external representation
_export_value(FIUMAP, $k, \$$fiu{$k});
$logger->trace(sprintf("Renaming setting %s -> %s (=%s).", $k, $ini_name, defined($ini_fiu->{$ini_name}) ? $ini_fiu->{$ini_name} : "undef"));
_export_value(FIUMAP, $k, \$ini_fiu->{$ini_name});
$logger->trace(sprintf("Exporting FIU%d setting %s -> %s (%s -> %s).",
$fiu_cnt,
$k,
$ini_name,
defined($fiu->{$k}) ? $fiu->{$k} : "undef",
defined($ini_fiu->{$ini_name}) ? $ini_fiu->{$ini_name} : "undef"),
);
}
$fiji_ini->set_block("FIU" . $fiu_cnt++, $ini_fiu);
}
......@@ -138,7 +144,13 @@ sub save ($) {
# Copy value to new hash with external naming.
$ini_design->{$ini_name} = $design_ref->{$k};
# Convert value to external representation
_export_value(DESIGNMAP, $k, \$$design_ref{$k});
_export_value(DESIGNMAP, $k, \$ini_design->{$ini_name});
$logger->trace(sprintf("Exporting Design setting %s -> %s (%s -> %s).",
$k,
$ini_name,
defined($design_ref->{$k}) ? $design_ref->{$k} : "undef",
defined($ini_design->{$ini_name}) ? $ini_design->{$ini_name} : "undef"),
);
}
$fiji_ini->set_block("CONSTS", $ini_design);
......@@ -164,115 +176,114 @@ sub save ($) {
# the constants for the respective FIU, see \ref _sanitize_fiu
#
# \returns a reference to the hash containing the read constants.
sub read_settingsfile {
sub read_settingsfile ($$$) {
my $logger = get_logger();
my ($phase, $fiji_ini_file, $existing_settings) = @_;
my $fiji_ini;
eval { $fiji_ini = new Config::Simple($fiji_ini_file) }; # pesky library tries to die on syntax errors
if (!defined($fiji_ini)) {
my $msg = "Could not read config file \"$fiji_ini_file\": " . (defined($@) ? $@ : Config::Simple->error());
my $submsg = defined($@) ? $@ : Config::Simple->error();
if (length($submsg) == 0) {
$submsg = "Empty file?";
}
my $msg = "Could not read config file \"$fiji_ini_file\": $submsg";
$logger->error($msg);
return $msg;
}
my $fiji_design_cfg = $fiji_ini->get_block("CONSTS");
if (!(%$fiji_design_cfg)) {
my $design_ref = $fiji_ini->get_block("CONSTS");
if (!(%$design_ref)) {
my $msg = "Could not fetch CONSTS block from config file \"$fiji_ini_file\"";
$logger->error($msg);
return $msg;
}
_set_defaults(DESIGNMAP, $design_ref, $phase);
my $fiji_design = _rename_import(DESIGNMAP, $fiji_design_cfg);
if (!defined($fiji_design)) {
$design_ref = _rename_import(DESIGNMAP, $design_ref);
if (!defined($design_ref)) {
my $msg = "Design constants do not match the FIJI Settings naming scheme.";
$logger->error($msg);
return $msg;
}
# Create a new instance or reuse the shallow hull of the existing one
my $fiji_settings_ref;
if (defined($existing_settings)) {
if (!blessed($existing_settings) || !$existing_settings->isa("FIJI::Settings")) {
my $msg ="Given settings are not of type FIJI::Settings.";
$logger->error($msg);
return $msg;
if (!defined($existing_settings)) {
$fiji_settings_ref = {};
bless($fiji_settings_ref, "FIJI::Settings");
} else {
$fiji_settings_ref = $existing_settings;
# Clear the hash
for (keys %$fiji_settings_ref) {
delete $fiji_settings_ref->{$_};
}
# overwrite existing Design Constants
foreach my $k (keys(%{$fiji_design})) {
$existing_settings->{'design'}->{$k} = $fiji_design->{$k};
}
$fiji_design = $existing_settings->{'design'};
if (defined($existing_settings->{'FIUs'})) {
$fiji_settings_ref->{'FIUs'} = $existing_settings->{'FIUs'};
if (!blessed($fiji_settings_ref) || !$fiji_settings_ref->isa("FIJI::Settings")) {
my $msg;
if (!defined($existing_settings)) {
$msg = "Could not create FIJI::Settings instance.";
} else {
$fiji_settings_ref->{'FIUs'} = ();
$msg = "Given settings are not of type FIJI::Settings.";
}
} else {
$fiji_settings_ref->{'FIUs'} = ();
$logger->error($msg);
return $msg;
}
$fiji_settings_ref->{'design'} = $design_ref;
$fiji_settings_ref->{'FIUs'} = [];
# sanitize and validate read design constants
$fiji_design = _sanitize_design($fiji_design, $phase);
if (!ref($fiji_design)) {
$logger->error($fiji_design);
return $fiji_design;
$design_ref = _sanitize_design($design_ref, $phase);
if (!ref($design_ref)) {
$logger->error($design_ref);
return $design_ref;
}
$fiji_settings_ref->{'design'} = $fiji_design;
my $fiu_num = 0;
# loop over all read FIUs
while (1) {
my $fiu_name = "FIU" . $fiu_num;
my $fiji_fiu_cfg = $fiji_ini->get_block($fiu_name);
if (!(%$fiji_fiu_cfg)) {
my $fiu_ref = $fiji_ini->get_block($fiu_name);
if (!(%$fiu_ref)) {
last;
}
my $fiji_fiu = _rename_import(FIUMAP, $fiji_fiu_cfg);
if (!defined($fiji_design)) {
$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.";
$logger->error($msg);
return $msg;
}
my $tmp_fiu = {};
_set_defaults(FIUMAP, $tmp_fiu, $phase);
if (defined($existing_settings)) {
my $ex_fiu = @{$existing_settings->{'FIUs'}}[$fiu_num];
if (defined($ex_fiu)) {
# overwrite default entries
foreach my $k (keys(%{$ex_fiu})) {
$tmp_fiu->{$k} = $ex_fiu->{$k};
}
}
# overwrite existing FIU entries
# $logger->trace("Overwriting values of $fiu_name.") if (defined($ex_fiu) && scalar(keys(%{$ex_fiu})) > 0);
foreach my $k (keys(%{$fiji_fiu})) {
$tmp_fiu->{$k} = $fiji_fiu->{$k};
foreach my $k (keys(%{$fiu_ref})) {
$tmp_fiu->{$k} = $fiu_ref->{$k};
}
$fiji_fiu = $tmp_fiu;
}
$fiji_fiu = _sanitize_fiu($fiji_fiu, $phase);
if (!defined($fiji_fiu)) {
my $msg = "Constants for $fiu_name in FIJI Settings are invalid";
$fiu_ref = $tmp_fiu;
$fiu_ref = _sanitize_fiu($fiu_ref, $phase);
if (!ref($fiu_ref)) {
my $msg = "(Some) constants for $fiu_name in FIJI Settings are invalid.";
$logger->error($msg);
return $msg;
}
@{$fiji_settings_ref->{'FIUs'}}[$fiu_num] = $fiji_fiu;
$fiji_settings_ref->{'FIUs'}->[$fiu_num] = $fiu_ref;
$fiu_num++;
$logger->trace("Read in $fiu_name from FIJI Settings file successfully.");
}
if ($fiu_num == 0) {
$logger->debug("Could not fetch any FIU block from config file \"$fiji_ini_file\"");
$fiji_settings_ref->{'FIUs'} = [];
$logger->debug("Could not fetch any FIU blocks from config file \"$fiji_ini_file\"");
}
# 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($fiji_design->{'FIU_NUM'}) && $fiji_design->{'FIU_NUM'} != $fiu_num) {
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 $msg;
} else {
$fiji_design->{'FIU_NUM'} = $fiu_num; # assume the best if FIU_NUM constant is not given
$design_ref->{'FIU_NUM'} = $fiu_num; # assume the best if FIU_NUM constant is not given
}
splice(@{$fiji_settings_ref->{'FIUs'}}, $fiu_num);
......@@ -300,6 +311,10 @@ sub _set_defaults {
next;
}
# Also, do not overwrite existing values
if (defined($consts_ref->{$k})) {
next;
}
$consts_ref->{$k} = $map_ref->{$k}->{default};
$logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $map_ref->{$k}->{'ini_name'}, $map_ref->{$k}->{default}));
}
......@@ -307,13 +322,6 @@ sub _set_defaults {
}
sub _clone ($) {
my ($existing_settings_ref) = @_;
my $new_settings_ref = \%{ Clone::clone ($existing_settings_ref) };
return $new_settings_ref;
}
sub validate_design_value {
my ($k, $v_ref) = @_;
return validate_value(DESIGNMAP, $k, $v_ref);
......@@ -438,7 +446,11 @@ sub _rename_import {
my $ini_name = $map_ref->{$k}->{'ini_name'};
if (exists($consts_ref->{$ini_name}) && $ini_name ne $k) {
$consts_ref->{$k} = $consts_ref->{$ini_name};
$logger->trace(sprintf("Renaming setting %s -> %s (=%s).", $ini_name, $k, defined($consts_ref->{$ini_name}) ? $consts_ref->{$ini_name} : "undef"));
$logger->trace(sprintf("Renaming Design setting %s -> %s (=%s).",
$ini_name,
$k,
defined($consts_ref->{$ini_name}) ? $consts_ref->{$ini_name} : "undef"),
);
delete $consts_ref->{$ini_name};
}
}
......
......@@ -41,20 +41,54 @@ sub Populate {
my $logger = get_logger();
my($self, $args) = @_;
my $settings = delete $args->{'-settings'};
if (!defined($settings) || ref($settings) ne 'REF' || !blessed(${$settings}) || !${$settings}->isa("FIJI::Settings")) {
if (!defined($settings) || !blessed($settings) || !$settings->isa("FIJI::Settings")) {
$logger->error("Given settings are not of type FIJI::Settings. No way to report this back from the constructor...");
} else {
$self->{'settings'} = $settings;
if (ref(${$self->{'settings'}}->{'FIUs'}) ne 'ARRAY') {
if (ref($self->{'settings'}->{'FIUs'}) ne 'ARRAY') {
$logger->debug("Adding empty FIUs array to settings reference.");
${$self->{'settings'}}->{'FIUs'} = [];
$self->{'settings'}->{'FIUs'} = [];
}
}
# FIXME: add an option to store a CODE reference that is called when any field is invalid
$self->SUPER::Populate($args);
$self->_populate_widget($self);
$self->ConfigSpecs(
-nets => [qw/METHOD nets Nets/, undef],
-settings => [qw/METHOD settings Settings/, undef],
);
$self->update();
}
sub nets {
my $logger = get_logger();
my ($self, $nets) = @_;
if (defined($nets)) {
if (ref($nets) ne 'ARRAY') {
$logger->error("Ignoring invalid nets array");
return undef;
}
$self->{'nets'} = $nets;
$self->update();
}
return $self->{'nets'}
}
sub settings {
my $logger = get_logger();
my ($self, $settings) = @_;
if (defined($settings)) {
if (!blessed($settings) || !$settings->isa("FIJI::Settings")) {
$logger->error("Given settings are not of type FIJI::Settings.");
return undef;
}
$self->{'settings'} = $settings;
$self->update();
}
return $self->{'settings'}
}
......@@ -95,14 +129,22 @@ sub update {
return;
}
$logger->trace("Connect widget ($name) with new settings instance hash ($k)");
$valw->{'fiji_backend_ref'} = \${$self->{'settings'}}->{'design'}->{$k};
my $orig_ref = \$self->{'settings'}->{'design'}->{$k};
my $type = DESIGNMAP->{$k}->{'type'};
my $orig = ${$self->{'settings'}}->{'design'}->{$k};
my $orig = $$orig_ref;
my $val = defined($type) && $type eq 'hexadecimal' ? sprintf("0x%x", $orig) : $orig;
if (ref($valw) eq 'Tk::CompleteEntry') {
$valw->configure('-choices' => $net_choices);
}
$valw->configure('-choices' => $net_choices,
'-textvariable' => $orig_ref,
);
} else {
if (defined($val)) {
$valw->configure('-text' => $val);
} else {
$valw->delete('0', 'end');
}
}
$valw->validate();
}
##############
......@@ -147,7 +189,7 @@ sub update {
my $fiu_cnt = $self->_fiu_cnt();
for (my $i = 0; $i < $fiu_cnt; $i++) {
my $fiu_ref = @{${$self->{'settings'}}->{'FIUs'}}[$i];
my $fiu_ref = @{$self->{'settings'}->{'FIUs'}}[$i];
$self->_add_fiu($fiu_ref, $i);
}
}
......@@ -211,21 +253,15 @@ sub _populate_widget {
);
# entry
my $type = DESIGNMAP->{$k}->{'type'};
my $orig = ${$self->{'settings'}}->{'design'}->{DESIGNMAP->{$k}->{'ini_name'}};
my $val = defined($type) && $type eq 'hexadecimal' ? sprintf("0x%x", $orig) : $orig;
if (defined($type) && $type eq 'net') {
$entry = $fr_design->CompleteEntry(
'-textvariable' => $val,
'-choices' => $net_choices,
);
$entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_net_entry, $self, $entry, $k],
);
} else {
$entry = $fr_design->Entry(
'-text' => $val,
);
$entry = $fr_design->Entry();
$entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_design_entry, $self, $entry, $k],
......@@ -315,7 +351,7 @@ sub _add_fiu_frame {
sub _fiu_cnt {
my($self) = @_;
my $fius = ${$self->{'settings'}}->{'FIUs'};
my $fius = $self->{'settings'}->{'FIUs'};
return (defined($fius) && ref($fius) eq 'ARRAY') ? scalar(@{$fius}) : 0;
}
......@@ -337,21 +373,10 @@ sub append_fiu ($) {
sub remove_fiu ($) {
my($self, $i) = @_;
$i = 0 if !defined($i);
splice(@{${$self->{'settings'}}->{'FIUs'}}, $i, 1);
splice(@{$self->{'settings'}->{'FIUs'}}, $i, 1);
$self->update();
}
sub set_netlist ($) {
my ($self, $filename) = @_;
my $nl = new FIJI::Netlist();
if ($nl->read_file($filename) != 0) {
return 1;
}
my $nets = $nl->get_nets();
$self->{'nets'} = $nets->{'names'};
return 0;
}
sub _add_fiu ($$) {
my($self, $fiu, $i) = @_;
if (!defined($i)) {
......@@ -360,8 +385,8 @@ sub _add_fiu ($$) {
if (!defined($fiu)) {
my %tmp_hash = (); # default is to add a new/empty FIU
$fiu = \%tmp_hash;
${$self->{'settings'}}->set_fiu_defaults($fiu);
push(@{${$self->{'settings'}}->{'FIUs'}}, $fiu);
$self->{'settings'}->set_fiu_defaults($fiu);
push(@{$self->{'settings'}->{'FIUs'}}, $fiu);
}
# forward declarations of widgets used in callbacks:
......@@ -376,7 +401,6 @@ sub _add_fiu ($$) {
'-textvariable' => \$fiu->{'FIU_NET_NAME'},
'-choices' => $choices,
);
# $net_entry->{'fiji_backend_ref'} = $text_ref;
$net_entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_net_entry, $self, $net_entry, "FIU$i"],
......@@ -403,11 +427,10 @@ sub _add_fiu ($$) {
'-width' => -1,
'-justify' => 'right',
);
$mask_entry->{'fiji_backend_ref'} = \$fiu->{'FIU_LFSR_MASK'};
$mask_entry->configure('-text' => sprintf("0x%x", $fiu->{'FIU_LFSR_MASK'}));
$mask_entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_fiu_entry, $self, $mask_entry, 'FIU_LFSR_MASK'],
'-validatecommand' => [\&_validate_fiu_entry, $self, $mask_entry, 'FIU_LFSR_MASK', $i],
);
$mask_entry->bind('<Control-a>',
sub {
......@@ -425,7 +448,7 @@ sub _add_fiu ($$) {
# $so_entry->configure('-text' => $fiu->{'FIU_LFSR_STUCK_OPEN_BIT'});
# $so_entry->configure(
# '-validate' => 'key',
# '-validatecommand' => [\&_validate_fiu_entry, $self, $so_entry, 'FIU_LFSR_STUCK_OPEN_BIT'],
# '-validatecommand' => [\&_validate_fiu_entry, $self, $so_entry, 'FIU_LFSR_STUCK_OPEN_BIT', $i],
# );
# $so_entry->bind('<Control-a>',
# sub {
......@@ -512,20 +535,18 @@ sub _update_fields {
my $model = ${$model_menu->cget('-variable')};
if ($model eq 'RUNTIME' ||
$model eq 'STUCK_OPEN') {
# $self->_set_fields(1, $lfsr_button, $so_entry);
# $self->_set_fields_by_button($lfsr_button, $mask_entry); # do not hard-enable $mask_entry
} elsif ($model eq 'PASS_THRU') {
# $self->_set_fields(0, $lfsr_button, $mask_entry, $so_entry);
} elsif ($model eq 'STUCK_AT_0' ||
$self->_set_fields(1, $mask_entry);
} elsif ($model eq 'PASS_THRU' ||
$model eq 'STUCK_AT_0' ||
$model eq 'STUCK_AT_1' ||
$model eq 'DELAY' ||
$model eq 'SEU') {
# $self->_set_fields(0, $so_entry);
# $self->_set_fields(1, $lfsr_button);
# $self->_set_fields_by_button($lfsr_button, $mask_entry); # do not hard-enable $mask_entry
$self->_set_fields(0, $mask_entry);
} else {
$logger->error("Unknown model selected: $model");
}
$net_entry->validate();
$mask_entry->validate();
}
......@@ -556,42 +577,52 @@ sub _validate_net {
}
my $complete_matches = grep(/^$new$/, @{$self->{'nets'}});
my $prefix_matches = grep(/^$new/, @{$self->{'nets'}});
$logger->trace("$new matches $complete_matches nets completely and is a prefix of $prefix_matches");
return $complete_matches == 1 || $prefix_matches > 0;
$logger->trace("'$new' matches $complete_matches nets completely and is a prefix of $prefix_matches");
return $complete_matches == 1;# || $prefix_matches > 0;
}
sub _validate_net_entry {
return _validate_entry(undef, @_);
my ($self, $widget, $name, $new) = @_;
my $ok = $self->_validate_net($widget, $name, $new);
_highlight_widget($widget, (!$ok));
# $widget->configure('-validate' => 'key');
return 1; # always allow the new value and show the user what happened.
}
sub _validate_design_entry {
return _validate_entry(DESIGNMAP, @_);
my $self = shift;
my $widget = shift;
my $name = shift;
my $new_ref = \shift;
my $old_ref = \$self->{'settings'}->{'design'}->{$name};
return _validate_entry(DESIGNMAP, $self, $widget, $name, $old_ref, $new_ref, @_);
}
sub _validate_fiu_entry {
return _validate_entry(FIUMAP, @_);
my $self = shift;
my $widget = shift;
my $name = shift;
my $i = shift;