VHDL.pm 23.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
#-------------------------------------------------------------------------------
#  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
#
#-------------------------------------------------------------------------------
#  File:              VHDL.pm
#  Created on:        28.05.2015
Christian Fibich's avatar
Christian Fibich committed
13
14
#  $LastChangedBy$
#  $LastChangedDate$
15
16
17
18
19
20
21
#
#  Description:
#  Contains functions to generate VHDL package and wrapper files for FIJI
#  Contains enum values for marking Verilog-Perl netlist ports with userdata:
#
#-------------------------------------------------------------------------------

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

## @class FIJI::VHDL
Christian Fibich's avatar
Christian Fibich committed
26
27
28
29
30
# @brief Functions generating VHDL code
## @class FIJI::VHDL
# Contains functions to generate VHDL package and wrapper files for FIJI
# Contains enum values for marking Verilog-Perl netlist ports with userdata:

31
32
33
34
package FIJI::VHDL;

use strict;
use warnings;
35
use Data::Dumper;
36
use Log::Log4perl qw(get_logger);
37
use POSIX qw(ceil);
38
39
40
41
use FIJI::Settings;

#  FIJI_USERDATA_xxx is intended as key for the port->userdata{} hash
#  FIJI_USERDATA_PORTTYPE:  type of the port (see FIJI_PORTTYPE_xxx enum)
42
#  FIJI_USERDATA_PREV_PORTNAME:  original name of the port in case it was driving an instrumented net
43
44
#  FIJI_USERDATA_FIU_INDEX: FIU# this FIJI_PORTTYPE_MODIFIED or FIJI_PORTTYPE_ORIGINAL should be connected to
#  FIJI_USERDATA_FD_INDEX:  Fault Detection channel this FIJI_PORTTYPE_FAULT_DETECTION should be connected to
45
use enum qw(FIJI_USERDATA_PORTTYPE FIJI_USERDATA_PREV_PORTNAME FIJI_USERDATA_FIU_INDEX FIJI_USERDATA_FD_INDEX);
46
47
48
49
50
51
52
53
54
55
56
57

#  FIJI_PORTTYPE_xxx is intended to be used as value for port->userdata{FIJI::VHDL->FIJI_USERDATA_PORTTYPE} to determine the special port usage
#  FIJI_PORTTYPE_CLOCK: clock output to FIJI from DUT
#  FIJI_PORTTYPE_MODIFIED: modified net input to DUT
#  FIJI_PORTTYPE_ORIGINAL: original net output to FIJI
#  FIJI_PORTTYPE_FAULT_DETECTION: fault detection net output to FIJI
#  FIJI_PORTTYPE_TRIGGER_FROM_DUT: internal trigger from DUT to FIJI
#  FIJI_PORTTYPE_RESET_FROM_DUT:   internal reset from DUT to FIJI
#  FIJI_PORTTYPE_RESET_TO_DUT:     internal reset from FIJI to DUT
use enum qw(FIJI_PORTTYPE_CLOCK FIJI_PORTTYPE_MODIFIED FIJI_PORTTYPE_ORIGINAL FIJI_PORTTYPE_FAULT_DETECTION FIJI_PORTTYPE_TRIGGER_FROM_DUT FIJI_PORTTYPE_RESET_FROM_DUT FIJI_PORTTYPE_RESET_TO_DUT);

#  Default values hash for signal and instantiation names, and the trigger and reset values
Christian Fibich's avatar
Christian Fibich committed
58
use constant FIJI_DEFAULTS => {
59
60
61
62
63
    TX_OUT_NAME       => "s_fiji_tx_o",
    RX_IN_NAME        => "s_fiji_rx_i",
    DUT_INST_NAME     => "i_DUT",
    FIJI_INST_NAME    => "i_FIJI",
    FIJI_WRAPPER_NAME => "fiji_top",
64
65
66
67
68
69
70
71
72
73
74
75

    FIJI_WRAPPER_CLOCK_SIGNAL_NAME          => "s_fiji_clk",
    FIJI_WRAPPER_ORIGINAL_SIGNAL_NAME       => "s_fiji_original",
    FIJI_WRAPPER_MODIFIED_SIGNAL_NAME       => "s_fiji_modified",
    FIJI_WRAPPER_FAULT_SIGNAL_NAME          => "s_fiji_fault_detect",
    FIJI_WRAPPER_TRIGGER_DUT_SIGNAL_NAME    => "s_fiji_trigger_from_dut",
    FIJI_WRAPPER_TRIGGER_EXT_SIGNAL_NAME    => "s_fiji_trigger_ext",
    FIJI_WRAPPER_RESET_FROM_DUT_SIGNAL_NAME => "s_fiji_reset_from_dut",
    FIJI_WRAPPER_RESET_TO_DUT_SIGNAL_NAME   => "s_fiji_reset_to_dut",
    FIJI_WRAPPER_RESET_EXT_SIGNAL_NAME      => "s_fiji_reset_ext",
    RESET_EXT_IN_NAME                       => "s_fiji_reset",

76
77
    FIJI_TRIGGER_EXT_ASSIGNMENT => "not(c_trigger_ext_active)",
    FIJI_RESET_EXT_ASSIGNMENT   => "not(c_reset_ext_active)",
78

79
    FIJI_FAULT_INJECTION_GEN_LABEL    => "gen_fault_injection",
80
    FIJI_NO_FAULT_INJECTION_GEN_LABEL => "gen_no_fault_injection",
Christian Fibich's avatar
Christian Fibich committed
81
82

    FIJI_WRAPPER_ATTRIBUTES => " -- no attributes",
Christian Fibich's avatar
Christian Fibich committed
83
};
84
85
86
87
88
89
90
91

## @function generate_config_package ($fiji_settings_filename, $vhdl_filename)
# @brief Generate a public_config_pkg VHDL package file for FIJI
#
# \param fiji_settings_filename the cfg file generated by fiji_setup
# \param vhdl_filename the name of the VHDL file to be generated
#
# \returns 0 if VHDL file was generated successfully.
Christian Fibich's avatar
Christian Fibich committed
92
93
sub generate_config_package {
    my ($class, $fiji_settings_filename, $vhdl_filename) = @_;
94

95
    my $logger = get_logger("");
96
97
98
    my $name   = $0;
    $name =~ s/\.p[lm]//;
    $logger->debug("=== generate_config_package ===");
Christian Fibich's avatar
Christian Fibich committed
99
    $logger->debug(sprintf("%d argument(s)%s", scalar(@_), scalar(@_) > 0 ? ": @_" : ""));
100

101
102
103
104
105
    my ($fiji_settings, $warn) = FIJI::Settings->new('download', $fiji_settings_filename);
    if (!defined($fiji_settings)) {
        return $warn . " Aborting.\n";
    } elsif (defined($warn)) {
        $logger->warn($warn);
106
107
108
109
110
    }
    my $fiji_consts = $fiji_settings->{'design'};
    my $fius        = $fiji_settings->{'fius'};

    # LFSR initial value is given as a 0-padded hex number
Christian Fibich's avatar
Christian Fibich committed
111
    my $lfsr_fmt = sprintf("X\"%%0%dx\"", $fiji_consts->{'LFSR_WIDTH'} / 4);
112
    my $lfsr_width_multiple_of_4 = ceil($fiji_consts->{'LFSR_WIDTH'}/4)*4-1;
113
114
115
    my @fiu_configs = ();

    # generate the fiu_config record contents
Christian Fibich's avatar
Christian Fibich committed
116
117
    for (my $i = 0 ; $i < $fiji_consts->{'FIU_NUM'} ; $i++) {
        my $lfsr_mask = sprintf("$lfsr_fmt", @{$fius}[$i]->{'FIU_LFSR_MASK'});
118
        my $str = <<"END_FIU";
119
120
121
122
123
        $i => (
            fault_model => @{$fius}[$i]->{'FIU_MODEL'},
            lfsr_mask =>   $lfsr_mask
        )
END_FIU
124
125
        push @fiu_configs, $str;
    }
Christian Fibich's avatar
Christian Fibich committed
126
127
    my $lfsr_poly_string = sprintf($lfsr_fmt, $fiji_consts->{'LFSR_POLY'});
    my $lfsr_seed_string = sprintf($lfsr_fmt, $fiji_consts->{'LFSR_SEED'});
128

129
130
    # invert is given as 2-bit binary mask
    # need to do this because fault detection invert can be specified even if channel is not enabled
Christian Fibich's avatar
Christian Fibich committed
131
132
133
    my $invert1 = ($fiji_consts->{'FAULT_DETECT_1_EN'}) ? $fiji_consts->{'FAULT_DETECT_1_INVERT'} : 0;
    my $invert2 = ($fiji_consts->{'FAULT_DETECT_2_EN'}) ? $fiji_consts->{'FAULT_DETECT_2_INVERT'} : 0;
    my $fault_detect_string = sprintf("%01d%01d", $invert2, $invert1);
Christian Fibich's avatar
Christian Fibich committed
134

Christian Fibich's avatar
Christian Fibich committed
135
136
    my $fiu_configs_string = join("        ,\n", @fiu_configs);
    my $vhdl_id = sprintf("X\"%04x\"", $fiji_consts->{'ID'});
137
    my $gentime = localtime;
138

Christian Fibich's avatar
Christian Fibich committed
139
    my $reset_dut_in_duration = ($fiji_consts->{'RESET_DUT_IN_EN'} eq 1) ? $fiji_consts->{'RESET_DUT_IN_DURATION'} : 1;
140

Christian Fibich's avatar
Christian Fibich committed
141
    $logger->debug(sprintf("Generating VHDL text.\n"));
142

143
    my $vhdl = <<"END_VHDL";
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
--------------------------------------------------------------------------------
-- 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                                              --
--                                                                            --
--------------------------------------------------------------------------------
-- File:              $vhdl_filename
-- Generated:         $gentime
--
-- Description:
-- Public config package for $fiji_settings_filename
--------------------------------------------------------------------------------

library ieee;
    use ieee.std_logic_1164.all;

library work;
    use work.fault_selection_type_pkg.all;

package public_config_pkg is

  ------------------------------------------------------------------------------
  -- Design configuration
  ------------------------------------------------------------------------------
  -- The design's clock frequency
  constant c_frequency : positive := $fiji_consts->{'FREQUENCY'};
  -- The baud rate
  constant c_baudrate  : positive := $fiji_consts->{'BAUDRATE'};
  -- The invert mask for the fault detection signals
177
  constant c_fault_detect_invert_mask : std_logic_vector(1 downto 0) := "$fault_detect_string";
178
179
180
181
182
183
184
185

  ------------------------------------------------------------------------------
  -- LFSR configuration
  ------------------------------------------------------------------------------

  -- Width of the LFSR for random FIU enable & stuck-open
  constant c_lfsr_width : natural                                   := $fiji_consts->{'LFSR_WIDTH'};
  -- Polynomial for the LFSR
186
187
  constant c_lfsr_poly_mul4 : std_logic_vector($lfsr_width_multiple_of_4 downto 0) := $lfsr_poly_string;
  constant c_lfsr_poly  : std_logic_vector(c_lfsr_width-1 downto 0) := c_lfsr_poly_mul4(c_lfsr_width-1 downto 0);
188
  -- Initial value for the LFSR
189
190
  constant c_lfsr_seed_mul4 : std_logic_vector($lfsr_width_multiple_of_4 downto 0) := $lfsr_seed_string;
  constant c_lfsr_seed  : std_logic_vector(c_lfsr_width-1 downto 0) := c_lfsr_seed_mul4(c_lfsr_width-1 downto 0);
191
192
193
194
195
196
197
198
199
200
201

  ------------------------------------------------------------------------------
  -- Controller Configuration
  ------------------------------------------------------------------------------

  -- Width of the timers in bytes.
  constant c_timer_width  : natural := $fiji_consts->{'TIMER_WIDTH'};
  
  -- FIC -> DUT reset signal: active level
  constant c_reset_dut_in_active : std_logic := '$fiji_consts->{'RESET_DUT_IN_ACTIVE'}';
  -- reset duration
202
  constant c_reset_dut_in_duration : positive := $reset_dut_in_duration; 
203
204

  -- external reset signal: active level
205
  constant c_reset_ext_active : std_logic := '$fiji_consts->{'RESET_EXT_ACTIVE'}';
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

  -- DUT -> FIC reset signal: active level
  constant c_reset_dut_out_active : std_logic := '$fiji_consts->{'RESET_DUT_OUT_ACTIVE'}';


  -- active level of the external and internal triggers
  constant c_trigger_ext_active             : std_logic := '$fiji_consts->{'TRIGGER_EXT_ACTIVE'}';
  constant c_trigger_dut_active             : std_logic := '$fiji_consts->{'TRIGGER_DUT_ACTIVE'}';

  -- hardware id
  constant c_id    : std_logic_vector(15 downto 0) :=  $vhdl_id;

  ------------------------------------------------------------------------------
  -- FIU Configuration
  ------------------------------------------------------------------------------

  type t_single_fiu_record is record
    fault_model             : t_select_fault_models;  --Select dynamic or single fault model. See fault_injection_unit
    lfsr_mask               : std_logic_vector(c_lfsr_width-1 downto 0);  -- Select which LFSR bits to AND for Stuck-open fault
  end record t_single_fiu_record;

  type t_fiu_records is array (natural range <>) of t_single_fiu_record;

  constant c_fiu_config : t_fiu_records := (

$fiu_configs_string

  );

end package public_config_pkg;
END_VHDL

Christian Fibich's avatar
Christian Fibich committed
238
    $logger->debug(sprintf("Writing public config package to $vhdl_filename.\n"));
239

Christian Fibich's avatar
Christian Fibich committed
240
    if (open(my $fh, ">", $vhdl_filename)) {
241
242
243
244
245
        print $fh $vhdl;
        close $fh;
    } else {
        return "Could not open file '$vhdl_filename' for writing: $!";
    }
246

Christian Fibich's avatar
Christian Fibich committed
247
    $logger->info(sprintf("Successfully generated public config package for $fiji_settings_filename in $vhdl_filename.\n"));
248

249
    return undef;
250
251
}

252
253
254
255
256
257
258
259
# VHDL '93 supports escaped identifiers in a similar way to Verilog
# A VHDL escaped identifier is delimited by '\' characters, thus
# '\' characters in the identifier have to be escaped.
sub _vhdl_escape_identifier {
    my $identifier = shift;
    return ($identifier =~ /^\\/) ? '\\'.($identifier =~ s/\\/\\\\/gr).'\\' : $identifier;
}

Christian Fibich's avatar
Christian Fibich committed
260
## @function generate_wrapper_module (%$wrapper_config)
261
262
# @brief Generate a VHDL wrapper module instantiating FIJI logic and the DUT
#
Christian Fibich's avatar
Christian Fibich committed
263
# \param wrapper_config a configuration hash ref.
264
265
266
267
268
269
#   -> {'netlist'} the Verilog-Perl netlist file
#   -> {'dut_toplevel_module_name'} the toplevel module in the vqm netlist
#   -> {'fiji_settings_filename'}   the path to the fiji.cfg file
#   -> {'vhdl_filename'}            the VHDL file to be generated
#
# \returns 0 if VHDL file was generated successfully.
Christian Fibich's avatar
Christian Fibich committed
270
271
sub generate_wrapper_module {
    my ($class, $wrapper_config) = @_;
272

273
274
275
276
    my $vqm_netlist            = $wrapper_config->{'netlist'};
    my $dut_toplevel           = $wrapper_config->{'dut_toplevel_module_name'};
    my $fiji_settings_filename = $wrapper_config->{'fiji_settings_filename'};
    my $vhdl_filename          = $wrapper_config->{'vhdl_filename'};
277

278
    my $logger = get_logger("");
279
    my $name   = $0;
280
281
    $name =~ s/\.p[lm]//;
    $logger->debug("=== generate_wrapper_module ===");
Christian Fibich's avatar
Christian Fibich committed
282
    $logger->debug(sprintf("%d argument(s)%s", scalar(@_), scalar(@_) > 0 ? ": @_" : ""));
283

284
285
286
287
288
    my ($fiji_settings, $warn) = FIJI::Settings->new('download', $fiji_settings_filename);
    if (!defined($fiji_settings)) {
        return $warn . " Aborting.\n";
    } elsif (defined($warn)) {
        $logger->warn($warn);
289
290
    }
    my $fiji_consts = $fiji_settings->{'design'};
291
    my $fius        = $fiji_settings->{'fius'};
292
293
294

    $logger->debug("=== Assigning values ===");

Christian Fibich's avatar
Christian Fibich committed
295
296
    my $tx_name = (defined $fiji_consts->{'TX_OUT_NAME'}) ? $fiji_consts->{'TX_OUT_NAME'} : FIJI_DEFAULTS->{'TX_OUT_NAME'};
    my $rx_name = (defined $fiji_consts->{'RX_IN_NAME'})  ? $fiji_consts->{'RX_IN_NAME'}  : FIJI_DEFAULTS->{'RX_IN_NAME'};
297

Christian Fibich's avatar
Christian Fibich committed
298
299
300
    my $dut_inst_name  = (defined $fiji_consts->{'DUT_INST_NAME'})     ? $fiji_consts->{'DUT_INST_NAME'}     : FIJI_DEFAULTS->{'DUT_INST_NAME'};
    my $fiji_inst_name = (defined $fiji_consts->{'FIJI_INST_NAME'})    ? $fiji_consts->{'FIJI_INST_NAME'}    : FIJI_DEFAULTS->{'FIJI_INST_NAME'};
    my $wrapper_name   = (defined $fiji_consts->{'FIJI_WRAPPER_NAME'}) ? $fiji_consts->{'FIJI_WRAPPER_NAME'} : FIJI_DEFAULTS->{'FIJI_WRAPPER_NAME'};
301

Christian Fibich's avatar
Christian Fibich committed
302
    # assign some defaults
Christian Fibich's avatar
Christian Fibich committed
303
304
305
306
307
308
309
310
311
312
313
    my $fiji_clock_signal_name            = FIJI_DEFAULTS->{'FIJI_WRAPPER_CLOCK_SIGNAL_NAME'};
    my $fiji_original_signal_name         = FIJI_DEFAULTS->{'FIJI_WRAPPER_ORIGINAL_SIGNAL_NAME'};
    my $fiji_modified_signal_name         = FIJI_DEFAULTS->{'FIJI_WRAPPER_MODIFIED_SIGNAL_NAME'};
    my $fiji_fault_detection_signal_name  = FIJI_DEFAULTS->{'FIJI_WRAPPER_FAULT_SIGNAL_NAME'};
    my $fiji_trigger_from_dut_signal_name = FIJI_DEFAULTS->{'FIJI_WRAPPER_TRIGGER_DUT_SIGNAL_NAME'};
    my $fiji_trigger_ext_signal_name      = FIJI_DEFAULTS->{'FIJI_WRAPPER_TRIGGER_EXT_SIGNAL_NAME'};
    my $fiji_reset_from_dut_signal_name   = FIJI_DEFAULTS->{'FIJI_WRAPPER_RESET_FROM_DUT_SIGNAL_NAME'};
    my $fiji_reset_to_dut_signal_name     = FIJI_DEFAULTS->{'FIJI_WRAPPER_RESET_TO_DUT_SIGNAL_NAME'};
    my $fiji_reset_ext_signal_name        = FIJI_DEFAULTS->{'FIJI_WRAPPER_RESET_EXT_SIGNAL_NAME'};
    my $gen_fault_injection_label         = FIJI_DEFAULTS->{'FIJI_FAULT_INJECTION_GEN_LABEL'};
    my $gen_no_fault_injection_label      = FIJI_DEFAULTS->{'FIJI_NO_FAULT_INJECTION_GEN_LABEL'};
Christian Fibich's avatar
Christian Fibich committed
314
    my $attributes                        = FIJI_DEFAULTS->{'FIJI_WRAPPER_ATTRIBUTES'};
315

316
317
    my $trigger_ext_assignment = "not(c_trigger_ext_active)";
    my $reset_ext_assignment   = "not(c_reset_ext_active)";
318
319
320
321

    my $vqm_toplevel_module = $vqm_netlist->find_module($dut_toplevel);

    # check inputs
Christian Fibich's avatar
Christian Fibich committed
322
323
    return "Toplevel module $dut_toplevel not found.\n" if (!defined $vqm_toplevel_module);
    return "Module $dut_toplevel is not at the top level.\n" unless ($vqm_toplevel_module->is_top);
324
325
326
327
328
329
330
331

    # create lists for vhdl declarations and maps
    my @ext_ports          = ();
    my @dut_comp_ports     = ();
    my @dut_port_maps      = ();
    my @signal_assignments = ();

    # add FIJI external ports
332
    push @ext_ports, "--", "-- FIJI ports", "--";
333
334
    push @ext_ports, _vhdl_escape_identifier($tx_name) . ": out std_logic";
    push @ext_ports, _vhdl_escape_identifier($rx_name) . ": in  std_logic";
335

Christian Fibich's avatar
Christian Fibich committed
336
    if ($fiji_consts->{'RESET_EXT_EN'}) {
337
        my $re = _vhdl_escape_identifier((defined $fiji_consts->{'RESET_EXT_IN_NAME'}) ? $fiji_consts->{'RESET_EXT_IN_NAME'} : FIJI_DEFAULTS->{'RESET_EXT_IN_NAME'});
338
339
        push @ext_ports, "$re : in  std_logic";
        $reset_ext_assignment = $re;
340
    }
Christian Fibich's avatar
Christian Fibich committed
341
    if ($fiji_consts->{'TRIGGER_EXT_EN'}) {
342
        my $te = _vhdl_escape_identifier((defined $fiji_consts->{'TRIGGER_EXT_IN_NAME'}) ? $fiji_consts->{'TRIGGER_EXT_IN_NAME'} : FIJI_DEFAULTS->{'TRIGGER_EXT_IN_NAME'});
343
344
        push @ext_ports, "$te : in  std_logic";
        $trigger_ext_assignment = $te;
345
    }
346

347
    # add divider
348
    push @ext_ports, "--", "-- DUT ports", "--";
349

Christian Fibich's avatar
Christian Fibich committed
350
    # @FIXME: Verilog-Perl bug
351
352
    # using ->ports_sorted instead of ->ports_ordered here because verilog-perl only
    # updates ports_sorted when using ->new_port.
Christian Fibich's avatar
Christian Fibich committed
353
    foreach my $port ($vqm_toplevel_module->ports_sorted) {
354

355
356
        # retrieve userdata from netlist
        my $fiji_porttype = $port->userdata(FIJI_USERDATA_PORTTYPE);
357
358
        my $fiu_idx       = $port->userdata(FIJI_USERDATA_FIU_INDEX);
        my $fd_idx        = $port->userdata(FIJI_USERDATA_FD_INDEX);
359
360

        # add to ports of vhdl component definition
361
362
        
        push @dut_comp_ports, ((_vhdl_escape_identifier($port->name)) . " : " . ($port->direction) . " " . (port2vhdtype($port)));
363

Christian Fibich's avatar
Christian Fibich committed
364
        # check if port has assigned a special FIJI function
Christian Fibich's avatar
Christian Fibich committed
365
366
        if (defined $fiji_porttype) {
            if ($fiji_porttype == FIJI_PORTTYPE_CLOCK) {
367

368
                # clock from DUT to FIJI
369
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_clock_signal_name");
Christian Fibich's avatar
Christian Fibich committed
370
371
            } elsif ($fiji_porttype == FIJI_PORTTYPE_ORIGINAL) {
                return "Port " . ($port->name) . " has no fiu_idx assignment" unless (defined $fiu_idx);
372
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_original_signal_name(" . $fiu_idx . ")");
Christian Fibich's avatar
Christian Fibich committed
373
374
            } elsif ($fiji_porttype == FIJI_PORTTYPE_MODIFIED) {
                return "Port " . ($port->name) . " has no fiu_idx assignment" unless (defined $fiu_idx);
375
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_modified_signal_name(" . $fiu_idx . ")");
Christian Fibich's avatar
Christian Fibich committed
376
377
            } elsif ($fiji_porttype == FIJI_PORTTYPE_FAULT_DETECTION) {
                return "Port " . ($port->name) . " has no fd_idx assignment" unless (defined $fd_idx);
378
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_fault_detection_signal_name(" . $fd_idx . ")");
Christian Fibich's avatar
Christian Fibich committed
379
            } elsif ($fiji_porttype == FIJI_PORTTYPE_TRIGGER_FROM_DUT) {
380
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_trigger_from_dut_signal_name");
Christian Fibich's avatar
Christian Fibich committed
381
            } elsif ($fiji_porttype == FIJI_PORTTYPE_RESET_FROM_DUT) {
382
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_reset_from_dut_signal_name");
Christian Fibich's avatar
Christian Fibich committed
383
            } elsif ($fiji_porttype == FIJI_PORTTYPE_RESET_TO_DUT) {
384
                push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $fiji_reset_to_dut_signal_name");
385
386
387
388
            } else {
                $logger->error("Unknown fiji_porttype assignment: $fiji_porttype");
            }
        } else {
389

390
            my $extportname = _vhdl_escape_identifier((defined($port->userdata(FIJI_USERDATA_PREV_PORTNAME))) ? $port->userdata(FIJI_USERDATA_PREV_PORTNAME) : $port->name);
391
            # add to externally connected DUT ports
392
            push @ext_ports, ("$extportname : " . ($port->direction) . " " . (port2vhdtype($port)));
393
            push @dut_port_maps, (_vhdl_escape_identifier($port->name) . " => $extportname");
394
395
        }
    }
396

397
    # generate VHDL text for declaration blocks
Christian Fibich's avatar
Christian Fibich committed
398
399
400
    my $ext_ports_vhdl      = join(";\n        ",     @ext_ports);
    my $dut_comp_ports_vhdl = join(";\n            ", @dut_comp_ports);
    my $dut_port_maps_vhdl  = join(",\n            ", @dut_port_maps);
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443

    my $gentime = localtime;

    # generate VHDL wrapper text
    my $vhdl = <<"END_VHDL";
---------------------------------------------------------------------------------
--  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
--
---------------------------------------------------------------------------------
--
-- FIJI Wrapper generated at $gentime
-- Options:
--     toplevel  = "$dut_toplevel"
--     inst_name = "$dut_inst_name"
--     fiji_name = "$fiji_inst_name"
--     wrapper   = "$wrapper_name"
--
---------------------------------------------------------------------------------

library ieee;
    use ieee.std_logic_1164.all;
library work;
    use work.private_config_pkg.all;
    use work.public_config_pkg.all;
    use work.fault_injection_top_pkg.all;

entity $wrapper_name is
    generic (
        g_implement_fault_injection : boolean := true
    );
    port (
        $ext_ports_vhdl
    );
end entity $wrapper_name;

architecture wrap of $wrapper_name is
    
Christian Fibich's avatar
Christian Fibich committed
444
    $attributes
445

446
447
448
449
450
451
452
453
454
    component $dut_toplevel is
        port (
            $dut_comp_ports_vhdl
        );
    end component $dut_toplevel;

    signal $fiji_trigger_ext_signal_name        : std_logic;
    signal $fiji_reset_ext_signal_name          : std_logic;
    signal $fiji_clock_signal_name                : std_logic;
455
    signal $fiji_reset_from_dut_signal_name     : std_logic := not(c_reset_dut_out_active);
456
457
458
459
460
461
462
463
464
465
466
467
468
    signal $fiji_reset_to_dut_signal_name       : std_logic;
    signal $fiji_trigger_from_dut_signal_name   : std_logic := not(c_trigger_dut_active);
    signal $fiji_fault_detection_signal_name       : std_logic_vector(c_num_fault_detect_nets-1 downto 0) := (others => '0');
    signal $fiji_original_signal_name           : std_logic_vector(c_fiu_config'length-1 downto 0);
    signal $fiji_modified_signal_name           : std_logic_vector(c_fiu_config'length-1 downto 0);
    
begin

    $dut_inst_name : $dut_toplevel
        port map(
            $dut_port_maps_vhdl
        );

469
    $gen_fault_injection_label : if g_implement_fault_injection = true generate
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489

        $fiji_trigger_ext_signal_name <= $trigger_ext_assignment;
        $fiji_reset_ext_signal_name   <= $reset_ext_assignment;

        $fiji_inst_name : fault_injection_top
            port map (
                s_fiji_clk_i           => $fiji_clock_signal_name,
                s_fiji_reset_ext_i     => $fiji_reset_ext_signal_name,
                s_fiji_reset_dut_out_i => $fiji_reset_from_dut_signal_name,
                s_fiji_reset_dut_in_o  => $fiji_reset_to_dut_signal_name,
                s_fiji_rx_i            => $rx_name,
                s_fiji_tx_o            => $tx_name,
                s_fiji_trigger_ext_i   => $fiji_trigger_ext_signal_name,
                s_fiji_trigger_dut_i   => $fiji_trigger_from_dut_signal_name,
                s_fiji_fault_detect_i  => $fiji_fault_detection_signal_name,
                s_fiji_original_i      => $fiji_original_signal_name,
                s_fiji_modified_o      => $fiji_modified_signal_name
            );
    end generate;

490
    $gen_no_fault_injection_label : if g_implement_fault_injection = false generate
491
492
493
494
495
496
        $fiji_modified_signal_name <= $fiji_original_signal_name;
    end generate;

end wrap;
END_VHDL

Christian Fibich's avatar
Christian Fibich committed
497
    $logger->debug(sprintf("Writing VHDL wrapper to $vhdl_filename.\n"));
498

Christian Fibich's avatar
Christian Fibich committed
499
    if (open(my $fh, ">", $vhdl_filename)) {
500
501
502
503
504
        print $fh $vhdl;
        close $fh;
    } else {
        return "Could not open file '$vhdl_filename' $!";
    }
505

Christian Fibich's avatar
Christian Fibich committed
506
    $logger->info(sprintf("Successfully generated VHDL wrapper for $fiji_settings_filename in $vhdl_filename.\n"));
507

508
    return undef;
509
510
511

}

Christian Fibich's avatar
Christian Fibich committed
512
513
## @function public port2vhdtype ()
# @brief generates a VHDL type declaration for a given port/its net
514
515
516
517
sub port2vhdtype {
    my $port = shift(@_);
    my $type;

Christian Fibich's avatar
Christian Fibich committed
518
    if (!defined $port->net->msb) {
519
        $type = "std_logic";
Christian Fibich's avatar
Christian Fibich committed
520
521
    } elsif ($port->net->msb > $port->net->lsb) {
        $type = sprintf("std_logic_vector(%d downto %d)", $port->net->msb, $port->net->lsb);
522
    } else {
Christian Fibich's avatar
Christian Fibich committed
523
        $type = sprintf("std_logic_vector(%d to %d)", $port->net->msb, $port->net->lsb);
524
525
526
527
528
    }

    return $type;
}

529
1;