Settings.pm 39.3 KB
Newer Older
1
2
3
#-----------------------------------------------------------------------
# Fault InJection Instrumenter (FIJI)
# https://embsys.technikum-wien.at/projects/vecs/fiji
Christian Fibich's avatar
Christian Fibich committed
4
#
5
6
7
8
# The creation of this file has been supported by the publicly funded
# R&D project Josef Ressel Center for Verification of Embedded Computing
# Systems (VECS) managed by the Christian Doppler Gesellschaft (CDG).
#
9
10
# Copyright (C) 2017 Christian Fibich <fibich@technikum-wien.at>
# Copyright (C) 2017 Stefan Tauner <tauner@technikum-wien.at>
Christian Fibich's avatar
Christian Fibich committed
11
#
12
13
# This module is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
Christian Fibich's avatar
Christian Fibich committed
14
#
15
16
17
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Christian Fibich's avatar
Christian Fibich committed
18
#
19
20
# See the LICENSE file for more details.
#-----------------------------------------------------------------------
Christian Fibich's avatar
Christian Fibich committed
21

Christian Fibich's avatar
Christian Fibich committed
22
23
## @file Settings.pm
# @brief Contains class \ref FIJI::Settings
24

25
## @class FIJI::Settings
Christian Fibich's avatar
Christian Fibich committed
26
# @brief Contains helper functions to deal with FIJI Settings files.
27

28
29
package FIJI::Settings;

30
31
32
use strict;
use warnings;

33
use Scalar::Util 'blessed';
34
35
use Log::Log4perl qw(get_logger);
use Scalar::Util "looks_like_number";
36
37
use POSIX qw(ceil);
use List::Util qw(max);
38
use File::Spec;
39

Christian Fibich's avatar
Christian Fibich committed
40
use FIJI::ConfigSorted;
41
42
use FIJI qw(:all);

Christian Fibich's avatar
Christian Fibich committed
43
## @var @base_resources stores the resource count for default config
Christian Fibich's avatar
Christian Fibich committed
44
45
my @base_resources;

46
## @function public new ($phase, $fiji_ini_file, $existing_settings, $nl_ref)
Stefan Tauner's avatar
Stefan Tauner committed
47
48
# Create a new settings instance.
#
49
50
51
52
53
54
55
56
57
# @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 {
58
    my $logger = get_logger("");
59
    my ($class, $phase, $fiji_ini_file, $existing_settings, $nl_ref) = @_;
60
61
62
63

    my $fiji_settings_ref;

    # if there is no existing settings instance yet, create one
Christian Fibich's avatar
Christian Fibich committed
64
    if (!defined($existing_settings)) {
65
        $fiji_settings_ref = {};
Christian Fibich's avatar
Christian Fibich committed
66
        $fiji_settings_ref = bless($fiji_settings_ref, $class);
67
    } else {
68
69
        $fiji_settings_ref = $existing_settings;
    }
Christian Fibich's avatar
Christian Fibich committed
70
    if (!blessed($fiji_settings_ref) || !$fiji_settings_ref->isa("FIJI::Settings")) {
71
        my $msg;
Christian Fibich's avatar
Christian Fibich committed
72
        if (!defined($existing_settings)) {
73
74
75
76
77
            $msg = "Could not create FIJI::Settings instance.";
        } else {
            $msg = "Given settings are not of type FIJI::Settings.";
        }
        $logger->error($msg);
78
        return (undef, $msg);
79
80
    }

81
    my ($errors, $warnings);
82
    # If there is a file given, try to read it. Else just create a default instance.
Christian Fibich's avatar
Christian Fibich committed
83
    if (defined($fiji_ini_file)) {
84
        ($fiji_settings_ref, $errors, $warnings) = read_settingsfile($phase, $fiji_ini_file, $fiji_settings_ref, $nl_ref);
85
        if (!defined($fiji_settings_ref)) {
86
            return (undef, $errors, $warnings);
87
        }
88
        $fiji_settings_ref->{'filename'} = $fiji_ini_file;
89
90
    } else {
        $fiji_settings_ref->{'design'} = {};
Christian Fibich's avatar
Christian Fibich committed
91
        _set_defaults(DESIGNMAP, $fiji_settings_ref->{'design'}, $phase);
92
        $fiji_settings_ref->{'fius'}     = [];
93
        $fiji_settings_ref->{'filename'} = File::Spec->curdir();
94
    }
Stefan Tauner's avatar
Stefan Tauner committed
95

96
    @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");
97

98
    return ($fiji_settings_ref, $errors, $warnings);
99
}
Stefan Tauner's avatar
Stefan Tauner committed
100
101

sub _export_value {
102
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
103
    my ($map_ref, $k, $v_ref) = @_;
104

Christian Fibich's avatar
Christian Fibich committed
105
    if (defined($map_ref->{$k}->{'type'})) {
106
        my $orig = ${$v_ref};
107
        if ($map_ref->{$k}->{'type'} eq 'hexadecimal' || $map_ref->{$k}->{'type'} eq 'lfsrpoly') {
Christian Fibich's avatar
Christian Fibich committed
108
            ${$v_ref} = sprintf("0x%x", $orig);
109
110
111

            # } elsif ($map_ref->{$k}->{'type'} eq 'natural') {
            # } elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
Christian Fibich's avatar
Christian Fibich committed
112
            $logger->trace("Converted value of $k (\"$orig\") to \"${$v_ref}\".") if ($orig ne ${$v_ref});
113
        } elsif ($map_ref->{$k}->{'type'} eq 'net' || $map_ref->{$k}->{'type'} eq 'driver') {
114
115
            # Due to an annoying behavior of Config::Simple we have to enclose
            # escaped identifiers with quotes. These are necessary to preserve spaces.
116
117
            # This also helps with concatenations... so simply quote all nets unconditionally.
            ${$v_ref} = "\"$orig\"";
118
119
        }
    }
120
121
}

122
## @method public save ($fiji_ini_file)
123
124
# @brief Store contained FIJI Settings to file.
#
Christian Fibich's avatar
Christian Fibich committed
125
# @attention Will happily overwrite existing files!
126
#
127
# @param fiji_ini_file The file name to write the FIJI Settings to.
Stefan Tauner's avatar
Stefan Tauner committed
128
sub save ($) {
129
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
130
    my ($self, $fiji_ini_file) = @_;
131
132
    return "No file name given" if !defined($fiji_ini_file);

Christian Fibich's avatar
Christian Fibich committed
133
    my $fiji_ini = new FIJI::ConfigSorted(syntax => 'ini');
134
135
    my $design_ref;
    my $fiu_cnt = 0;
Christian Fibich's avatar
Christian Fibich committed
136
    foreach my $key (keys %{$self}) {
137
        my $val = $self->{$key};
Christian Fibich's avatar
Christian Fibich committed
138
139
140
        if (ref(\$val) eq "REF") {
            if (ref($val) eq "HASH") {
                if ($key eq "design") {
141
142
143
                    $design_ref = $val;
                    next;
                }
Christian Fibich's avatar
Christian Fibich committed
144
145
146
            } elsif (ref($val) eq "ARRAY") {
                if ($key eq "fius") {
                    foreach my $fiu (@{$val}) {
147
148
                        my $ini_fiu;

Christian Fibich's avatar
Christian Fibich committed
149
                        foreach my $k (keys(%{$fiu})) {
150
                            my $ini_name = FIUMAP->{$k}->{'ini_name'};
Christian Fibich's avatar
Christian Fibich committed
151
                            if (!defined($fiu->{$k})) {
152
153
154
155
156
157
158
159
                                $logger->debug("Skip saving undefined value of FIU constant with key $ini_name.");
                                next;
                            }

                            # Copy value to new hash with external naming.
                            $ini_fiu->{$ini_name} = $fiu->{$k};

                            # Convert value to external representation
Christian Fibich's avatar
Christian Fibich committed
160
161
                            _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"),);
162
                        }
Christian Fibich's avatar
Christian Fibich committed
163
                        $fiji_ini->set_block("FIU" . $fiu_cnt++, $ini_fiu);
164
165
166
                    }
                    next;
                }
167
            }
168
169
        } elsif ($key eq "filename") {
            next;
170
        }
171
172

        my $err = "Unknown element found in FIJI Settings: key: \"$key\" val: \"$val\"";
173
174
175
176
177
        $logger->error($err);
        return $err;
    }
    $design_ref->{'FIU_NUM'} = $fiu_cnt;
    my $ini_design;
Christian Fibich's avatar
Christian Fibich committed
178
    foreach my $k (keys(%{$design_ref})) {
179
        my $ini_name = DESIGNMAP->{$k}->{'ini_name'};
Christian Fibich's avatar
Christian Fibich committed
180
        if (!defined($design_ref->{$k})) {
181
182
183
184
185
186
            $logger->debug("Skip saving undefined value of design constant with key $ini_name.");
            next;
        }

        # Copy value to new hash with external naming.
        $ini_design->{$ini_name} = $design_ref->{$k};
187

188
        # Convert value to external representation
Christian Fibich's avatar
Christian Fibich committed
189
190
        _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"),);
191
    }
Christian Fibich's avatar
Christian Fibich committed
192
    $fiji_ini->set_block("CONSTS", $ini_design);
193

Christian Fibich's avatar
Christian Fibich committed
194
    if (!defined($fiji_ini->write($fiji_ini_file))) {
Christian Fibich's avatar
Christian Fibich committed
195
        my $err = FIJI::ConfigSorted->error();
196
197
198
        $logger->error($err);
        return $err;
    }
199
    $self->{'filename'} = $fiji_ini_file;
200
201
    return undef;
}
202

203
## @function public read_settingsfile ($phase, $fiji_ini_file, $existing_settings, $nl_ref)
204
# @brief Load the FIJI Settings file containing design and FIU constants.
205
#
206
# @param phase  Tool flow phase the settings stored in the given file
Stefan Tauner's avatar
Stefan Tauner committed
207
#               need to be compatible with.
208
# @param fiji_ini_file The name of an .ini file with FIJI Settings:
209
#         - a 'consts' block containing the constants specified by
Stefan Tauner's avatar
Stefan Tauner committed
210
#           \ref _sanitize_design.
211
212
213
#         - 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
214
215
216
# @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)
217
#
218
219
220
# @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.
221
sub read_settingsfile ($$$) {
222
    my $logger = get_logger("");
223
    my ($phase, $fiji_ini_file, $existing_settings, $nl_ref) = @_;
224
    my $fiji_ini;
Christian Fibich's avatar
Christian Fibich committed
225
    eval { $fiji_ini = new FIJI::ConfigSorted($fiji_ini_file) };    # pesky library tries to die on syntax errors
Christian Fibich's avatar
Christian Fibich committed
226
    if (!defined($fiji_ini)) {
Christian Fibich's avatar
Christian Fibich committed
227
        my $submsg = defined($@) ? $@ : FIJI::ConfigSorted->error();
Christian Fibich's avatar
Christian Fibich committed
228
        if (length($submsg) == 0) {
229
230
231
232
            $submsg = "Empty file?";
        }
        my $msg = "Could not read config file \"$fiji_ini_file\": $submsg";
        $logger->error($msg);
233
        return (undef, $msg);
234
235
236
    }

    my $design_ref = $fiji_ini->get_block("CONSTS");
Christian Fibich's avatar
Christian Fibich committed
237
    if (!(%$design_ref)) {
238
239
        my $msg = "Could not fetch CONSTS block from config file \"$fiji_ini_file\"";
        $logger->error($msg);
240
        return (undef, $msg);
241
    }
Christian Fibich's avatar
Christian Fibich committed
242
    _set_defaults(DESIGNMAP, $design_ref, $phase);
243

Christian Fibich's avatar
Christian Fibich committed
244
245
    $design_ref = _rename_import(DESIGNMAP, $design_ref);
    if (!defined($design_ref)) {
246
247
        my $msg = "Design constants do not match the FIJI Settings naming scheme.";
        $logger->error($msg);
248
        return (undef, $msg);
249
250
251
252
    }

    # Create a new instance or reuse the shallow hull of the existing one
    my $fiji_settings_ref;
Christian Fibich's avatar
Christian Fibich committed
253
    if (!defined($existing_settings)) {
254
        $fiji_settings_ref = {};
Christian Fibich's avatar
Christian Fibich committed
255
        bless($fiji_settings_ref, "FIJI::Settings");
Stefan Tauner's avatar
Stefan Tauner committed
256
    } else {
257
258
259
        $fiji_settings_ref = $existing_settings;

        # Clear the hash
Christian Fibich's avatar
Christian Fibich committed
260
        for (keys %$fiji_settings_ref) {
261
262
263
            delete $fiji_settings_ref->{$_};
        }
    }
Christian Fibich's avatar
Christian Fibich committed
264
    if (!blessed($fiji_settings_ref) || !$fiji_settings_ref->isa("FIJI::Settings")) {
265
        my $msg;
Christian Fibich's avatar
Christian Fibich committed
266
        if (!defined($existing_settings)) {
267
268
269
270
271
            $msg = "Could not create FIJI::Settings instance.";
        } else {
            $msg = "Given settings are not of type FIJI::Settings.";
        }
        $logger->error($msg);
272
        return (undef, $msg);
273
274
275
276
277
    }
    $fiji_settings_ref->{'design'} = $design_ref;
    $fiji_settings_ref->{'fius'}   = [];

    # sanitize and validate read design constants
278
279
280

    my ($errors, $warnings);
    ($design_ref, $errors, $warnings) = _sanitize_design($design_ref, $phase, $nl_ref);
Christian Fibich's avatar
Christian Fibich committed
281
    if (!ref($design_ref)) {
282
283
        $logger->error($errors);
        return (undef, $errors, $warnings);
284
285
286
    }

    my $fiu_num = 0;
287
288
    my $error;
    # Loop over all read FIUs
289
    while (1) {
290

291
292
        my $fiu_id = "FIU" . $fiu_num;
        my $fiu_ref  = $fiji_ini->get_block($fiu_id);
Christian Fibich's avatar
Christian Fibich committed
293
        if (!(%$fiu_ref)) {
294
295
            last;
        }
Christian Fibich's avatar
Christian Fibich committed
296
        $fiu_ref = _rename_import(FIUMAP, $fiu_ref);
297
298
        if (!defined($fiu_ref)) {
            my $msg = "FIU constants of $fiu_id do not match the FIJI Settings naming scheme.";
299
            $logger->error($msg);
300
            return (undef, $msg);
301
302
303
        }

        my $tmp_fiu = {};
304
        _set_defaults(FIUMAP, $tmp_fiu, $phase, $design_ref, $fiu_num);
305
306

        # overwrite default entries
Christian Fibich's avatar
Christian Fibich committed
307
        foreach my $k (keys(%{$fiu_ref})) {
308
309
310
311
            $tmp_fiu->{$k} = $fiu_ref->{$k};
        }
        $fiu_ref = $tmp_fiu;

312
313
        my ($fiu_errors, $fiu_warnings);
        ($fiu_ref, $fiu_errors, $fiu_warnings) = _sanitize_fiu($fiu_ref, $phase, $nl_ref);
Christian Fibich's avatar
Christian Fibich committed
314
        if (!ref($fiu_ref)) {
315
316
317
            my $msg = "";
            $msg .= "$errors\n" if defined($errors);
            $msg .= "Fatal problems sanitizing $fiu_id:\n$fiu_errors";
318
            $logger->error($msg);
319
320
321
322
323
324
325
            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";
326
        }
327

328
329
330
        if (defined($fiu_warnings)) {
            $warnings = "" if !defined($warnings);
            $warnings .= "$name_str:\n$fiu_warnings";
331
332
        }

333
334
        $fiji_settings_ref->{'fius'}->[$fiu_num] = $fiu_ref;
        $fiu_num++;
335
        $logger->trace("Read in $fiu_id from FIJI Settings file successfully.");
336
337
    }

Christian Fibich's avatar
Christian Fibich committed
338
    if ($fiu_num == 0) {
339
        my $msg = "No FIU blocks in config file. Synthesis would fail.";
340
        $logger->warn($msg);
341
342
343
344
345
346
347
        if ($phase eq 'instrument') {
            $errors = "" if !defined($errors);
            $errors .= "$msg\n";
        } else {
            $warnings = "" if !defined($warnings);
            $warnings .= "$msg\n";
        }
348
349
350
351
    }

    # FIU_NUM is optional in the Settings file... if it was set check that
    # it corresponds to the number of FIU<number> blocks.
Christian Fibich's avatar
Christian Fibich committed
352
    if (defined($design_ref->{'FIU_NUM'}) && $design_ref->{'FIU_NUM'} != $fiu_num) {
353
354
355
356
        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";
357
    }
358
    $design_ref->{'FIU_NUM'} = $fiu_num; # assume the best if FIU_NUM constant is not given or misleading
359

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
    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 {
                $errors = "$msg\n";
            }
        } else {
            $logger->warn($msg);
            if (defined($warnings)) {
                $warnings .= "\n$msg\n";
            } else {
                $warnings = "$msg\n";
            }
        }
    }

    $logger->info("Successfully read in design constants and $fiu_num FIU definitions from FIJI Settings file \"$fiji_ini_file\".") if !defined($errors);
    return (!defined($errors) ? $fiji_settings_ref : undef, $errors, $warnings);
}

## @method determine_duplicate_fiu_nets (@$fius_ref)
# @brief Test for multiple instrumentations of a single net
#
# @param fius_ref   arrayref to a list of FIU hashes
# @param netname    (optional) Look only for a specific net.
#
# @returns          a (possible empty) hash keys by nets that are referred to multiple times.
#                   The values are arrays of FIU indices that refer to the key's net.
sub determine_duplicate_fiu_nets {
    my ($self, $target_net) = @_;

    my $fius_ref = $self->{'fius'};
    my $seen = {};
    my $dup_nets = {};
    my $i = 0;
    foreach my $fiu_ref (@{$fius_ref}) {
        my $netname = $fiu_ref->{'FIU_NET_NAME'};
        if (defined($netname) && length($netname) > 0) {
            if (!defined($target_net) || ($target_net eq $netname)) {
                if (defined $seen->{$netname}) {
                    if (!defined($dup_nets->{$netname})) {
                        $dup_nets->{$netname} = [$seen->{$netname}];
                    }
                    push(@{$dup_nets->{$netname}}, $i);
                } else {
                    $seen->{$netname} = $i;
                }
            }
        }
        $i += 1;
    }
    return $dup_nets;
421
422
}

423
## @method public set_fiu_defaults (%$fiu_ref)
424
425
426
# @brief Overwrite existing fields (if defined) with defaults defined in FIJI.pm.
#
sub set_fiu_defaults ($) {
427
428
    my ($self, $consts_ref, $phase, $fiu_num) = @_;
    return _set_defaults(FIUMAP, $consts_ref, $phase, $self->{'design'}, $fiu_num);
Stefan Tauner's avatar
Stefan Tauner committed
429
430
}

431
432
433
434
435
436
437
438
## @method public default_timer_value()
# @brief Return sensible default timer values for these settings
sub default_timer_value {
    my ($self) = @_;
    # default to 10 ms at default frequency
    return (10e-3 * $self->{'design'}->{'FREQUENCY'});
}

Stefan Tauner's avatar
Stefan Tauner committed
439
440
441
## @function _set_defaults (%$map_ref, %$consts_ref)
# @brief Set defaults according to FIJI.pm.
sub _set_defaults {
442
    my $logger = get_logger("");
443
    my ($map_ref, $consts_ref, $phase, $design_ref, $fiu_num) = @_;
Christian Fibich's avatar
Christian Fibich committed
444
445
    foreach my $k (keys(%{$map_ref})) {
        if (exists($map_ref->{$k}->{'default'})) {
446

447
            # Set default only if it is not mandatory in the given phase.
Christian Fibich's avatar
Christian Fibich committed
448
            if (defined($phase) && scalar(grep { $_ eq $phase } @{$map_ref->{$k}->{'phases_opt'}}) == 0) {
449
450
451
452
                next;
            }

            # Also, do not overwrite existing values
Christian Fibich's avatar
Christian Fibich committed
453
            if (defined($consts_ref->{$k})) {
454
455
                next;
            }
456
457
458
459
460
461
            my $default = $map_ref->{$k}->{default};
            if (ref($default) eq 'CODE') {
                $consts_ref->{$k} = $default->($consts_ref, $phase, $design_ref, $fiu_num);
            } else {
                $consts_ref->{$k} = $default;
            }
Christian Fibich's avatar
Christian Fibich committed
462
            $logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $map_ref->{$k}->{'ini_name'}, $map_ref->{$k}->{default}));
463
464
465
        }
    }
}
466

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
# @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;
}


538
## @function validate_value (%$map_ref, $nl_ref, $k, $$v_ref, $dep_ref, $consts_ref, $log_func)
539
540
#   Do validation (and conversation from external->internal representation)
#
541
542
543
544
545
546
547
548
549
550
#   @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 v_ref    scalar reference to the proposed value (that may be modified)
#   @param dep_ref  scalar reference to a value the proposed value depends on
#   @param consts_ref (optional) reference to related settings hash
#   @param log_func (optional) the (log4perl) log function to use
#                   (default is \&Log::Log4perl::Logger::trace)
#
#   @returns undef if value is valid, or a string to explain why it is invalid.
551
sub validate_value {
552
    my $logger = get_logger("");
553
    my ($map_ref, $nl_ref, $k, $v_ref, $dep_ref, $consts_ref, $log_func) = @_;
554
    $log_func = \&Log::Log4perl::Logger::trace if !defined($log_func);
555
556
557
558
559

    if (!defined (${$v_ref})) {
        # if a key does not contain a value, e.g.
        # DRIVER_TYPE=
        # set the corresponding value to an empty string instead of undef
560
        $logger->trace("$k is undef, setting to empty string");
561
562
563
        ${$v_ref} = ""
    }

Christian Fibich's avatar
Christian Fibich committed
564
    if (defined($map_ref->{$k}->{'type'})) {
565
566
        my $orig = ${$v_ref};

Christian Fibich's avatar
Christian Fibich committed
567
        if ($map_ref->{$k}->{'type'} eq 'net') {
568
569
570
571
572
573
            return "Netlist not available" if !defined($nl_ref);

            my $msg = $nl_ref->validate_net($orig);
            if (defined($msg)) {
                return $msg;
            }
574
575
576
577
578
        } 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;
            }
579
580
581
582
583
584
585
586
587
588
589
        } elsif ($map_ref->{$k}->{'type'} eq 'driver') {
            return "Netlist not available" if !defined($nl_ref);

            my $net_path = $consts_ref->{'FIU_NET_NAME'};
            my $driver_path = $orig;
            my $driver_type = $consts_ref->{'FIU_DRIVER_TYPE'};
            
            my $msg = $nl_ref->validate_driver($net_path, $driver_path, $driver_type);
            if (defined($msg)) {
                return "$msg";
            }
Christian Fibich's avatar
Christian Fibich committed
590
        } elsif ($map_ref->{$k}->{'type'} eq 'hexadecimal' || $map_ref->{$k}->{'type'} eq 'lfsrpoly') {
Christian Fibich's avatar
Christian Fibich committed
591
            if ($orig !~ /^(0|(0[xX][[:xdigit:]]+))$/) {
592
                return "$orig does not look like a natural hexadecimal number";
593
            }
594
            return "$orig is too large" if (length($orig) > 2+8); # Hexadecimal numbers > 0xffffffff are non-portable
595
596
597
            ${$v_ref} = hex($orig);

            # Check for natural value range. Should never trigger due to the regex above.
Christian Fibich's avatar
Christian Fibich committed
598
            if (${$v_ref} < 0) {
599
                return "$orig is negative";
600
            }
Christian Fibich's avatar
Christian Fibich committed
601
        } elsif ($map_ref->{$k}->{'type'} eq 'natural') {
602
603

            # Match hexadecimal, binary, octal and decimal numbers (the latter also in scientific notation)
Christian Fibich's avatar
Christian Fibich committed
604
            if ($orig !~ /^(0|(0(x[0-9a-fA-F]+|[0-7]+))|(0b[01]+)|([1-9][0-9]*(e(-[0-9])?[0-9]+)?))$/) {
605
                return "$orig does not look like a number";
606
607
608
609
            }

            # convert non-decimal (hexadecimal, binary, octal) values to decimal
            ${$v_ref} = oct($orig) if $orig =~ /^0/;
Christian Fibich's avatar
Christian Fibich committed
610
            if (!looks_like_number(${$v_ref})) {
611
                return "$orig does not look like a number";
612
            }
Stefan Tauner's avatar
Stefan Tauner committed
613

614
            # Check for natural value range. Should never trigger due to the regex above.
Christian Fibich's avatar
Christian Fibich committed
615
            if (${$v_ref} < 0) {
616
                return "$orig is negative";
617
            }
Christian Fibich's avatar
Christian Fibich committed
618
        } elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
619
620

            # convert strings to binary if need be
Christian Fibich's avatar
Christian Fibich committed
621
            if (!defined($orig)) {
622
                return "\"undef\" is not a boolean value";
Christian Fibich's avatar
Christian Fibich committed
623
            } elsif (lc($orig) eq 'true') {
624
                $orig = 1;
Christian Fibich's avatar
Christian Fibich committed
625
            } elsif (lc($orig) eq 'false') {
626
627
                $orig = 0;
            }
Christian Fibich's avatar
Christian Fibich committed
628
            if (($orig ne '0') && ($orig ne '1')) {
629
                return "\"$orig\" does not look like a boolean value";
630
631
632
            }

            # ensure proper boolean value, i.e. 0 or 1
Christian Fibich's avatar
Christian Fibich committed
633
            ${$v_ref} = (!!$orig) ? 1 : 0;
634
        }
Christian Fibich's avatar
Christian Fibich committed
635
        $logger->trace("Converted value of $k (\"$orig\") to \"${$v_ref}\".") if (defined($orig) && $orig ne ${$v_ref});
636
637
    }

Christian Fibich's avatar
Christian Fibich committed
638
    if (defined($map_ref->{$k}->{'values'})) {
639
        my $values_ref = $map_ref->{$k}->{'values'};
Christian Fibich's avatar
Christian Fibich committed
640
        if (ref($values_ref) eq 'ARRAY') {
641
642

            # Look for given value in allowed values
Christian Fibich's avatar
Christian Fibich committed
643
            if (scalar(grep { $_ eq ${$v_ref} } @{$values_ref}) == 0) {
644
                return "${$v_ref} is not allowed. Allowed values are: " . join(", ", @{$map_ref->{$k}->{'values'}});
645
            }
Christian Fibich's avatar
Christian Fibich committed
646
        } elsif (ref($values_ref) eq 'CODE') {
647
            if (!$values_ref->(${$v_ref}, $consts_ref->{$k}, $map_ref, $consts_ref, $$dep_ref)) {
648
                return "${$v_ref} is not allowed";
649
650
651
            }
        }
    }
652
    return undef;
653
}
Stefan Tauner's avatar
Stefan Tauner committed
654
655
656
657

# @function _rename_import (%$map_ref, %$consts_ref)
# Rename and convert entries in consts_ref according to map_ref.
#
658
659
660
661
# This function takes a hash of FIJI Settings and converts its keys
# to the respective internal representation. This allows us to use different
# name representations in the external file than within the implementation.
#
Stefan Tauner's avatar
Stefan Tauner committed
662
663
664
#
# \returns $consts_ref, or undef on errors
sub _rename_import {
665
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
666
667
    my ($map_ref, $consts_ref) = @_;
    if (ref($consts_ref) ne 'HASH') {
668
669
670
        $logger->error("Parameter is not a reference to a hash (containing design constants).");
        return undef;
    }
671

672
673
    # Iterating over respective hash from FIJI.pm and rename the entries
    # to match our internal naming scheme.
Christian Fibich's avatar
Christian Fibich committed
674
    foreach my $k (keys(%{$map_ref})) {
675
        my $ini_name = $map_ref->{$k}->{'ini_name'};
Christian Fibich's avatar
Christian Fibich committed
676
        if (exists($consts_ref->{$ini_name}) && $ini_name ne $k) {
677
            $consts_ref->{$k} = $consts_ref->{$ini_name};
678
            $logger->trace(sprintf("Renaming Design setting %s -> %s (=%s).", $ini_name, $k, defined($consts_ref->{$ini_name}) ? $consts_ref->{$ini_name} : "<undef>"),);
679
680
681
            delete $consts_ref->{$ini_name};
        }
    }
Christian Fibich's avatar
Christian Fibich committed
682
683
    foreach my $entry_key (keys(%{$consts_ref})) {
        if (!exists($map_ref->{$entry_key})) {
684
            $logger->warn(sprintf("Deleting unknown setting %s = %s.", $entry_key, defined($consts_ref->{$entry_key}) ? $consts_ref->{$entry_key} : "<undef>"));
685
686
687
688
689
690
            delete $consts_ref->{$entry_key};
        }
    }

    return $consts_ref;
}
Stefan Tauner's avatar
Stefan Tauner committed
691

692
## @function _sanitize_fiu (%$fiu_ref, $phase)
693
694
# @brief Convert and sanity check FIJI Settings.
#
695
696
# \param fiu_ref a reference to a hash containing FIJI Settings for a
#                single FIU.
Christian Fibich's avatar
Christian Fibich committed
697
# \param phase   the current design phase
698
699
700
#
# \returns A new hash with all constants required in the FIU settings
#          in sanitized form, or undef on errors.
701
702
703
# @returns A list comprising a) the given hash with all constants required in the FIU settings in sanitized form (or undef in the case of an error),
#          b) a diagnostic string describing the reason why sanitation failed (undef if successful),
#          c) a diagnostic string describing any anomalies that did not hinder sanitation.
704
sub _sanitize_fiu {
705
    my $logger = get_logger("");
706
    my ($fiu_ref, $phase, $nl_ref) = @_;
Christian Fibich's avatar
Christian Fibich committed
707
    if (ref($fiu_ref) ne 'HASH') {
708
709
        my $msg = "Parameter is not a reference to a hash (containing FIU constants).";
        $logger->error($msg);
710
        return (undef, $msg);
711
    }
712

713
714
    my ($warnings, $errors);
    ($fiu_ref, $errors, $warnings) = _validate_hashmap(FIUMAP, $nl_ref, $fiu_ref, $phase);
Christian Fibich's avatar
Christian Fibich committed
715
    if (!ref($fiu_ref)) {
716
717
        my $msg = "Could not validate FIU Constants. $errors";
        return chomp $msg;
718
    }
Stefan Tauner's avatar
Stefan Tauner committed
719

720
    return ($fiu_ref, $errors, $warnings);
721
722
}

723
sub _disabled_via_dependency {
Christian Fibich's avatar
Christian Fibich committed
724
    my ($map_ref, $consts_ref, $k) = @_;
725
726
727
    my $dependency = $map_ref->{$k}->{'depends_on'};
    return defined($dependency) && !$consts_ref->{$dependency};
}
728

Christian Fibich's avatar
Christian Fibich committed
729
sub _validate_hashmap {
730
    my $logger = get_logger("");
731
    my ($map_ref, $nl_ref, $consts_ref, $phase) = @_;
Christian Fibich's avatar
Christian Fibich committed
732
    my @map_keys = keys(%{$map_ref});
733
734
    my $errors;
    my $warnings;
Christian Fibich's avatar
Christian Fibich committed
735
    foreach my $entry_key (keys(%{$consts_ref})) {
736
737
738
739
        my $forbidden_by = $map_ref->{$entry_key}->{'forbidden_by'};
        my $ini_name     = $map_ref->{$entry_key}->{'ini_name'};

        @map_keys = grep { $_ ne $entry_key } @map_keys;    # mark constant key as done
Christian Fibich's avatar
Christian Fibich committed
740
741
        if (_disabled_via_dependency($map_ref, $consts_ref, $entry_key)) {
            $logger->debug(sprintf("Key %s is disabled via %s. Skipping validation.", $entry_key, $map_ref->{$entry_key}->{'depends_on'}));
742
743
        } elsif (scalar(grep { $_ eq $phase } @{$map_ref->{$entry_key}->{'phases_moot'}}) != 0) {
            $logger->debug(sprintf("Key %s is irrelevant in phase %s. Skipping validation.", $entry_key, $phase));
744
745
746
        } else {
            my $rv = validate_value($map_ref, $nl_ref, $entry_key, \$consts_ref->{$entry_key}, undef, $consts_ref);
            if (defined($rv)) {
747
                my $msg = sprintf("%s = \"%s\" is invalid (%s)%s.", $entry_key, !defined($consts_ref->{$entry_key}) ? "<undef>" : $consts_ref->{$entry_key}, $rv, defined($phase) ? " in phase $phase" : "");
748
749
750
751
752
753
754
755
756
757
                if (scalar(grep { $_ eq $phase } @{$map_ref->{$entry_key}->{'phases_opt'}}) == 0) {
                    $logger->error($msg);
                    $errors = "" if !defined($errors);
                    $errors .= "$msg\n";
                } else {
                    $logger->warn($msg);
                    $warnings = "" if !defined($warnings);
                    $warnings .= "$msg\n";
                }
            }
758
759
        }

Christian Fibich's avatar
Christian Fibich committed
760
        if (defined($forbidden_by) && $consts_ref->{$entry_key} && $consts_ref->{$forbidden_by}) {
761
762
            my $msg = "$entry_key is forbidden when $forbidden_by is enabled";
            $logger->error($msg);
763
764
            $errors = "" if !defined($errors);
            $errors .= "$msg\n";
765
        }
Stefan Tauner's avatar
Stefan Tauner committed
766
    }
767

Christian Fibich's avatar
Christian Fibich committed
768
    if (!defined($phase)) {
769

770
771
772
        # If there is no phase we are creating an "empty" hash that has
        # all possible defaults set earlier already and the there is
        # nothing we can or should do here.
773
        return ($consts_ref, $errors, $warnings);
774
    }
775

776
777
778
779
780
    # Iterate over the constants defined in FIJI.pm that apparently are
    # not contained in $consts_ref.
    foreach my $k (@map_keys) {
        my $dependency = $map_ref->{$k}->{'depends_on'};
        if (
Christian Fibich's avatar
Christian Fibich committed
781
782
783
            scalar(grep { $_ eq $phase } @{$map_ref->{$k}->{'phases_opt'}}) == 0 &&    # mandatory in current phase
            !_disabled_via_dependency($map_ref, $consts_ref, $k)                       # no dependency or dependency is enabled
           )
784
785
786
        {
            my $msg = "$k is mandatory in phase $phase.";
            $logger->error($msg);
787
788
            $errors = "" if !defined($errors);
            $errors .= "$msg\n";
789
790
791
        }

    }
Stefan Tauner's avatar
Stefan Tauner committed
792

Christian Fibich's avatar
Christian Fibich committed
793
    # @TODO: implement the same mechanism with forbidden_by
794

795
    return ($consts_ref, $errors, $warnings);
796
}
Stefan Tauner's avatar
Stefan Tauner committed
797

798
## @function _sanitize_design (%$consts_ref, $phase, $nl_ref)
Stefan Tauner's avatar
Stefan Tauner committed
799
# @brief Sanity check FIJI Design Settings.
800
#
801
802
# The function deals with sanity checks for the values themselves as
# specified by FIJI.pm. Additionally, it checks for the following conditions:
803
804
#
#   - FIU_CFG_BITS: > 0
805
#   - TIMER_WIDTH: > 0, <= 16
806
807
808
#   - ID: > 0, < 2^15-1
#   - BAUDRATE: > 0
#
809
810
811
# @param consts_ref A reference to a hash containing some design settings
# @param phase      The tool flow phase that defines the rules to check against
# @param nl_ref     A reference to a FIJI::netlist (for validation of nets and drivers only)
812
#
813
814
815
# @returns A list comprising a) the given hash ref with all constants required in the design settings in sanitized form (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 that did not hinder sanitation.
Stefan Tauner's avatar
Stefan Tauner committed
816
sub _sanitize_design {
817
    my $logger = get_logger("");
818
    my ($consts_ref, $phase, $nl_ref) = @_;
Christian Fibich's avatar
Christian Fibich committed
819
    if (ref($consts_ref) ne 'HASH') {
820
        return (undef, "Parameter is not a reference to a hash (containing design constants).");
821
822
823
    }

    # check for sane values
824
825
    my ($warnings, $errors);
    ($consts_ref, $errors, $warnings) = _validate_hashmap(DESIGNMAP, $nl_ref, $consts_ref, $phase);
Christian Fibich's avatar
Christian Fibich committed
826
    if (!ref($consts_ref)) {
827
828
        my $msg = "Could not validate Design Constants:\n$errors";
        return (undef, chomp $msg, $warnings);
829
830
    }

Christian Fibich's avatar
Christian Fibich committed
831
    if (($consts_ref->{'FIU_CFG_BITS'} <= 0)) {
832
833
        $errors = "" if !defined($errors);
        $errors .= "FIU_CFG_BITS is <= 0.\n";
834
    }
Christian Fibich's avatar
Christian Fibich committed
835
    if (($consts_ref->{'TIMER_WIDTH'} <= 0) || ($consts_ref->{'TIMER_WIDTH'} > 16)) {
836
837
        $errors = "" if !defined($errors);
        $errors .= "TIMER_WIDTH is invalid ($consts_ref->{'TIMER_WIDTH'}).\n";
838
    }
Christian Fibich's avatar
Christian Fibich committed
839
    if (defined($consts_ref->{'ID'}) && ($consts_ref->{ID} < 0 || $consts_ref->{ID} > (2**16 - 1))) {
840
841
        $errors = "" if !defined($errors);
        $errors .= sprintf("ID is invalid (0x%04X).\n", $consts_ref->{ID});
842
    }
Christian Fibich's avatar
Christian Fibich committed
843
    if (($consts_ref->{'BAUDRATE'} <= 0)) {
844
845
        $errors = "" if !defined($errors);
        $errors .= "BAUDRATE is <= 0.\n";
846
847
    }

848
    return ($consts_ref, $errors, $warnings);
849
850
}

851
852
sub _log2 {
    my $val = shift;
Christian Fibich's avatar
Christian Fibich committed
853
    return ($val > 0) ? (log($val) / log(2)) : 0;
854
855
}

856
## @function private _est_resources ($FREQUENCY, $BAUD, $TIMER_WIDTH, $RST_CYCLES, $LFSR_WIDTH, $FIU_NUM, $algo)
857
# @brief estimates the number of registers and LUTs to implement FIJI logic with the given settings
Christian Fibich's avatar
Christian Fibich committed
858
#
859
860
861
862
863
# The function ant its parameters were determined by experiment & fitted by scipy.optimize.curve_fit
#
# @param FREQUENCY      the clock frequency the FIJI logic will run at in Hz
# @param BAUD           the baud rate for DUT <-> FIJI communication
# @param TIMER_WIDTH    the width of the injection timer (durations) in Bytes
864
# @param RST_CYCLES   the number of cycles to apply a FIJI-to-DUT reset
865
# @param LFSR_WIDTH     width of the LFSR used for stuck-open emulation
Christian Fibich's avatar
Christian Fibich committed
866
# @param FIU_NUM        the number of FIUs in the configuration
867
868
869
#
# @returns ($registers, $lutsum)

Christian Fibich's avatar
Christian Fibich committed
870
sub _est_resources {
871
872
873
874
    # We recalculate resources even if parameters are bogus. Disabling
    # warnings at least hides this stupidity from the user.
    no warnings 'numeric';

875
    my $logger = get_logger("");
876
    my ($FREQUENCY, $BAUD, $TIMER_WIDTH, $RST_CYCLES, $LFSR_WIDTH, $FIU_NUM) = @_;
Christian Fibich's avatar
Christian Fibich committed
877

Christian Fibich's avatar
Christian Fibich committed
878
    # @FIXME where do we put these values? they are likely to change if the VHDL
879
880
    # source is changed...

Christian Fibich's avatar
Christian Fibich committed
881
882
    my $registers;
    my $lut6;
883
    my $out_of_range = [];
Christian Fibich's avatar
Christian Fibich committed
884

885
886
887
888
    if ($FREQUENCY < 1000000 || $FREQUENCY > 500000000) {
        $logger->debug("FREQUENCY $FREQUENCY out of range for correct resource estimation (1000000 - 500000000)");
        push @{$out_of_range}, "FREQUENCY";
    }
Christian Fibich's avatar
Christian Fibich committed
889
    if ($BAUD < 9600 || $BAUD > 3000000) {
890
891
892
        $logger->debug("BAUD $BAUD out of range for correct resource estimation (9600 - 3000000)");
        push @{$out_of_range}, "BAUD";
    }
Christian Fibich's avatar
Christian Fibich committed
893
    if ($TIMER_WIDTH < 1 || $TIMER_WIDTH > 8) {
894
895
896
        $logger->debug("TIMER_WIDTH $TIMER_WIDTH out of range for correct resource estimation (1 - 8)");
        push @{$out_of_range}, "TIMER_WIDTH";
    }
897
898
899
    if ($RST_CYCLES < 1 || $RST_CYCLES > 16) {
        $logger->debug("RST_CYCLES $RST_CYCLES out of range for correct resource estimation (1 - 16)");
        push @{$out_of_range}, "RST_CYCLES";
900
    }
Christian Fibich's avatar
Christian Fibich committed
901
    if ($LFSR_WIDTH < 16 || $LFSR_WIDTH > 64) {
902
        $logger->debug("LFSR_WIDTH $LFSR_WIDTH out of range for correct resource estimation (16 - 64)");
903
        push @{$out_of_range}, "RST_CYCLES";
904
    }
Christian Fibich's avatar
Christian Fibich committed
905
    if ($FIU_NUM < 1 || $FIU_NUM > 64) {