source: rtems/testsuites/sptests/spcache01/init.c @ c4b8b147

5
Last change on this file since c4b8b147 was c4b8b147, checked in by Sebastian Huber <sebastian.huber@…>, on 11/03/17 at 07:35:38

tests: Use simple console driver

Update #3170.
Update #3199.

  • Property mode set to 100644
File size: 11.6 KB
Line 
1/*
2 * Copyright (c) 2014, 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <inttypes.h>
20#include <setjmp.h>
21#include <stdio.h>
22#include <stdlib.h>
23
24#include <rtems.h>
25#include <rtems/counter.h>
26#include <rtems/score/sysstate.h>
27
28#include "tmacros.h"
29
30const char rtems_test_name[] = "SPCACHE 1";
31
32#ifdef __or1k__
33  #define I() __asm__ volatile ("l.nop")
34#else
35  #define I() __asm__ volatile ("nop")
36#endif
37
38#define I8() I(); I(); I(); I(); I(); I(); I(); I()
39
40#define I64() I8(); I8(); I8(); I8(); I8(); I8(); I8(); I8()
41
42#define I512() I64(); I64(); I64(); I64(); I64(); I64(); I64(); I64()
43
44CPU_STRUCTURE_ALIGNMENT static int data[1024];
45
46static bool do_longjmp;
47
48static jmp_buf instruction_invalidate_return_context;
49
50static void test_data_flush_and_invalidate(void)
51{
52  if (rtems_cache_get_data_line_size() > 0) {
53    RTEMS_INTERRUPT_LOCK_DECLARE(, lock)
54    rtems_interrupt_lock_context lock_context;
55    volatile int *vdata = &data[0];
56    int n = 32;
57    int i;
58    size_t data_size = n * sizeof(data[0]);
59    bool write_through;
60
61    printf("data cache flush and invalidate test\n");
62
63    rtems_interrupt_lock_initialize(&lock, "test");
64    rtems_interrupt_lock_acquire(&lock, &lock_context);
65
66    for (i = 0; i < n; ++i) {
67      vdata[i] = i;
68    }
69
70    rtems_cache_flush_multiple_data_lines(&data[0], data_size);
71
72    for (i = 0; i < n; ++i) {
73      rtems_test_assert(vdata[i] == i);
74    }
75
76    for (i = 0; i < n; ++i) {
77      vdata[i] = ~i;
78    }
79
80    rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);
81
82    write_through = vdata[0] == ~0;
83    if (write_through) {
84      for (i = 0; i < n; ++i) {
85        rtems_test_assert(vdata[i] == ~i);
86      }
87    } else {
88      for (i = 0; i < n; ++i) {
89        rtems_test_assert(vdata[i] == i);
90      }
91    }
92
93    for (i = 0; i < n; ++i) {
94      vdata[i] = ~i;
95    }
96
97    rtems_cache_flush_multiple_data_lines(&data[0], data_size);
98    rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);
99
100    for (i = 0; i < n; ++i) {
101      rtems_test_assert(vdata[i] == ~i);
102    }
103
104    rtems_interrupt_lock_release(&lock, &lock_context);
105    rtems_interrupt_lock_destroy(&lock);
106
107    printf(
108      "data cache operations by line passed the test (%s cache detected)\n",
109      write_through ? "write-through" : "copy-back"
110    );
111  } else {
112    printf(
113      "skip data cache flush and invalidate test"
114        " due to cache line size of zero\n"
115    );
116  }
117
118  /* Make sure these are nops */
119  rtems_cache_flush_multiple_data_lines(NULL, 0);
120  rtems_cache_invalidate_multiple_data_lines(NULL, 0);
121}
122
123static uint64_t do_some_work(void)
124{
125  rtems_counter_ticks a;
126  rtems_counter_ticks b;
127  rtems_counter_ticks d;
128
129  /* This gives 1024 nop instructions */
130  a = rtems_counter_read();
131  I512();
132  I512();
133  b = rtems_counter_read();
134
135  d = rtems_counter_difference(b, a);
136
137  return rtems_counter_ticks_to_nanoseconds(d);
138}
139
140static uint64_t load(void)
141{
142  rtems_counter_ticks a;
143  rtems_counter_ticks b;
144  rtems_counter_ticks d;
145  size_t i;
146  volatile int *vdata = &data[0];
147
148  a = rtems_counter_read();
149  for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
150    vdata[i];
151  }
152  b = rtems_counter_read();
153
154  d = rtems_counter_difference(b, a);
155
156  return rtems_counter_ticks_to_nanoseconds(d);
157}
158
159static uint64_t store(void)
160{
161  rtems_counter_ticks a;
162  rtems_counter_ticks b;
163  rtems_counter_ticks d;
164  size_t i;
165  volatile int *vdata = &data[0];
166
167  a = rtems_counter_read();
168  for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
169    vdata[i] = 0;
170  }
171  b = rtems_counter_read();
172
173  d = rtems_counter_difference(b, a);
174
175  return rtems_counter_ticks_to_nanoseconds(d);
176}
177
178static void test_timing(void)
179{
180  RTEMS_INTERRUPT_LOCK_DECLARE(, lock)
181  rtems_interrupt_lock_context lock_context;
182  size_t data_size = sizeof(data);
183  uint64_t d[3];
184  uint32_t cache_level;
185  size_t cache_size;
186  bool exception;
187
188  rtems_interrupt_lock_initialize(&lock, "test");
189
190  printf(
191    "data cache line size %zi bytes\n"
192    "data cache size %zi bytes\n",
193    rtems_cache_get_data_line_size(),
194    rtems_cache_get_data_cache_size(0)
195  );
196
197  cache_level = 1;
198  cache_size = rtems_cache_get_data_cache_size(cache_level);
199  while (cache_size > 0) {
200    printf(
201      "data cache level %" PRIu32 " size %zi bytes\n",
202      cache_level,
203      cache_size
204    );
205    ++cache_level;
206    cache_size = rtems_cache_get_data_cache_size(cache_level);
207  }
208
209  rtems_interrupt_lock_acquire(&lock, &lock_context);
210
211  d[0] = load();
212  d[1] = load();
213  rtems_cache_flush_entire_data();
214  d[2] = load();
215
216  rtems_interrupt_lock_release(&lock, &lock_context);
217
218  printf(
219    "load %zi bytes with flush entire data\n"
220    "  duration with normal cache %" PRIu64 " ns\n"
221    "  duration with warm cache %" PRIu64 " ns\n"
222    "  duration with flushed cache %" PRIu64 " ns\n",
223    data_size,
224    d[0],
225    d[1],
226    d[2]
227  );
228
229  rtems_interrupt_lock_acquire(&lock, &lock_context);
230
231  d[0] = load();
232  d[1] = load();
233  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
234  d[2] = load();
235
236  rtems_interrupt_lock_release(&lock, &lock_context);
237
238  printf(
239    "load %zi bytes with flush multiple data\n"
240    "  duration with normal cache %" PRIu64 " ns\n"
241    "  duration with warm cache %" PRIu64 " ns\n"
242    "  duration with flushed cache %" PRIu64 " ns\n",
243    data_size,
244    d[0],
245    d[1],
246    d[2]
247  );
248
249  rtems_interrupt_lock_acquire(&lock, &lock_context);
250
251  d[0] = load();
252  d[1] = load();
253  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
254  d[2] = load();
255
256  rtems_interrupt_lock_release(&lock, &lock_context);
257
258  printf(
259    "load %zi bytes with invalidate multiple data\n"
260    "  duration with normal cache %" PRIu64 " ns\n"
261    "  duration with warm cache %" PRIu64 " ns\n"
262    "  duration with invalidated cache %" PRIu64 " ns\n",
263    data_size,
264    d[0],
265    d[1],
266    d[2]
267  );
268
269  rtems_interrupt_lock_acquire(&lock, &lock_context);
270
271  d[0] = store();
272  d[1] = store();
273  rtems_cache_flush_entire_data();
274  d[2] = store();
275
276  rtems_interrupt_lock_release(&lock, &lock_context);
277
278  printf(
279    "store %zi bytes with flush entire data\n"
280    "  duration with normal cache %" PRIu64 " ns\n"
281    "  duration with warm cache %" PRIu64 " ns\n"
282    "  duration with flushed cache %" PRIu64 " ns\n",
283    data_size,
284    d[0],
285    d[1],
286    d[2]
287  );
288
289  rtems_interrupt_lock_acquire(&lock, &lock_context);
290
291  d[0] = store();
292  d[1] = store();
293  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
294  d[2] = store();
295
296  rtems_interrupt_lock_release(&lock, &lock_context);
297
298  printf(
299    "store %zi bytes with flush multiple data\n"
300    "  duration with normal cache %" PRIu64 " ns\n"
301    "  duration with warm cache %" PRIu64 " ns\n"
302    "  duration with flushed cache %" PRIu64 " ns\n",
303    data_size,
304    d[0],
305    d[1],
306    d[2]
307  );
308
309  rtems_interrupt_lock_acquire(&lock, &lock_context);
310
311  d[0] = store();
312  d[1] = store();
313  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
314  d[2] = store();
315
316  rtems_interrupt_lock_release(&lock, &lock_context);
317
318  printf(
319    "store %zi bytes with invalidate multiple data\n"
320    "  duration with normal cache %" PRIu64 " ns\n"
321    "  duration with warm cache %" PRIu64 " ns\n"
322    "  duration with invalidated cache %" PRIu64 " ns\n",
323    data_size,
324    d[0],
325    d[1],
326    d[2]
327  );
328
329  printf(
330    "instruction cache line size %zi bytes\n"
331    "instruction cache size %zi bytes\n",
332    rtems_cache_get_instruction_line_size(),
333    rtems_cache_get_instruction_cache_size(0)
334  );
335
336  cache_level = 1;
337  cache_size = rtems_cache_get_instruction_cache_size(cache_level);
338  while (cache_size > 0) {
339    printf(
340      "instruction cache level %" PRIu32 " size %zi bytes\n",
341      cache_level,
342      cache_size
343    );
344    ++cache_level;
345    cache_size = rtems_cache_get_instruction_cache_size(cache_level);
346  }
347
348  rtems_interrupt_lock_acquire(&lock, &lock_context);
349
350  d[0] = do_some_work();
351  d[1] = do_some_work();
352  rtems_cache_invalidate_entire_instruction();
353  d[2] = do_some_work();
354
355  rtems_interrupt_lock_release(&lock, &lock_context);
356
357  printf(
358    "invalidate entire instruction\n"
359    "  duration with normal cache %" PRIu64 " ns\n"
360    "  duration with warm cache %" PRIu64 " ns\n"
361    "  duration with invalidated cache %" PRIu64 " ns\n",
362    d[0],
363    d[1],
364    d[2]
365  );
366
367  rtems_interrupt_lock_acquire(&lock, &lock_context);
368
369  d[0] = do_some_work();
370  d[1] = do_some_work();
371
372  do_longjmp = true;
373
374  if (setjmp(instruction_invalidate_return_context) == 0) {
375    rtems_cache_invalidate_multiple_instruction_lines(do_some_work, 4096);
376    exception = false;
377  } else {
378    exception = true;
379  }
380
381  do_longjmp = false;
382
383  d[2] = do_some_work();
384
385  rtems_interrupt_lock_release(&lock, &lock_context);
386
387  printf(
388    "invalidate multiple instruction\n"
389    "  duration with normal cache %" PRIu64 " ns\n"
390    "  duration with warm cache %" PRIu64 " ns\n"
391    "  duration with invalidated cache %" PRIu64 " ns\n",
392    d[0],
393    d[1],
394    d[2]
395  );
396
397  if (exception) {
398    printf(
399      "rtems_cache_invalidate_multiple_data_lines() generated an exception\n"
400    );
401  }
402
403  rtems_interrupt_lock_destroy(&lock);
404}
405
406static void test_cache_aligned_alloc(void)
407{
408  void *p0;
409  void *p1;
410  size_t cls;
411
412  printf("test rtems_cache_aligned_malloc()\n");
413
414  p0 = rtems_cache_aligned_malloc(1);
415  p1 = rtems_cache_aligned_malloc(1);
416
417  rtems_test_assert(p0 != NULL);
418  rtems_test_assert(p1 != NULL);
419
420  cls = rtems_cache_get_data_line_size();
421  if (cls > 0) {
422    size_t m = cls - 1;
423    uintptr_t a0 = (uintptr_t) p0;
424    uintptr_t a1 = (uintptr_t) p1;
425
426    rtems_test_assert(a1 - a0 > cls);
427    rtems_test_assert((a0 & m) == 0);
428    rtems_test_assert((a1 & m) == 0);
429  }
430
431  free(p0);
432  free(p1);
433}
434
435#define AREA_SIZE 256
436
437static char cache_coherent_area_0[AREA_SIZE];
438
439static char cache_coherent_area_1[AREA_SIZE];
440
441static char cache_coherent_area_2[AREA_SIZE];
442
443static void add_area(void *begin)
444{
445  rtems_cache_coherent_add_area(NULL, 0);
446  rtems_cache_coherent_add_area(begin, AREA_SIZE);
447}
448
449static void test_cache_coherent_alloc(void)
450{
451  void *p0;
452  void *p1;
453  System_state_Codes previous_state;
454
455  printf("test cache coherent allocation\n");
456
457  p0 = rtems_cache_coherent_allocate(1, 0, 0);
458  rtems_test_assert(p0 != NULL);
459
460  rtems_cache_coherent_free(p0);
461
462  p0 = rtems_cache_coherent_allocate(1, 0, 0);
463  rtems_test_assert(p0 != NULL);
464
465  add_area(&cache_coherent_area_0[0]);
466  add_area(&cache_coherent_area_1[0]);
467
468  previous_state = _System_state_Get();
469  _System_state_Set(previous_state + 1);
470  add_area(&cache_coherent_area_2[0]);
471  _System_state_Set(previous_state);
472
473  p1 = rtems_cache_coherent_allocate(1, 0, 0);
474  rtems_test_assert(p1 != NULL);
475
476  rtems_cache_coherent_free(p0);
477  rtems_cache_coherent_free(p1);
478}
479
480static void Init(rtems_task_argument arg)
481{
482  TEST_BEGIN();
483
484  test_data_flush_and_invalidate();
485  test_timing();
486  test_cache_aligned_alloc();
487  test_cache_coherent_alloc();
488
489  TEST_END();
490
491  rtems_test_exit(0);
492}
493
494static void fatal_extension(
495  rtems_fatal_source source,
496  bool always_set_to_false,
497  rtems_fatal_code error
498)
499{
500  if (source == RTEMS_FATAL_SOURCE_EXCEPTION && do_longjmp) {
501    _ISR_Set_level(0);
502    longjmp(instruction_invalidate_return_context, 1);
503  }
504}
505
506#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
507#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
508
509#define CONFIGURE_MAXIMUM_TASKS 1
510
511#define CONFIGURE_INITIAL_EXTENSIONS \
512  { .fatal = fatal_extension }, \
513  RTEMS_TEST_INITIAL_EXTENSION
514
515#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
516
517#define CONFIGURE_INIT
518
519#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.