fault_injection_top_tb.vhd 10.7 KB
Newer Older
1
--------------------------------------------------------------------------------
2
3
4
-- Fault InJection Instrumenter (FIJI)
-- https://embsys.technikum-wien.at/projects/vecs/fiji
--
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
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- Copyright (C) 2017 Christian Fibich <fibich@technikum-wien.at>
-- Copyright (C) 2017 Stefan Tauner <tauner@technikum-wien.at>
--
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 0.51 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-0.51. Unless required by applicable
-- law or agreed to in writing, software, hardware and materials
-- distributed under this License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or
-- implied. See the License for the specific language governing
-- permissions and limitations under the License.
--
-- See the LICENSE file for more details.
--
-- Description:
25
--  Fault injection top-level testbench file
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.uniform;
use ieee.math_real.round;

library work;
use work.fault_injection_controller_pkg.all;
use work.fault_injection_uart_pkg.all;
use work.fault_injection_unit_pkg.all;
use work.fault_injection_top_pkg.all;

use work.public_config_pkg.all;
use work.private_config_pkg.all;


library std;
use std.textio.all;

-------------------------------------------------------------------------------

entity fault_injection_top_tb is
  generic (
    g_data_file_name : string           -- test vectors
    );
end entity fault_injection_top_tb;

-------------------------------------------------------------------------------

architecture sim of fault_injection_top_tb is

  -- serial MARK level  (Stop Bit)
  constant c_rs232_mark  : std_logic := '1';
  -- serial SPACE level (Start Bit)
  constant c_rs232_space : std_logic := '0';


  constant c_half_clock_period : time := (1.0 / real(c_frequency)/2.0) * (1 sec);

  signal s_fiji_clk_i           : std_logic := '0';
  signal s_fiji_reset_ext_i     : std_logic;
  signal s_fiji_reset_dut_out_i : std_logic;
  signal s_fiji_reset_dut_in_o  : std_logic;
  signal s_fiji_rx_i            : std_logic;
  signal s_fiji_tx_o            : std_logic;
73
74
  signal s_fiji_trig_ext_i   : std_logic;
  signal s_fiji_trig_dut_i   : std_logic;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  signal s_fiji_fault_detect_i  : std_logic_vector(c_num_fault_detect_nets-1 downto 0);
  signal s_fiji_original_i      : std_logic_vector(c_fiu_config'length -1 downto 0);
  signal s_fiji_modified_o      : std_logic_vector(c_fiu_config'length -1 downto 0);

  procedure wait_clock_cycles (
    signal clk     : in std_logic;
    constant LEVEL : in std_logic;
    constant N     : in positive) is
  begin
    l_wait_clock_cycles : for i in 1 to N loop
      wait until clk = LEVEL;
    end loop;
  end procedure wait_clock_cycles;

  procedure serial_byte(
    constant C_RS232_MARK  : in  std_logic;
    constant C_RS232_SPACE : in  std_logic;
    constant C_BAUD_RATE   : in  natural;
    constant C_BAUD_ERROR  : in  natural;
    variable data          : in  string(10 downto 1);
    signal uart_rx         : out std_logic) is
  begin
    l_serial_byte : for i in 1 to 10 loop
      case data(i) is
        when 'M' =>
          uart_rx <= C_RS232_MARK;
        when 'S' =>
          uart_rx <= C_RS232_SPACE;
        when '1' =>
          uart_rx <= C_RS232_MARK;
        when '0' =>
          uart_rx <= C_RS232_SPACE;
        when 'X' =>
          uart_rx <= C_RS232_SPACE;
          wait for 200 ms / (C_BAUD_RATE - C_BAUD_ERROR);
          uart_rx <= C_RS232_MARK;
          wait for 800 ms / (C_BAUD_RATE - C_BAUD_ERROR);
          next;
        when others =>
          uart_rx <= not(C_RS232_SPACE);
      end case;
      wait for 1000 ms / (C_BAUD_RATE - C_BAUD_ERROR);
    end loop;
    uart_rx <= not(C_RS232_SPACE);
  end procedure;

begin  -- architecture sim

  DUT : fault_injection_top
    port map (
      s_fiji_clk_i           => s_fiji_clk_i,
      s_fiji_reset_ext_i     => s_fiji_reset_ext_i,
      s_fiji_reset_dut_out_i => s_fiji_reset_dut_out_i,
      s_fiji_reset_dut_in_o  => s_fiji_reset_dut_in_o,
      s_fiji_rx_i            => s_fiji_rx_i,
      s_fiji_tx_o            => s_fiji_tx_o,
      s_fiji_fault_detect_i  => s_fiji_fault_detect_i,
132
133
      s_fiji_trig_ext_i   => s_fiji_trig_ext_i,
      s_fiji_trig_dut_i   => s_fiji_trig_dut_i,
134
135
136
137
138
139
140
141
142
143
      s_fiji_original_i      => s_fiji_original_i,
      s_fiji_modified_o      => s_fiji_modified_o);

  p_report_clock : process
  begin
    report "Half clock period is "&time'image(c_half_clock_period)&".";
    wait;
  end process;

  -- clock generation
144
  s_fiji_clk_i <= not s_fiji_clk_i after c_half_clock_period;
145
146
147
148


  p_fault_detect : process
    variable rand         : real;
149
    variable seed1, seed2 : integer;
150
151
152
153
154
155
  begin
    seed1 := 42;
    seed2 := 24;
    while true loop
      uniform(seed1, seed2, rand);
      s_fiji_fault_detect_i <= std_logic_vector(to_unsigned(integer(round(rand*3.0)), 2));
156
      wait for 1 us;
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
      wait until s_fiji_clk_i = '1';
    end loop;
  end process p_fault_detect;


  p_reset : process
  begin
    s_fiji_reset_ext_i     <= c_reset_ext_active;
    s_fiji_reset_dut_out_i <= not c_reset_dut_out_active;
    wait for c_half_clock_period;
    s_fiji_reset_dut_out_i <= c_reset_dut_out_active;
    wait for 0.5*c_half_clock_period;
    s_fiji_reset_dut_out_i <= not c_reset_dut_out_active;
    wait for 0.5*c_half_clock_period;
    s_fiji_reset_ext_i     <= not c_reset_ext_active;
    wait;
  end process;


176
  p_dut : process                       -- simulating the DUT's signals
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  begin
    -- insert signal assignments here
    s_fiji_original_i <= (others => '0');
    wait_clock_cycles(s_fiji_clk_i, '1', 25000);
    s_fiji_original_i <= (others => '1');
    wait_clock_cycles(s_fiji_clk_i, '1', 25000);
  end process p_dut;

  -- waveform generation
  p_transmit_data : process
    file f_data_in    : text open read_mode is g_data_file_name;
    variable L        : line;
    variable cmd      : character;
    variable data     : string(10 downto 1);
    variable duration : time;
    variable int      : integer;
    variable good     : boolean;
  begin
    -- insert signal assignments here
    s_fiji_rx_i          <= not (c_rs232_space);
197
198
    s_fiji_trig_ext_i <= c_trigger_ext_active;
    s_fiji_trig_dut_i <= c_trigger_dut_active;
199
200
201
202
203
204
205
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
238
239
240
241
242
243
244
245
246
    wait for 10000 ms / c_baudrate;
    l_read_file : while not endfile(f_data_in) loop
      readline(f_data_in, L);
      read(L, cmd, GOOD => good);

      if not good then
        next;
      end if;

      case cmd is
        -- ">": Transmit data via serial 
        when '>' =>
          read(L, data, GOOD => good);
        if not good then
          next;
        end if;

        serial_byte(c_rs232_mark, c_rs232_space, c_baudrate, 0, data, s_fiji_rx_i);
        -- pause 10 bit times
        wait for 1000 ms / c_baudrate;
        -- "W": Wait for a duration of type <time> e.g. 1 ms
        when 'W' =>
        read(L, duration, good);
        if not good then
          report "Invalid time 'W' command";
        else
          wait for duration;
        end if;
        -- "N": wait for a number of bit times
        when 'N' =>
        read(L, int, good);
        if not good then
          report "Invalid #bits after 'N' command";
        else
          wait for int*(1000 ms / c_baudrate);
        end if;
        -- "C": wait for a number of clock cycles
        when 'C' =>
        read(L, int, good);
        if not good then
          report "Invalid #cycles after 'C' command";
        else
          l_wait_clock : for j in 1 to int loop
            wait until s_fiji_clk_i = '1';
          end loop;
        end if;
        -- "T": generate trigger signal lasting a number of cycles
        when 'T' =>
247
        s_fiji_trig_ext_i <= not(c_trigger_ext_active);
248
249
250
251
252
253
254
255
        read(L, int, good);
        if not good then
          int := 1;
          report "Invalid #cycles after 'T' command";
        end if;
        l_wait_ext_trigger : for j in 1 to int loop
          wait until s_fiji_clk_i = '1';
        end loop;
256
        s_fiji_trig_ext_i <= c_trigger_ext_active;
257
258
        wait until s_fiji_clk_i = '1';
        when 'I' =>
259
        s_fiji_trig_dut_i <= not(c_trigger_dut_active);
260
261
262
263
264
265
266
267
        read(L, int, good);
        if not good then
          int := 1;
          report "Invalid #cycles after 'I' command";
        end if;
        l_wait_int_trigger : for j in 1 to int loop
          wait until s_fiji_clk_i = '1';
        end loop;
268
        s_fiji_trig_dut_i <= c_trigger_dut_active;
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
        wait until s_fiji_clk_i = '1';
        when others =>
        null;
      end case;
    end loop;
    wait;
  end process p_transmit_data;

  p_receive_return_message : process
    variable v_rx       : std_logic_vector(7 downto 0);
    variable v_msg_type : string(1 to 10);
  begin
    v_rx := (others => '0');
    wait until s_fiji_tx_o = c_rs232_space;
    wait for 500 ms / c_baudrate;
    assert s_fiji_tx_o = c_rs232_space report "[TB:p_receive_return_message] Start Bit Error" severity failure;
    l_wait_bit : for i in 0 to 7 loop
      wait for 1000 ms / c_baudrate;
      if s_fiji_tx_o = c_rs232_mark then
        v_rx(i) := '1';
      end if;
    end loop;
    wait for 1000 ms / c_baudrate;
    assert s_fiji_tx_o = c_rs232_mark report "[TB:p_receive_return_message] Stop Bit Error" severity failure;
    assert v_rx(7) = (v_rx(6) xor v_rx(5) xor v_rx(4) xor v_rx(3) xor
                      v_rx(2) xor v_rx(1) xor v_rx(0)) report "[TB:p_receive_return_message] Return parity error" severity failure;

    case v_rx(c_msg_bit_type1 downto c_msg_bit_type0) is
      when c_msg_type_conf_done =>
        v_msg_type := "CONF_DONE ";
      when c_msg_type_underrun =>
        v_msg_type := "UNDERRUN  ";
      when c_msg_type_ready =>
        v_msg_type := "READY     ";
      when others =>
        report "[TB:Message_Proc] Illegal message type received" severity failure;
        v_msg_type := "**ILLEGAL*";
    end case;
    report "[TB:p_receive_return_message] "&v_msg_type&" message received " & lf &
      "              FAULT DETECT 1 : "&std_logic'image(v_rx(c_msg_bit_fault1))& lf &
      "              FAULT DETECT 0 : "&std_logic'image(v_rx(c_msg_bit_fault0))& lf &
      "                  UART ERROR : "&std_logic'image(v_rx(c_msg_bit_uart))& lf &
      "                  ID   ERROR : "&std_logic'image(v_rx(c_msg_bit_id))& lf &
      "                  CRC  ERROR : "&std_logic'image(v_rx(c_msg_bit_crc));


  end process p_receive_return_message;


end architecture sim;