~ruther/vhdl-i2c

ref: 57bc4031f549c4c98b9f726cf3ca7681299aa521 vhdl-i2c/tb/i2c/startstop_condition_generator_tb.vhd -rw-r--r-- 9.8 KiB
57bc4031 — Rutherther feat: store address, rw in address generator or detector 1 year, 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
73
74
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
132
133
134
135
136
137
138
139
140
141
142
143
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
library ieee;
use ieee.std_logic_1164.all;

library i2c;
library vunit_lib;
context vunit_lib.vunit_context;

entity startstop_condition_generator_tb is

  generic (
    runner_cfg : string);

end entity startstop_condition_generator_tb;

architecture tb of startstop_condition_generator_tb is
  signal clk : std_logic := '0';
  constant CLK_PERIOD : time := 10 ns;

  signal rst_n : std_logic := '0';

  signal sda : std_logic := 'H';
  signal slave_sda : std_logic := 'H';
  signal sda_enable : std_logic;

  signal scl : std_logic := 'H';
  signal not_scl : std_logic;

  signal scl_rising : std_logic := '0';
  signal scl_falling : std_logic := '0';
  signal scl_falling_delayed : std_logic := '0';

  signal gen_start, gen_stop : std_logic := '0';
  signal req_scl_rise, req_scl_fall : std_logic := '0';

  signal start_condition : std_logic := '0';
  signal stop_condition : std_logic := '0';

  signal done : std_logic := '0';

  constant DELAY : natural := 5;
  constant TIMEOUT : time := DELAY * CLK_PERIOD * 2;
  signal one : std_logic := '1';
  signal zero : std_logic := '0';
begin  -- architecture tb

  clk <= not clk after CLK_PERIOD/2;
  rst_n <= '1' after 2*CLK_PERIOD;

  sda <= 'H';
  sda <= '0' when sda_enable = '1' else 'Z';

  slave_sda <= '1' when sda = 'H' else sda;

  not_scl <= not scl;
  scl <= 'H';

  uut : entity i2c.startstop_condition_generator
    generic map (
      DELAY => DELAY)
    port map (
      clk_i                 => clk,
      rst_in                => rst_n,
      sda_i                 => slave_sda,
      sda_enable_o          => sda_enable,
      scl_rising_i          => scl_rising,
      scl_falling_i         => scl_falling,
      scl_falling_delayed_i => scl_falling_delayed,
      start_condition_i     => start_condition,
      stop_condition_i      => stop_condition,
      gen_start_i           => gen_start,
      gen_stop_i            => gen_stop,
      req_scl_fall_o        => req_scl_fall,
      req_scl_rise_o        => req_scl_rise,
      done_o                => done);

  main: process is
    procedure wait_delay(constant delay : in integer) is
    begin  -- procedure wait_delay
      for i in 0 to delay loop
        wait until falling_edge(clk);
      end loop;  -- i
      wait until falling_edge(clk);
    end procedure wait_delay;

    procedure req_clear is
    begin  -- procedure req_clear
      gen_start <= '0';
      gen_stop <= '0';
    end procedure req_clear;

    procedure req_start is
    begin  -- procedure req_start
      req_clear;
      gen_start <= '1';
    end procedure req_start;

    procedure req_stop is
    begin  -- procedure req_start
      req_clear;
      gen_stop <= '1';
    end procedure req_stop;

    procedure wait_start_condition(nowait: std_logic := '0') is
    begin  -- procedure wait_start_condition
      check_equal(start_condition, '0', "Got start condition already when supposed to wait for it.");
      wait until rising_edge(start_condition) or rising_edge(stop_condition) for TIMEOUT;
      check_equal(stop_condition, '0', "Got stop condition instead of start.");
      check_equal(start_condition, '1', "Waiting for start condition timed out.");
      wait until falling_edge(clk);
    end procedure wait_start_condition;

    procedure wait_stop_condition is
    begin  -- procedure wait_start_condition
      check_equal(stop_condition, '0', "Got stop condition already when supposed to wait for it.");
      wait until rising_edge(stop_condition) or rising_edge(start_condition) for TIMEOUT;
      check_equal(start_condition, '0', "Got start condition instead of stop.");
      check_equal(stop_condition, '1', "Waiting for stop condition timed out.");
      wait until falling_edge(clk);
    end procedure wait_stop_condition;

    procedure wait_done is
    begin  -- procedure wait_done
      wait until rising_edge(done) for TIMEOUT;
      check_equal(done, '1', "Expected done.");
      wait until falling_edge(clk);
    end procedure wait_done;
    
    procedure comply_scl_rise(constant time_out: time := TIMEOUT) is
    begin  -- procedure comply_scl_rise
      wait until req_scl_rise = '1' or req_scl_fall = '1' for time_out;
      check_equal(req_scl_rise, '1', "Should want rise");
      check_equal(req_scl_fall, '0', "Should want rise, not fall");
      scl <= 'Z';
      wait until falling_edge(clk);
    end procedure comply_scl_rise;

    procedure comply_scl_fall is
    begin  -- procedure comply_scl_rise
      wait until req_scl_fall = '1' or req_scl_rise = '1' for TIMEOUT;
      check_equal(req_scl_fall, '1', "Should want fall");
      check_equal(req_scl_rise, '0', "Should want fall, not rise");
      scl <= '0';
      wait until falling_edge(clk);
    end procedure comply_scl_fall;

    procedure check_no_reqs is
    begin  -- procedure check_no_reqs
      check_equal(sda_enable, '0', "Should not hold sda enable after everything done.");
      wait until req_scl_fall = '1' or req_scl_rise = '1' or start_condition = '1' or stop_condition = '1' for TIMEOUT;
      check_equal(req_scl_fall, '0', "SCL fall was requested even though there shouldn't be any more requests.");
      check_equal(req_scl_rise, '0', "SCL rise was requested even though there shouldn't be any more requests.");
      check_equal(start_condition, '0', "Start condition triggered even though there shouldn't be any more conditions.");
      check_equal(stop_condition, '0', "Stop condition triggered even though there shouldn't be any more conditions.");
      check_equal(sda_enable, '0', "Should not hold sda enable after everything done.");
      wait until falling_edge(clk);
    end procedure check_no_reqs;
  begin  -- process main
    wait until rst_n = '1';
    wait until falling_edge(clk);

    check_equal(scl, 'H', "begin SCL not high");

    test_runner_setup(runner, runner_cfg);

    while test_suite loop
      if run("start") then

        req_start;
        wait_start_condition;
        comply_scl_fall;
        wait_done;
        check_no_reqs;

      elsif run("start_from_wrong_sda") then

        sda <= '0';
        req_start;
        comply_scl_fall;
        sda <= 'H';-- cannot hold SDA from outside
        comply_scl_rise(2*TIMEOUT);
        wait_start_condition;
        comply_scl_fall;
        wait_done;
        req_clear;
        check_no_reqs;

      elsif run("repeated_start") then

        scl <= '0';
        wait until falling_edge(scl_falling_delayed);
        req_start;
        comply_scl_rise;
        wait_start_condition;
        comply_scl_fall;
        wait_done;
        req_clear;
        check_no_reqs;

      elsif run("stop") then
        scl <= '0';
        wait until falling_edge(scl_falling_delayed);
        req_stop;
        comply_scl_rise;
        wait_stop_condition;
        wait_done;
        req_clear;
        check_no_reqs;

      elsif run("stop_from_high_scl") then
        sda <= '0';
        req_stop;
        wait for TIMEOUT;
        -- is not holding sda low
        check_equal(sda_enable, '0');
        -- that means sda would be
        -- high if not held by the
        -- testbench
        sda <= 'Z';
        wait_done;
        check_no_reqs;
      elsif run("stop_from_high_scl_wrong_sda") then
        req_stop;
        comply_scl_fall;
        comply_scl_rise(2*TIMEOUT);
        wait_stop_condition;
        wait_done;
        req_clear;
        check_no_reqs;
      elsif run("start_start_stop") then

        req_start;
        wait_start_condition;
        comply_scl_fall;
        wait_done;

        req_clear;
        wait until falling_edge(clk);

        check_equal(scl, '0');

        req_start;
        comply_scl_rise;
        wait_start_condition;
        comply_scl_fall;
        wait_done;

        req_clear;
        wait until falling_edge(clk);

        check_equal(scl, '0');

        req_stop;
        comply_scl_rise;
        wait_stop_condition;
        wait_done;
        check_no_reqs;

        check_equal(scl, 'H');

      elsif run("start_stop_start") then
        req_start;
        wait_start_condition;
        comply_scl_fall;
        wait_done;

        req_clear;
        wait until falling_edge(clk);

        check_equal(scl, '0');

        req_stop;
        comply_scl_rise;
        wait_stop_condition;
        wait_done;

        req_clear;
        wait until falling_edge(clk);

        check_equal(scl, 'H');

        req_start;
        wait_start_condition;
        comply_scl_fall;
        wait_done;
        check_no_reqs;
      end if;
    end loop;

    test_runner_cleanup(runner);
  end process main;

  set_scl_rising: process is
  begin  -- process scl_rising
    wait until rising_edge(scl);
    scl_rising <= '1';
    wait until falling_edge(clk);
    wait until rising_edge(clk);
    scl_rising <= '0';
  end process set_scl_rising;

  set_scl_falling: process is
  begin  -- process scl_rising
    wait until falling_edge(scl);
    scl_falling <= '1';
    wait until rising_edge(clk);
    wait until falling_edge(clk);
    scl_falling <= '0';
  end process set_scl_falling;

  set_delayed_scl_falling: process is
  begin  -- process scl_rising
    wait until falling_edge(scl);
    wait until falling_edge(clk);
    scl_falling_delayed <= '1';
    wait until rising_edge(clk);
    wait until falling_edge(clk);
    scl_falling_delayed <= '0';
  end process set_delayed_scl_falling;

  set_start_condition: process is
  begin  -- process scl_rising
    wait until falling_edge(sda);
    if scl = 'H' then
        start_condition <= '1';
        wait until rising_edge(clk);
        wait until falling_edge(clk);
        start_condition <= '0';
    end if;
  end process set_start_condition;

  set_stop_condition: process is
  begin  -- process scl_rising
    wait until rising_edge(sda);
    if scl = 'H' then
        stop_condition <= '1';
        wait until rising_edge(clk);
        wait until falling_edge(clk);
        stop_condition <= '0';
    end if;
  end process set_stop_condition;

end architecture tb;
Do not follow this link