Tests.pm 41.6 KB
Newer Older
Christian Fibich's avatar
Christian Fibich committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#-------------------------------------------------------------------------------
#  University of Applied Sciences Technikum Wien
#
#  Department of Embedded Systems
#  http://embsys.technikum-wien.at
#
#  Josef Ressel Center for Verification of Embedded Computing Systems
#  http://vecs.technikum-wien.at
#
#-------------------------------------------------------------------------------
#  Description:
#
# Contains helper functions to deal with FIJI Test files.
#-------------------------------------------------------------------------------

16
## @file Tests.pm
Christian Fibich's avatar
Christian Fibich committed
17
# @brief Contains class \ref FIJI::Tests
18
19
20

## @class FIJI::Tests
#
Christian Fibich's avatar
Christian Fibich committed
21
# @brief Contains helper functions to deal with FIJI Test files.
22
23
24
25
26
27
28
29
30
31
package FIJI::Tests;

use strict;
use warnings;

use Scalar::Util 'blessed';
use Log::Log4perl qw(get_logger);
use Scalar::Util "looks_like_number";
use Data::Dumper;
use Clone qw(clone);
Christian Fibich's avatar
Christian Fibich committed
32
33
34
use File::Spec;

use FIJI::ConfigSorted;
35
use FIJI::Settings;
36
37
use FIJI::Tests::VHDL;
use FIJI::Tests::SystemVerilog;
38
use FIJI qw(:all);
Christian Fibich's avatar
Christian Fibich committed
39

Christian Fibich's avatar
Christian Fibich committed
40
# @FIXME rather similar to Settings.pm
Christian Fibich's avatar
Christian Fibich committed
41
42
# Can we generalize this?

Christian Fibich's avatar
Christian Fibich committed
43
# @FIXME which data has to be present in a test configuration file?
Christian Fibich's avatar
Christian Fibich committed
44

45
## @function public new ($phase, $fiji_ini_file, $existing_settings)
46
47
# Create a new settings instance.
#
Christian Fibich's avatar
Christian Fibich committed
48
49
50
# \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
51
52
53
#        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.
54
sub new {
55
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
56
    my ($class, $phase, $cfgs_per_msg, $fiu_num, $fiji_ini_file, $existing_settings, $num_tests) = @_;
57

58
    my $fiji_settings_ref = {};
59

60
61
    $fiji_settings_ref->{'ext'}->{'CFGS_PER_MSG'} = $cfgs_per_msg;
    $fiji_settings_ref->{'ext'}->{'FIU_NUM'}      = $fiu_num;
Christian Fibich's avatar
Christian Fibich committed
62

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

80
    # If there is a file given, try to read it. Else just create a default instance.
Christian Fibich's avatar
Christian Fibich committed
81
82
    if (defined($fiji_ini_file)) {
        $fiji_settings_ref = read_settingsfile($phase, $fiji_ini_file, $fiji_settings_ref, $cfgs_per_msg, $fiu_num);
Christian Fibich's avatar
Christian Fibich committed
83

Christian Fibich's avatar
Christian Fibich committed
84
        if (!ref($fiji_settings_ref)) {
85
86
            return $fiji_settings_ref;    # actually an error message
        }
87
88
        $fiji_settings_ref->{'filename'} = $fiji_ini_file;

89
    } else {
Christian Fibich's avatar
Christian Fibich committed
90

91
92
93
94
        # create a default instance

        $fiji_settings_ref->{'design'} = {};
        my $tkm_ref = TESTCONSTMAP;
Christian Fibich's avatar
Christian Fibich committed
95
        for my $k (keys(%{$tkm_ref})) {
96
            $fiji_settings_ref->{'design'}->{$k} = TESTCONSTMAP->{$k}->{'default'};
97
        }
98

Christian Fibich's avatar
Christian Fibich committed
99
        _set_defaults(TESTCONSTMAP, $fiji_settings_ref->{'design'}, $phase);
100
101
102
103
104
        $fiji_settings_ref->{'design'}->{'NUM_TESTS'} = $num_tests;
        $fiji_settings_ref->{'ext'}->{'TESTPATMAP'}   = _generate_testpatmap($fiji_settings_ref);

        $fiji_settings_ref->{'tests'} = [];

Christian Fibich's avatar
Christian Fibich committed
105
106
        if (defined($num_tests)) {
            for (my $i = 0 ; $i < $num_tests ; $i++) {
107
                my $thistest = {};
Christian Fibich's avatar
Christian Fibich committed
108
                for my $k (keys(%{$fiji_settings_ref->{'ext'}->{'TESTPATMAP'}})) {
109
110
                    $thistest->{$k} = $fiji_settings_ref->{'ext'}->{'TESTPATMAP'}->{$k}->{'default'};
                }
Christian Fibich's avatar
Christian Fibich committed
111
                push @{$fiji_settings_ref->{'tests'}}, $thistest;
Christian Fibich's avatar
Christian Fibich committed
112
            }
113
        }
114
        $fiji_settings_ref->{'filename'} = File::Spec->curdir();
115
    }
116
    return $fiji_settings_ref;
117
118
}

119
sub _export_value {
120
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
121
    my ($map_ref, $k, $v_ref) = @_;
122

Christian Fibich's avatar
Christian Fibich committed
123
    if (defined($map_ref->{$k}->{'type'})) {
124
        my $orig = ${$v_ref};
Christian Fibich's avatar
Christian Fibich committed
125
126
        if ($map_ref->{$k}->{'type'} eq 'hexadecimal') {
            ${$v_ref} = sprintf("0x%x", $orig);
127

128
129
            # } elsif ($map_ref->{$k}->{'type'} eq 'natural') {
            # } elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
Christian Fibich's avatar
Christian Fibich committed
130
            $logger->trace("Converted value of $k (\"$orig\") to \"${$v_ref}\".") if ($orig ne ${$v_ref});
131
132
133
134
        }

        # } elsif (defined($map_ref->{$k}->{'values'})) {
    }
135
136
}

137
## @method public save ($fiji_ini_file)
138
139
# @brief Store contained FIJI Settings to file.
#
Christian Fibich's avatar
Christian Fibich committed
140
# @attention Will happily overwrite existing files!
141
142
#
# \param fiji_ini_file The file name to write the FIJI Settings to.
143
sub save {
144
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
145
    my ($self, $fiji_ini_file) = @_;
146
147
    return "No file name given" if !defined($fiji_ini_file);

Christian Fibich's avatar
Christian Fibich committed
148
    my $fiji_ini = new FIJI::ConfigSorted(syntax => 'ini');
149
150
151
    my $design_ref;
    my $test_cnt = 0;

Christian Fibich's avatar
Christian Fibich committed
152
    foreach my $key (keys %{$self}) {
153
        my $val = $self->{$key};
Christian Fibich's avatar
Christian Fibich committed
154
155
156
        if (ref(\$val) eq "REF") {
            if (ref($val) eq "HASH") {
                if ($key eq "design") {
157
158
                    $design_ref = $val;
                    next;
Christian Fibich's avatar
Christian Fibich committed
159
                } elsif ($key eq "ext") {
160
161
                    next;
                }
Christian Fibich's avatar
Christian Fibich committed
162
163
164
            } elsif (ref($val) eq "ARRAY") {
                if ($key eq "tests") {
                    foreach my $test (@{$val}) {
165
166
                        my $ini_test;

Christian Fibich's avatar
Christian Fibich committed
167
                        foreach my $k (keys(%{$test})) {
168
                            my $ini_name = $self->{'ext'}->{'TESTPATMAP'}->{$k}->{'ini_name'};
Christian Fibich's avatar
Christian Fibich committed
169
                            if (!defined($test->{$k})) {
170
171
172
173
174
175
176
177
                                $logger->debug("Skip saving undefined value of TEST constant with key $ini_name.");
                                next;
                            }

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

                            # Convert value to external representation
Christian Fibich's avatar
Christian Fibich committed
178
179
                            _export_value($self->{'ext'}->{'TESTPATMAP'}, $k, \$ini_test->{$ini_name});
                            $logger->trace(sprintf("Exporting TEST%d setting %s -> %s (%s -> %s).", $test_cnt, $k, $ini_name, defined($test->{$k}) ? $test->{$k} : "undef", defined($ini_test->{$ini_name}) ? $ini_test->{$ini_name} : "undef"),);
180
                        }
Christian Fibich's avatar
Christian Fibich committed
181
                        $fiji_ini->set_block("TEST" . $test_cnt++, $ini_test);
182
183
184
                    }
                    next;
                }
185
            }
186
187
        } elsif ($key eq "filename") {
            next;
188
        }
189

190
191
192
193
194
195
196
        my $err = "Unknown element found in FIJI Settings: \"$val\"";
        $logger->error($err);

        #return $err;
    }
    $design_ref->{'NUM_TESTS'} = $test_cnt;
    my $ini_design;
Christian Fibich's avatar
Christian Fibich committed
197
    foreach my $k (keys(%{$design_ref})) {
198
        my $ini_name = TESTCONSTMAP->{$k}->{'ini_name'};
Christian Fibich's avatar
Christian Fibich committed
199
        if (!defined($design_ref->{$k})) {
200
201
202
203
204
205
            $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};
206

207
        # Convert value to external representation
Christian Fibich's avatar
Christian Fibich committed
208
209
        _export_value(TESTCONSTMAP, $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"),);
210
    }
Christian Fibich's avatar
Christian Fibich committed
211
    $fiji_ini->set_block("CONSTS", $ini_design);
212

Christian Fibich's avatar
Christian Fibich committed
213
    if (!defined($fiji_ini->write($fiji_ini_file))) {
Christian Fibich's avatar
Christian Fibich committed
214
        my $err = FIJI::ConfigSorted->error();
215
216
217
        $logger->error($err);
        return $err;
    }
218
219

    $self->{'filename'} = $fiji_ini_file;
220
221
    return undef;
}
222

223
## @function public read_settingsfile ($phase, $fiji_ini_file)
224
225
226
227
228
229
230
231
232
233
234
235
# @brief Load the FIJI Settings file containing design and TEST constants.
#
# \param phase  Tool flow phase the settings stored in the given file
#               need to be compatible with.
# \param fiji_ini_file The name of an .ini file with FIJI Settings:
#         - a 'consts' block containing the constants specified by
#           \ref _sanitize_design.
#         - at least one TEST block named "TEST<number>" where "<number>"
#           is a strictly increasing integer starting with 0 containing
#           the constants for the respective TEST, see \ref _sanitize_test
#
# \returns a reference to the hash containing the read constants.
236
sub read_settingsfile {
237
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
238
    my ($phase, $fiji_ini_file, $existing_settings, $cfgs_per_msg, $fiu_num) = @_;
239
240
241
    my $fiji_ini;
    my $global_settings_filename;

Christian Fibich's avatar
Christian Fibich committed
242
    eval { $fiji_ini = new FIJI::ConfigSorted($fiji_ini_file) };    # pesky library tries to die on syntax errors
Christian Fibich's avatar
Christian Fibich committed
243
    if (!defined($fiji_ini)) {
Christian Fibich's avatar
Christian Fibich committed
244
        my $submsg = defined($@) ? $@ : FIJI::ConfigSorted->error();
Christian Fibich's avatar
Christian Fibich committed
245
        if (length($submsg) == 0) {
246
247
248
249
250
251
            $submsg = "Empty file?";
        }
        my $msg = "Could not read config file \"$fiji_ini_file\": $submsg";
        $logger->error($msg);
        return $msg;
    }
252

253
    my $design_ref = $fiji_ini->get_block("CONSTS");
Christian Fibich's avatar
Christian Fibich committed
254
    if (!(%$design_ref)) {
255
256
257
258
        my $msg = "Could not fetch CONSTS block from config file \"$fiji_ini_file\"";
        $logger->error($msg);
        return $msg;
    }
Christian Fibich's avatar
Christian Fibich committed
259
    _set_defaults(TESTCONSTMAP, $design_ref, $phase);
260

Christian Fibich's avatar
Christian Fibich committed
261
262
    $design_ref = _rename_import(TESTCONSTMAP, $design_ref);
    if (!defined($design_ref)) {
263
264
265
266
        my $msg = "Design constants do not match the FIJI Tests naming scheme.";
        $logger->error($msg);
        return $msg;
    }
267

268
269
270
    # Create a new instance or reuse the shallow hull of the existing
    my $fiji_settings_ref;

Christian Fibich's avatar
Christian Fibich committed
271
    if (!defined($existing_settings)) {
272
        $fiji_settings_ref = {};
Christian Fibich's avatar
Christian Fibich committed
273
        bless($fiji_settings_ref, "FIJI::Tests");
274
    } else {
275
276
277
        $fiji_settings_ref = $existing_settings;

        # Clear the hash
Christian Fibich's avatar
Christian Fibich committed
278
        for (keys %$fiji_settings_ref) {
279
280
            delete $fiji_settings_ref->{$_};
        }
281
    }
Christian Fibich's avatar
Christian Fibich committed
282
    if (!blessed($fiji_settings_ref) || !$fiji_settings_ref->isa("FIJI::Tests")) {
283
        my $msg;
Christian Fibich's avatar
Christian Fibich committed
284
        if (!defined($existing_settings)) {
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
            $msg = "Could not create FIJI::Tests instance.";
        } else {
            $msg = "Given settings are not of type FIJI::Tests.";
        }
        $logger->error($msg);
        return $msg;
    }

    $fiji_settings_ref->{'ext'}->{'CFGS_PER_MSG'} = $cfgs_per_msg;
    $fiji_settings_ref->{'ext'}->{'FIU_NUM'}      = $fiu_num;
    $fiji_settings_ref->{'ext'}->{'TESTPATMAP'}   = _generate_testpatmap($fiji_settings_ref);
    $fiji_settings_ref->{'design'}                = $design_ref;
    $fiji_settings_ref->{'tests'}                 = [];

    # sanitize and validate read design constants
Christian Fibich's avatar
Christian Fibich committed
300
301
    $design_ref = _sanitize_design($design_ref, $phase);
    if (!ref($design_ref)) {
302
303
304
305
306
307
308
309
310
311
        $logger->error($design_ref);
        return $design_ref;
    }

    my $test_num = 0;

    # loop over all read TESTs
    while (1) {
        my $test_name = "TEST" . $test_num;
        my $test_ref  = $fiji_ini->get_block($test_name);
Christian Fibich's avatar
Christian Fibich committed
312
        if (!(%$test_ref)) {
313
314
315
            last;
        }

Christian Fibich's avatar
Christian Fibich committed
316
317
        $test_ref = _rename_import($fiji_settings_ref->{'ext'}->{'TESTPATMAP'}, $test_ref);
        if (!defined($design_ref)) {
318
319
320
321
322
323
            my $msg = "Test constants of $test_name do not match the FIJI Tests naming scheme.";
            $logger->error($msg);
            return $msg;
        }

        my $tmp_test = {};
Christian Fibich's avatar
Christian Fibich committed
324
        _set_defaults($fiji_settings_ref->{'ext'}->{'TESTPATMAP'}, $tmp_test, $phase);
325
326

        # overwrite default entries
Christian Fibich's avatar
Christian Fibich committed
327
        foreach my $k (keys(%{$test_ref})) {
328
329
330
331
            $tmp_test->{$k} = $test_ref->{$k};
        }
        $test_ref = $tmp_test;

Christian Fibich's avatar
Christian Fibich committed
332
333
        $test_ref = _sanitize_test($fiji_settings_ref->{'ext'}->{'TESTPATMAP'}, $test_ref, $phase);
        if (!ref($test_ref)) {
334
335
336
337
338
339
340
341
342
            my $msg = "(Some) constants for $test_name in Tests Settings are invalid.";
            $logger->error($msg);
            return $msg;
        }
        $fiji_settings_ref->{'tests'}->[$test_num] = $test_ref;
        $test_num++;
        $logger->trace("Read in $test_name from FIJI Tests file successfully.");
    }

Christian Fibich's avatar
Christian Fibich committed
343
    if ($test_num == 0) {
344
345
346
347
348
        $logger->debug("Could not fetch any TEST blocks from config file \"$fiji_ini_file\"");
    }

    # TEST_NUM is optional in the Settings file... if it was set check that
    # it corresponds to the number of TEST<number> blocks.
Christian Fibich's avatar
Christian Fibich committed
349
    if (defined($design_ref->{'NUM_TESTS'}) && $design_ref->{'NUM_TESTS'} != $test_num) {
350
351
352
353
354
355
356
        my $msg = NUM_TESTS->{'ini_name'} . " does not match the numbers of TEST blocks found.";
        $logger->error($msg);
        return $msg;
    } else {
        $design_ref->{'NUM_TESTS'} = $test_num;    # assume the best if TEST_NUM constant is not given
    }

Christian Fibich's avatar
Christian Fibich committed
357
    splice(@{$fiji_settings_ref->{'tests'}}, $test_num);
358
359
    $logger->info("Successfully read in design constants and $test_num TEST definitions from FIJI Tests file \"$fiji_ini_file\".");
    return $fiji_settings_ref;
360
361
}

362
363
364
## @method private _generate_testpatmap ()
# @brief generates tailored TESTPATMAP for validating test patterns
#
365
# clones the original TESTPATMAP and adds FIU_x_FAULT_y keys
366
367
#
# @returns the tailored TESTPATMAP
368
sub _generate_testpatmap {
369
    my ($self) = @_;
370

371
    my $testpatmap = clone(TESTPATMAP);
372

Christian Fibich's avatar
Christian Fibich committed
373
    for (my $pattern_idx = 1 ; $pattern_idx <= $self->{'ext'}->{'CFGS_PER_MSG'} ; $pattern_idx++) {
374

375
        my $prop_name = "TIMER_VALUE_${pattern_idx}";
376
        $testpatmap->{$prop_name} = {
377
            ini_name   => $prop_name,
378
            default    => DEFAULT_TIMER_VALUE,
379
            type       => "natural",
380
            phases_opt => [qw(manual)]
381
382
        };

Christian Fibich's avatar
Christian Fibich committed
383
        for (my $fiu_idx = 0 ; $fiu_idx < $self->{'ext'}->{'FIU_NUM'} ; $fiu_idx++) {
384
385
386
387
388
389
390
            my $prop_name = "FIU_${fiu_idx}_FAULT_${pattern_idx}";
            $testpatmap->{$prop_name} = {
                ini_name   => $prop_name,
                default    => "NONE",
                values     => [qw(NONE STUCK_AT_0 STUCK_AT_1 DELAY SEU STUCK_OPEN)],
                phases_opt => [qw(manual)]
            };
391
392
393
        }
    }

394
    return $testpatmap;
395
396
}

397
## @method public set_test_defaults (%$test_ref)
398
399
# @brief Overwrite existing fields (if defined) with defaults defined in FIJI.pm.
#
400
sub set_test_defaults {
Christian Fibich's avatar
Christian Fibich committed
401
402
    my ($self, $consts_ref) = @_;
    return _set_defaults($self->{'ext'}->{'TESTPATMAP'}, $consts_ref);
403
404
}

405
## @function public _set_defaults (%$map_ref, %$consts_ref)
406
407
# @brief Set defaults according to FIJI.pm.
sub _set_defaults {
408
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
409
410
411
    my ($map_ref, $consts_ref, $phase) = @_;
    foreach my $k (keys(%{$map_ref})) {
        if (exists($map_ref->{$k}->{'default'})) {
412
413

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

418
            # Also, do not overwrite existing values
Christian Fibich's avatar
Christian Fibich committed
419
            if (defined($consts_ref->{$k})) {
420
421
422
                next;
            }
            $consts_ref->{$k} = $map_ref->{$k}->{default};
Christian Fibich's avatar
Christian Fibich committed
423
            $logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $map_ref->{$k}->{'ini_name'}, $map_ref->{$k}->{default}));
424
425
426
        }
    }
}
427
428

sub validate_design_value {
Christian Fibich's avatar
Christian Fibich committed
429
430
    my ($k, $v_ref) = @_;
    return validate_value(TESTCONSTMAP, $k, $v_ref);
431
432
433
}

sub validate_test_value {
Christian Fibich's avatar
Christian Fibich committed
434
435
    my ($m, $k, $v_ref) = @_;
    return validate_value($m, $k, $v_ref);
436
437
}

438
## @function public validate_value (%$map_ref, $k, $$v_ref, $old, $log_func)
439
440
441
442
443
444
445
446
#   Do validation (and conversation from external->internal representation)
#
#   \param map_ref  reference to FIJI Settings mappings
#   \param k        key identifying the respective setting
#   \param v_ref    scalar reference to the proposed value (that may be modified)
#   \param old      (optional) previously valid value
#   \param log_func (optional) the (log4perl) log function to use
#                   (defaul is \&Log::Log4perl::Logger::trace)
447
sub validate_value {
448
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
449
    my ($map_ref, $k, $v_ref, $old, $log_func) = @_;
450
    $log_func = \&Log::Log4perl::Logger::trace if !defined($log_func);
Christian Fibich's avatar
Christian Fibich committed
451
    if (defined($map_ref->{$k}->{'type'})) {
452
453
        my $orig = ${$v_ref};

Christian Fibich's avatar
Christian Fibich committed
454
        # @FIXME: check if the constant is depending on another constant, that needs to be enabled.
455
456
457
458
        # my $dependency = @{$map_ref->{$k}->{'depends_on'}};
        # if (defined($dependency) && defined(@{$map_ref->{$dependency}->{'value'}}
        # }

Christian Fibich's avatar
Christian Fibich committed
459
460
461
        if ($map_ref->{$k}->{'type'} eq 'hexadecimal') {
            if ($orig !~ /^(0|(0[xX][[:xdigit:]]+))$/) {
                $log_func->($logger, "$k: $orig does not look like a natural hexadecimal number.");
462
463
464
465
466
                return 0;
            }
            ${$v_ref} = hex($orig);

            # Check for natural value range. Should never trigger due to the regex above.
Christian Fibich's avatar
Christian Fibich committed
467
468
            if (${$v_ref} < 0) {
                $log_func->($logger, "$k: $orig is negative.");
469
470
                return 0;
            }
Christian Fibich's avatar
Christian Fibich committed
471
        } elsif ($map_ref->{$k}->{'type'} eq 'natural'
472
            || $map_ref->{$k}->{'type'} eq 'min_duration'
Christian Fibich's avatar
Christian Fibich committed
473
            || $map_ref->{$k}->{'type'} eq 'max_duration')
474
475
        {
            # Match hexadecimal, binary, octal and decimal numbers (the latter also in scientific notation)
Christian Fibich's avatar
Christian Fibich committed
476
477
            if ($orig !~ /^(0|(0(x[0-9a-fA-F]+|[0-7]+))|(0b[01]+)|([1-9][0-9]*(e(-[0-9])?[0-9]+)?))$/) {
                $log_func->($logger, "$k: $orig does not look like a number.");
478
479
480
481
482
                return 0;
            }

            # convert non-decimal (hexadecimal, binary, octal) values to decimal
            ${$v_ref} = oct($orig) if $orig =~ /^0/;
Christian Fibich's avatar
Christian Fibich committed
483
484
            if (!looks_like_number(${$v_ref})) {
                $log_func->($logger, "$k: $orig does not look like a number.");
485
486
487
488
                return 0;
            }

            # Check for natural value range. Should never trigger due to the regex above.
Christian Fibich's avatar
Christian Fibich committed
489
490
            if (${$v_ref} < 0) {
                $log_func->($logger, "$k: $orig is negative.");
491
492
                return 0;
            }
Christian Fibich's avatar
Christian Fibich committed
493
        } elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
494
495

            # convert strings to binary if need be
Christian Fibich's avatar
Christian Fibich committed
496
497
            if (!defined($orig)) {
                $log_func->($logger, "$k: \"undef\" is not a boolean value.");
498
                return 0;
Christian Fibich's avatar
Christian Fibich committed
499
            } elsif (lc($orig) eq 'true') {
500
                $orig = 1;
Christian Fibich's avatar
Christian Fibich committed
501
            } elsif (lc($orig) eq 'false') {
502
503
                $orig = 0;
            }
Christian Fibich's avatar
Christian Fibich committed
504
505
            if (($orig ne '0') && ($orig ne '1')) {
                $log_func->($logger, "$k: \"$orig\" does not look like a boolean value.");
506
507
508
509
                return 0;
            }

            # ensure proper boolean value, i.e. 0 or 1
Christian Fibich's avatar
Christian Fibich committed
510
511
512
513
            ${$v_ref} = (!!$orig) ? 1 : 0;
        } elsif ($map_ref->{$k}->{'type'} eq 'prob') {
            if ($orig !~ /^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/) {
                $log_func->($logger, "$k: $orig does not look like a positive real number.");
514
515
                return 0;
            }
Christian Fibich's avatar
Christian Fibich committed
516
        }
517

Christian Fibich's avatar
Christian Fibich committed
518
        $logger->trace("Converted value of $k (\"$orig\") to \"${$v_ref}\".") if (defined($orig) && $orig ne ${$v_ref});
519
    }
Christian Fibich's avatar
Christian Fibich committed
520

Christian Fibich's avatar
Christian Fibich committed
521
    if (defined($map_ref->{$k}->{'values'})) {
522
        my $values_ref = $map_ref->{$k}->{'values'};
Christian Fibich's avatar
Christian Fibich committed
523
        if (ref($values_ref) eq 'ARRAY') {
524

525
            # Look for given value in allowed values
Christian Fibich's avatar
Christian Fibich committed
526
527
            if (scalar(grep { $_ eq ${$v_ref} } @{$values_ref}) == 0) {
                $log_func->($logger, "$k: ${$v_ref} is not allowed. Allowed values are: " . join(", ", @{$map_ref->{$k}->{'values'}}));
528
529
                return 0;
            }
Christian Fibich's avatar
Christian Fibich committed
530
531
532
        } elsif (ref($values_ref) eq 'CODE') {
            if (!$values_ref->(${$v_ref}, $old)) {
                $log_func->($logger, "$k: ${$v_ref} is not allowed.");
533
534
535
                return 0;
            }
        }
536
    }
537

538
    return 1;
539
540
}

541
# @function public _rename_import (%$map_ref, %$consts_ref)
542
543
544
545
546
547
548
549
550
# Rename and convert entries in consts_ref according to map_ref.
#
# This function takes a hash of FIJI Settings and converts its contents
# to the respective internal representation. This allows to use different
# names and value representations in the external file than within the
# implementation.
#
# \returns $consts_ref, or undef on errors
sub _rename_import {
551
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
552
553
    my ($map_ref, $consts_ref) = @_;
    if (ref($consts_ref) ne 'HASH') {
554
555
556
        $logger->error("Parameter is not a reference to a hash (containing design constants).");
        return undef;
    }
557

558
559
    # Iterating over respective hash from FIJI.pm and rename the entries
    # to match our internal naming scheme.
Christian Fibich's avatar
Christian Fibich committed
560
    foreach my $k (keys(%{$map_ref})) {
561
        my $ini_name = $map_ref->{$k}->{'ini_name'};
Christian Fibich's avatar
Christian Fibich committed
562
        if (exists($consts_ref->{$ini_name}) && $ini_name ne $k) {
563
            $consts_ref->{$k} = $consts_ref->{$ini_name};
Christian Fibich's avatar
Christian Fibich committed
564
            $logger->trace(sprintf("Renaming Design setting %s -> %s (=%s).", $ini_name, $k, defined($consts_ref->{$ini_name}) ? $consts_ref->{$ini_name} : "undef"),);
565
566
567
            delete $consts_ref->{$ini_name};
        }
    }
Christian Fibich's avatar
Christian Fibich committed
568
569
570
    foreach my $entry_key (keys(%{$consts_ref})) {
        if (!exists($map_ref->{$entry_key})) {
            $logger->debug("Deleting unknown setting %s = %s.", $entry_key, $consts_ref->{$entry_key});
571
572
573
574
575
576
            delete $consts_ref->{$entry_key};
        }
    }

    return $consts_ref;
}
577

578
## @function public _sanitize_test (%$test_ref, $phase)
579
580
581
582
# @brief Convert and sanity check FIJI Settings.
#
# \param test_ref a reference to a hash containing FIJI Settings for a
#                single TEST.
Christian Fibich's avatar
Christian Fibich committed
583
# \param phase the current design phase
584
585
586
#
# \returns A new hash with all constants required in the TEST settings
#          in sanitized form, or undef on errors.
587
sub _sanitize_test {
588
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
589
590
    my ($testpatmap, $test_ref, $phase) = @_;
    if (ref($test_ref) ne 'HASH') {
591
592
593
594
        my $msg = "Parameter is not a reference to a hash (containing TEST constants).";
        $logger->error($msg);
        return $msg;
    }
595

Christian Fibich's avatar
Christian Fibich committed
596
597
    $test_ref = _validate_hashmap($testpatmap, $test_ref, $phase);
    if (!ref($test_ref)) {
598
599
600
        $logger->error("Could not validate Design Constants.");
        return $test_ref;
    }
601

602
    return $test_ref;
603
604
605
}

sub _disabled_via_dependency ($$$) {
Christian Fibich's avatar
Christian Fibich committed
606
    my ($map_ref, $consts_ref, $k) = @_;
607
608
    my $dependency = $map_ref->{$k}->{'depends_on'};
    return defined($dependency) && !$consts_ref->{$dependency};
609
610
611
}

sub _validate_hashmap ($$;$) {
612
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
613
614
615
    my ($map_ref, $consts_ref, $phase) = @_;
    my @map_keys = keys(%{$map_ref});
    foreach my $entry_key (keys(%{$consts_ref})) {
616
617
        my $ini_name = $map_ref->{$entry_key}->{'ini_name'};

Christian Fibich's avatar
Christian Fibich committed
618
619
        if (!exists($map_ref->{$entry_key})) {
            $logger->debug("Deleting unknown setting %s = %s.", $entry_key, $consts_ref->{$entry_key});
620
621
622
623
            next;
        }

        @map_keys = grep { $_ ne $entry_key } @map_keys;    # mark constant key as done
Christian Fibich's avatar
Christian Fibich committed
624
625
626
627
        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'}));
        } elsif (!validate_value($map_ref, $entry_key, \$consts_ref->{$entry_key})) {
            my $msg = sprintf("%s = %s is invalid.", $entry_key, !defined($consts_ref->{$entry_key}) ? "<undef>" : $consts_ref->{$entry_key});
628
629
630
631
632
            $logger->error($msg);
            return $msg;
        }
    }

Christian Fibich's avatar
Christian Fibich committed
633
    if (!defined($phase)) {
634
635
636
637
638
639
640

        # 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.
        return $consts_ref;
    }

641
642
643
644
645
646
647
648
649
650
651
652
653
#     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 (
            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
           ) {
          my $msg = "$k is mandatory in phase $phase.";
          $logger->error($msg);
          return $msg;
        }
      }
654
655
656
    return $consts_ref;
}

657
## @function public _sanitize_design (%$consts_ref, $phase)
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# @brief Sanity check FIJI Design Settings.
#
# The function deals with sanity checks for the values
# themselves. It checks for the following conditions:
#
#   - NUM_TESTS: > 0
#   - REPEAT_OFFSET: 0 .. NUM_TESTS-1
#
# \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
#
# \returns The given hash with all constants required in the design
#          settings in sanitized form, or an error message.
sub _sanitize_design {
672
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
673
674
    my ($consts_ref, $phase) = @_;
    if (ref($consts_ref) ne 'HASH') {
675
676
677
678
679
680
        my $msg = "Parameter is not a reference to a hash (containing design constants).";
        $logger->error($msg);
        return $msg;
    }

    # check for sane values
Christian Fibich's avatar
Christian Fibich committed
681
682
    $consts_ref = _validate_hashmap(TESTCONSTMAP, $consts_ref, $phase);
    if (!ref($consts_ref)) {
683
684
685
686
687
        my $msg = "Could not validate Design Constants.";
        $logger->error($msg);
        return "$msg $consts_ref";
    }

Christian Fibich's avatar
Christian Fibich committed
688
    if (($consts_ref->{'NUM_TESTS'} <= 0)) {
689
690
691
692
693
        my $msg = "NUM_TESTS is <= 0.";
        $logger->error($msg);
        return $msg;
    }

Christian Fibich's avatar
Christian Fibich committed
694
    if (($consts_ref->{'REPEAT_OFFSET'} < 0) || ($consts_ref->{'REPEAT_OFFSET'} >= $consts_ref->{'NUM_TESTS'})) {
695
696
697
698
699
700
        my $msg = "NUM_TESTS is out of range [0 - NUM_TESTS[.";
        $logger->error($msg);
        return $msg;
    }

    return $consts_ref;
701
702
}

703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
sub export_gate_level {
    my $logger = get_logger("");
    my ($self, $gl_file_name, $global_settings_ref, $num_repetitions, $last_test) = @_;

    my $glfd;

    $num_repetitions = 1 if (!defined $num_repetitions);
    $last_test       = @{$self->{'tests'}} if (!defined $last_test);
    
    if (!defined open($glfd, ">", $gl_file_name)) {
        return "Could not open file $gl_file_name for writing: $!";
    }

    print $glfd FIJI::Tests::VHDL::export_as_vhd_fiji_architecture($self,$last_test,$num_repetitions,$global_settings_ref);

    unless (close($glfd)) {
         return "Could not close file $gl_file_name: $!";
    }
    $logger->info("Exporting as VHDL architecture for gate-level simulation successful.");
    return undef;
}

725
sub export_tb {
726
    my $logger = get_logger("");
727
    my ($self, $tb_file_name, $global_settings_ref, $num_repetitions, $last_test) = @_;
728

729
730
731
    $num_repetitions = 1 if (!defined $num_repetitions);
    $last_test       = @{$self->{'tests'}} if (!defined $last_test);
    
732
733
734
735
736
    my $export_sim_model_map = {
        ".vhd" => \&FIJI::Tests::VHDL::export_as_vhd_fiji_architecture,
        ".sv"  => \&FIJI::Tests::VHDL::export_as_vhd_fiji_architecture,
    };

737
738
739
740
    my $export_controller_map = {
        ".vhd" => \&FIJI::Tests::VHDL::export_controller,
        ".sv"   => \&FIJI::Tests::SystemVerilog::export_controller,
    };
741

742
743
744
745
    my $export_fiu_map = {
        ".vhd" => \&FIJI::Tests::VHDL::export_fiu,
        ".sv"   => \&FIJI::Tests::SystemVerilog::export_fiu,
    };
746

747
748
749
    for my $ext (".vhd", ".sv") {
        my $tbfd;
        my $fn = $tb_file_name.$ext;
750

751
752
753
        if (!defined open($tbfd, ">", $fn)) {
            return "Could not open file $fn for writing: $!";
        }
754

755
756
757
        unless (defined $export_controller_map->{$ext}) {
            return "Controller export: Unknown HDL filetype \"$ext\"";
        }
758

759
        print $tbfd $export_controller_map->{$ext}->($self,$last_test,$num_repetitions,$global_settings_ref);
760

761
762
763
        unless (defined $export_fiu_map->{$ext}) {
            return "FIU export: Unknown HDL filetype \"$ext\"";
        }
Christian Fibich's avatar
Christian Fibich committed
764

765
766
        for (my $fi = 0; $fi < $global_settings_ref->{'design'}->{'FIU_NUM'}; $fi++) {
            print $tbfd $export_fiu_map->{$ext}->($fi,$global_settings_ref);
767
768
        }

769
770
        unless (close($tbfd)) {
             return "Could not close file $fn: $!";
771
772
        }
    }
773
    $logger->info("Exporting as templates for RTL simulation successful.");
774
    return undef;
775
776
}

Christian Fibich's avatar
Christian Fibich committed
777
## @method export_as_sim_script ($sim_file_name, $last_test, $num_repetitions, %$global_settings_ref)
778
779
# @brief generate a sim script from the current test file depending on repetitions and the last executed test
#
Christian Fibich's avatar
Christian Fibich committed
780
# @TODO: validate generated sim script files in Questa
781
#       makes use of random_force functionality or implement a different way of exporting sim scripts
Christian Fibich's avatar
Christian Fibich committed
782
783
784
785
786
#
# @param sim_file_name         the file to write the simulator script to
# @param last_test             index of the last test to be included in the script
# @param num_repetitions       the number of repetitions to be included in the script
# @param global_settings_ref   a reference to FIJI::Settings
787
sub export_as_sim_script {
788
    my $logger = get_logger("");
Christian Fibich's avatar
Christian Fibich committed
789
    my ($self, $sim_file_name, $last_test, $num_repetitions, $global_settings_ref) = @_;
790
    my $script_text = "# Sim script generated " . localtime . "\n#source random_force.tcl\n";
Christian Fibich's avatar
Christian Fibich committed
791

Christian Fibich's avatar
Christian Fibich committed
792
    if (ref($global_settings_ref) ne "FIJI::Settings") {
Christian Fibich's avatar
Christian Fibich committed
793
794
795
796
        $logger->error("Given settings are not of type FIJI::Settings");
        return 0;
    }

Christian Fibich's avatar
Christian Fibich committed
797
    my $msg;
798
    my $time   = 0;
Christian Fibich's avatar
Christian Fibich committed
799
800
    my $indent = "    ";

Christian Fibich's avatar
Christian Fibich committed
801
    open(my $sfd, ">", $sim_file_name);
802

Christian Fibich's avatar
Christian Fibich committed
803
    if (!defined $sfd) {
Christian Fibich's avatar
Christian Fibich committed
804
805
806
807
        $msg = "Could not open file $sim_file_name for writing: $!";
        return $msg;
    }

Christian Fibich's avatar
Christian Fibich committed
808
809
    # @FIXME translate in actual Questasim tcl syntax
    if ($global_settings_ref->{'design'}->{'RESET_DUT_OUT_EN'} == 1) {
Christian Fibich's avatar
Christian Fibich committed
810
        $script_text .= <<"END_RST";
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
set testbench_name \$1;
set start    0;
set test     0;
set lfsrval  $global_settings_ref->{'design'}->{'LFSR_SEED'};

proc modbit signal {
     set curval [examine \$signal];

     # Always invert signal
     if {\$curval == "1"} {
        set retstring "0"
     } elseif {\$curval == "0"} {
        set retstring "1"
     } elseif {\$curval == "H"} {
        set retstring "L"
     } elseif {\$curval == "L"} {
        set retstring "H"
     }

    return \$retstring;
}

proc randbit mask {
    return expr {(\$lfsrval & \$mask) > 0};
}

when -label rst {\"\$testbench_name|$global_settings_ref->{'design'}->{'RESET_DUT_OUT_NAME'}\" == not $global_settings_ref->{'design'}->{'RESET_DUT_IN_ACTIVE'} &&
                 \"\$testbench_name|$global_settings_ref->{'design'}->{'CLOCK_NET'}\" == 1 && \"\$start == 0\"} {
    set start 1;
    nowhen rst;
}

when -label lfsr {\"\$testbench_name|$global_settings_ref->{'design'}->{'CLOCK_NET'}'event && 
                    \$testbench_name|$global_settings_ref->{'design'}->{'CLOCK_NET'}' = '1'\" &&
                  \"\$start == 1\"} {
    if ( expr{ \$lfsrval & (1 << ($global_settings_ref->{'design'}->{'LFSR_WIDTH'}-1))} != 0 ) {
        set \$lfsrval [expr {((\$lfsrval ^ $global_settings_ref->{'design'}->{'LFSR_POLY'}) << 1) | 1}];
    } else {
        set \$lfsrval [expr {(\$lfsrval << 1)}];
    }
}
END_RST
    } else {
Christian Fibich's avatar
Christian Fibich committed
854
        $script_text .= "set start 1";
Christian Fibich's avatar
Christian Fibich committed
855
856
    }

857
858
    my $absolute_test_index = 0;

Christian Fibich's avatar
Christian Fibich committed
859
    for (my $ri = 0 ; $ri <= $num_repetitions ; $ri++) {
Christian Fibich's avatar
Christian Fibich committed
860
        $script_text .= "#\n# Repetition $ri\n#\n";
Christian Fibich's avatar
Christian Fibich committed
861
862
863
        my $start = ($ri == 0) ? 0 : $self->{'design'}->{'REPEAT_OFFSET'};
        my $end = ($ri == $num_repetitions) ? $last_test : ($self->{'design'}->{'NUM_TESTS'} - 1);
        for (my $ti = $start ; $ti <= $end ; $ti++) {
864
865

            $script_text .= "\n#\n# Test $ri:$ti\n#\n";
Christian Fibich's avatar
Christian Fibich committed
866
            $script_text .= "when -label test_$absolute_test_index \"\$test = $absolute_test_index" . (($absolute_test_index == 0) ? " && \$start = 1" : "") . "\" {\n";
867
868

            if ($absolute_test_index > 0) {
Christian Fibich's avatar
Christian Fibich committed
869
870
871
872
873
874
                $script_text .= $indent . "eval {nowhen test_" .    ($absolute_test_index - 1) . "}\n";
                $script_text .= $indent . "eval {nowhen dutrst_" .  ($absolute_test_index - 1) . "}\n";
                $script_text .= $indent . "eval {nowhen trigger_" . ($absolute_test_index - 1) . "}\n";
                $script_text .= $indent . "eval {nowhen action_" .  ($absolute_test_index - 1) . "_1}\n";
                $script_text .= $indent . "eval {nowhen action_" .  ($absolute_test_index - 1) . "_2}\n";
                $script_text .= $indent . "eval {nowhen clk}\n";
875
876
            }

Christian Fibich's avatar
Christian Fibich committed
877
            my $test = @{$self->{'tests'}}[$ti];
Christian Fibich's avatar
Christian Fibich committed
878

879
            if ($test->{'RESET_DUT_AFTER_CONFIG'} == 1) {
Christian Fibich's avatar
Christian Fibich committed
880
                $script_text .= $indent . "force -freeze " . $global_settings_ref->{'design'}->{'RESET_DUT_IN_NAME'};
881
882
                $script_text .= " '" . $global_settings_ref->{'design'}->{'RESET_DUT_IN_ACTIVE'} . "'";
                $script_text .= " -cancel " . ($global_settings_ref->{'design'}->{'RESET_DUT_IN_DURATION'} * (10**12) / ($global_settings_ref->{'design'}->{'FREQUENCY'})) . " ps; \n";
Christian Fibich's avatar
Christian Fibich committed
883
                $script_text .= $indent . "when -label dutrst_$absolute_test_index \"\$now == " . ($global_settings_ref->{'design'}->{'RESET_DUT_IN_DURATION'} * (10**12) / ($global_settings_ref->{'design'}->{'FREQUENCY'})) . " ps\" {\n";
Christian Fibich's avatar
Christian Fibich committed
884
885
            }

886
            my ($tr, $act);
Christian Fibich's avatar
Christian Fibich committed
887
888
            if ($test->{'TRIGGER'} ne "NONE") {
                if ($test->{'TRIGGER'} eq "INT") {
889
                    $tr  = $global_settings_ref->{'design'}->{'TRIGGER_DUT_NAME'};
Christian Fibich's avatar
Christian Fibich committed
890
891
                    $act = $global_settings_ref->{'design'}->{'TRIGGER_DUT_ACTIVE'};
                } else {
892
                    $tr  = $global_settings_ref->{'design'}->{'TRIGGER_DUT_NAME'};
Christian Fibich's avatar
Christian Fibich committed
893
894
                    $act = $global_settings_ref->{'design'}->{'TRIGGER_EXT_ACTIVE'};
                }
Christian Fibich's avatar
Christian Fibich committed
895
                $script_text .= ($indent x 2) . "when -label trigger_$absolute_test_index {$tr = $act} {\n";
Christian Fibich's avatar
Christian Fibich committed
896
897
            }

898
899
            $time = 0;

Christian Fibich's avatar
Christian Fibich committed
900
            for (my $ci = 1 ; $ci <= $global_settings_ref->{'design'}->{'CFGS_PER_MSG'} ; $ci++) {
Christian Fibich's avatar
Christian Fibich committed
901
902
                $script_text .= ($indent) . "#\n" . ($indent) . "# Pattern $ri:$ti:$ci\n" . ($indent) . "#\n";
                $script_text .= ($indent) . "echo \"Fault $ri:$ti:$ci\"\n";
Christian Fibich's avatar
Christian Fibich committed
903
                $time += ($test->{"TIMER_VALUE_$ci"} / $global_settings_ref->{'design'}->{'FREQUENCY'}) * (10**12);
Christian Fibich's avatar
Christian Fibich committed
904
                my $action_text = "";
Christian Fibich's avatar
Christian Fibich committed
905
                for (my $fi = 0 ; $fi < $global_settings_ref->{'design'}->{'FIU_NUM'} ; $fi++) {
906

Christian Fibich's avatar
Christian Fibich committed
907
                    # export patterns to simulator commands
908
                    $action_text .= $indent x 3;
909
                    my $pattern = $test->{"FIU_${fi}_FAULT_${ci}"};
Christian Fibich's avatar
Christian Fibich committed
910
                    if ($pattern eq "STUCK_AT_0") {
911
                        $action_text .= "force -freeze \"\$testbench_name|" . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "\" '0'; \n";
Christian Fibich's avatar
Christian Fibich committed
912
                    } elsif ($pattern eq "STUCK_AT_1") {
913
                        $action_text .= "force -freeze  \"\$testbench_name|" . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "\" '1'; \n";
Christian Fibich's avatar
Christian Fibich committed
914
                    } elsif ($pattern eq "STUCK_OPEN") {
Christian Fibich's avatar
Christian Fibich committed
915
916
917
                        $action_text .= "when -label clk \"\$testbench_name|" . $global_settings_ref->{'design'}->{'CLOCK_NET'} . "'event && \$testbench_name|" . $global_settings_ref->{'design'}->{'CLOCK_NET'} . " = '1'\" {\n";
                        $action_text .= ($indent x 4) . "force -freeze \"\$testbench_name|" . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "\" [randbit " . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_LFSR_MASK'} . "]; \n";
                        $action_text .= ($indent x 3) . "};\n";
Christian Fibich's avatar
Christian Fibich committed
918
                    } elsif ($pattern eq "SEU") {
919
920
921
922
                        $action_text .= "force -freeze \"\$testbench_name|" . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "\" \n";
                        $action_text .= $indent x 3;
                        $action_text .= "${indent}${indent}[modbit " . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "] ";
                        $action_text .= " -cancel " . ((10**12) / ($global_settings_ref->{'design'}->{'FREQUENCY'})) . " ps; \n";
Christian Fibich's avatar
Christian Fibich committed
923
                    } elsif ($pattern eq "DELAY") {
Christian Fibich's avatar
Christian Fibich committed
924

Christian Fibich's avatar
Christian Fibich committed
925
                        #@FIXME think of something better than setting to 'X'
926
                        $action_text .= "force  \"\$testbench_name|" . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "\" 'X'; \n";
Christian Fibich's avatar
Christian Fibich committed
927
                    } else {
928
                        $action_text .= "noforce  \"\$testbench_name|" . @{$global_settings_ref->{'fius'}}[$fi]->{'FIU_NET_NAME'} . "\"; \n";
Christian Fibich's avatar
Christian Fibich committed
929
930
                    }
                }
Christian Fibich's avatar