File indexing completed on 2025-05-11 08:24:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031
0032 #include <inttypes.h>
0033 #include <setjmp.h>
0034 #include <stdio.h>
0035 #include <stdlib.h>
0036
0037 #include <rtems.h>
0038 #include <rtems/counter.h>
0039 #include <rtems/score/cpuimpl.h>
0040 #include <rtems/score/sysstate.h>
0041
0042 #include "tmacros.h"
0043
0044 const char rtems_test_name[] = "SPCACHE 1";
0045
0046 #define I() _CPU_Instruction_no_operation()
0047
0048 #define I8() I(); I(); I(); I(); I(); I(); I(); I()
0049
0050 #define I64() I8(); I8(); I8(); I8(); I8(); I8(); I8(); I8()
0051
0052 #define I512() I64(); I64(); I64(); I64(); I64(); I64(); I64(); I64()
0053
0054 CPU_STRUCTURE_ALIGNMENT static int data[1024];
0055
0056 static bool do_longjmp;
0057
0058 static jmp_buf instruction_invalidate_return_context;
0059
0060 static void test_data_flush_and_invalidate(void)
0061 {
0062 if (rtems_cache_get_data_line_size() > 0) {
0063 RTEMS_INTERRUPT_LOCK_DECLARE(, lock)
0064 rtems_interrupt_lock_context lock_context;
0065 volatile int *vdata = &data[0];
0066 int n = 32;
0067 int i;
0068 size_t data_size = n * sizeof(data[0]);
0069 bool write_through;
0070
0071 printf("data cache flush and invalidate test\n");
0072
0073 rtems_interrupt_lock_initialize(&lock, "test");
0074 rtems_interrupt_lock_acquire(&lock, &lock_context);
0075
0076 for (i = 0; i < n; ++i) {
0077 vdata[i] = i;
0078 }
0079
0080 rtems_cache_flush_multiple_data_lines(&data[0], data_size);
0081
0082 for (i = 0; i < n; ++i) {
0083 rtems_test_assert(vdata[i] == i);
0084 }
0085
0086 for (i = 0; i < n; ++i) {
0087 vdata[i] = ~i;
0088 }
0089
0090 rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);
0091
0092 write_through = vdata[0] == ~0;
0093 if (write_through) {
0094 for (i = 0; i < n; ++i) {
0095 rtems_test_assert(vdata[i] == ~i);
0096 }
0097 } else {
0098 for (i = 0; i < n; ++i) {
0099 rtems_test_assert(vdata[i] == i);
0100 }
0101 }
0102
0103 for (i = 0; i < n; ++i) {
0104 vdata[i] = ~i;
0105 }
0106
0107 rtems_cache_flush_multiple_data_lines(&data[0], data_size);
0108 rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);
0109
0110 for (i = 0; i < n; ++i) {
0111 rtems_test_assert(vdata[i] == ~i);
0112 }
0113
0114 rtems_interrupt_lock_release(&lock, &lock_context);
0115 rtems_interrupt_lock_destroy(&lock);
0116
0117 printf(
0118 "data cache operations by line passed the test (%s cache detected)\n",
0119 write_through ? "write-through" : "copy-back"
0120 );
0121 } else {
0122 printf(
0123 "skip data cache flush and invalidate test"
0124 " due to cache line size of zero\n"
0125 );
0126 }
0127
0128
0129 rtems_cache_flush_multiple_data_lines(NULL, 0);
0130 rtems_cache_invalidate_multiple_data_lines(NULL, 0);
0131 }
0132
0133 static uint64_t do_some_work(void)
0134 {
0135 rtems_counter_ticks a;
0136 rtems_counter_ticks b;
0137 rtems_counter_ticks d;
0138
0139
0140 a = rtems_counter_read();
0141 I512();
0142 I512();
0143 b = rtems_counter_read();
0144
0145 d = rtems_counter_difference(b, a);
0146
0147 return rtems_counter_ticks_to_nanoseconds(d);
0148 }
0149
0150 static uint64_t load(void)
0151 {
0152 rtems_counter_ticks a;
0153 rtems_counter_ticks b;
0154 rtems_counter_ticks d;
0155 size_t i;
0156 volatile int *vdata = &data[0];
0157
0158 a = rtems_counter_read();
0159 for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
0160 vdata[i];
0161 }
0162 b = rtems_counter_read();
0163
0164 d = rtems_counter_difference(b, a);
0165
0166 return rtems_counter_ticks_to_nanoseconds(d);
0167 }
0168
0169 static uint64_t store(void)
0170 {
0171 rtems_counter_ticks a;
0172 rtems_counter_ticks b;
0173 rtems_counter_ticks d;
0174 size_t i;
0175 volatile int *vdata = &data[0];
0176
0177 a = rtems_counter_read();
0178 for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
0179 vdata[i] = 0;
0180 }
0181 b = rtems_counter_read();
0182
0183 d = rtems_counter_difference(b, a);
0184
0185 return rtems_counter_ticks_to_nanoseconds(d);
0186 }
0187
0188 static void test_timing(void)
0189 {
0190 RTEMS_INTERRUPT_LOCK_DECLARE(, lock)
0191 rtems_interrupt_lock_context lock_context;
0192 size_t data_size = sizeof(data);
0193 uint64_t d[3];
0194 uint32_t cache_level;
0195 size_t cache_size;
0196 bool exception;
0197
0198 rtems_interrupt_lock_initialize(&lock, "test");
0199
0200 printf(
0201 "data cache line size %zi bytes\n"
0202 "data cache size %zi bytes\n",
0203 rtems_cache_get_data_line_size(),
0204 rtems_cache_get_data_cache_size(0)
0205 );
0206
0207 cache_level = 1;
0208 cache_size = rtems_cache_get_data_cache_size(cache_level);
0209 while (cache_size > 0) {
0210 printf(
0211 "data cache level %" PRIu32 " size %zi bytes\n",
0212 cache_level,
0213 cache_size
0214 );
0215 ++cache_level;
0216 cache_size = rtems_cache_get_data_cache_size(cache_level);
0217 }
0218
0219 rtems_interrupt_lock_acquire(&lock, &lock_context);
0220
0221 d[0] = load();
0222 d[1] = load();
0223 rtems_cache_flush_entire_data();
0224 d[2] = load();
0225
0226 rtems_interrupt_lock_release(&lock, &lock_context);
0227
0228 printf(
0229 "load %zi bytes with flush entire data\n"
0230 " duration with normal cache %" PRIu64 " ns\n"
0231 " duration with warm cache %" PRIu64 " ns\n"
0232 " duration with flushed cache %" PRIu64 " ns\n",
0233 data_size,
0234 d[0],
0235 d[1],
0236 d[2]
0237 );
0238
0239 rtems_interrupt_lock_acquire(&lock, &lock_context);
0240
0241 d[0] = load();
0242 d[1] = load();
0243 rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
0244 d[2] = load();
0245
0246 rtems_interrupt_lock_release(&lock, &lock_context);
0247
0248 printf(
0249 "load %zi bytes with flush multiple data\n"
0250 " duration with normal cache %" PRIu64 " ns\n"
0251 " duration with warm cache %" PRIu64 " ns\n"
0252 " duration with flushed cache %" PRIu64 " ns\n",
0253 data_size,
0254 d[0],
0255 d[1],
0256 d[2]
0257 );
0258
0259 rtems_interrupt_lock_acquire(&lock, &lock_context);
0260
0261 d[0] = load();
0262 d[1] = load();
0263 rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
0264 d[2] = load();
0265
0266 rtems_interrupt_lock_release(&lock, &lock_context);
0267
0268 printf(
0269 "load %zi bytes with invalidate multiple data\n"
0270 " duration with normal cache %" PRIu64 " ns\n"
0271 " duration with warm cache %" PRIu64 " ns\n"
0272 " duration with invalidated cache %" PRIu64 " ns\n",
0273 data_size,
0274 d[0],
0275 d[1],
0276 d[2]
0277 );
0278
0279 rtems_interrupt_lock_acquire(&lock, &lock_context);
0280
0281 d[0] = store();
0282 d[1] = store();
0283 rtems_cache_flush_entire_data();
0284 d[2] = store();
0285
0286 rtems_interrupt_lock_release(&lock, &lock_context);
0287
0288 printf(
0289 "store %zi bytes with flush entire data\n"
0290 " duration with normal cache %" PRIu64 " ns\n"
0291 " duration with warm cache %" PRIu64 " ns\n"
0292 " duration with flushed cache %" PRIu64 " ns\n",
0293 data_size,
0294 d[0],
0295 d[1],
0296 d[2]
0297 );
0298
0299 rtems_interrupt_lock_acquire(&lock, &lock_context);
0300
0301 d[0] = store();
0302 d[1] = store();
0303 rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
0304 d[2] = store();
0305
0306 rtems_interrupt_lock_release(&lock, &lock_context);
0307
0308 printf(
0309 "store %zi bytes with flush multiple data\n"
0310 " duration with normal cache %" PRIu64 " ns\n"
0311 " duration with warm cache %" PRIu64 " ns\n"
0312 " duration with flushed cache %" PRIu64 " ns\n",
0313 data_size,
0314 d[0],
0315 d[1],
0316 d[2]
0317 );
0318
0319 rtems_interrupt_lock_acquire(&lock, &lock_context);
0320
0321 d[0] = store();
0322 d[1] = store();
0323 rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
0324 d[2] = store();
0325
0326 rtems_interrupt_lock_release(&lock, &lock_context);
0327
0328 printf(
0329 "store %zi bytes with invalidate multiple data\n"
0330 " duration with normal cache %" PRIu64 " ns\n"
0331 " duration with warm cache %" PRIu64 " ns\n"
0332 " duration with invalidated cache %" PRIu64 " ns\n",
0333 data_size,
0334 d[0],
0335 d[1],
0336 d[2]
0337 );
0338
0339 printf(
0340 "instruction cache line size %zi bytes\n"
0341 "instruction cache size %zi bytes\n",
0342 rtems_cache_get_instruction_line_size(),
0343 rtems_cache_get_instruction_cache_size(0)
0344 );
0345
0346 cache_level = 1;
0347 cache_size = rtems_cache_get_instruction_cache_size(cache_level);
0348 while (cache_size > 0) {
0349 printf(
0350 "instruction cache level %" PRIu32 " size %zi bytes\n",
0351 cache_level,
0352 cache_size
0353 );
0354 ++cache_level;
0355 cache_size = rtems_cache_get_instruction_cache_size(cache_level);
0356 }
0357
0358 rtems_interrupt_lock_acquire(&lock, &lock_context);
0359
0360 d[0] = do_some_work();
0361 d[1] = do_some_work();
0362 rtems_cache_invalidate_entire_instruction();
0363 d[2] = do_some_work();
0364
0365 rtems_interrupt_lock_release(&lock, &lock_context);
0366
0367 printf(
0368 "invalidate entire instruction\n"
0369 " duration with normal cache %" PRIu64 " ns\n"
0370 " duration with warm cache %" PRIu64 " ns\n"
0371 " duration with invalidated cache %" PRIu64 " ns\n",
0372 d[0],
0373 d[1],
0374 d[2]
0375 );
0376
0377 rtems_interrupt_lock_acquire(&lock, &lock_context);
0378
0379 d[0] = do_some_work();
0380 d[1] = do_some_work();
0381
0382 do_longjmp = true;
0383
0384 if (setjmp(instruction_invalidate_return_context) == 0) {
0385 rtems_cache_invalidate_multiple_instruction_lines(do_some_work, 4096);
0386 exception = false;
0387 } else {
0388 exception = true;
0389 }
0390
0391 do_longjmp = false;
0392
0393 d[2] = do_some_work();
0394
0395 rtems_interrupt_lock_release(&lock, &lock_context);
0396
0397 printf(
0398 "invalidate multiple instruction\n"
0399 " duration with normal cache %" PRIu64 " ns\n"
0400 " duration with warm cache %" PRIu64 " ns\n"
0401 " duration with invalidated cache %" PRIu64 " ns\n",
0402 d[0],
0403 d[1],
0404 d[2]
0405 );
0406
0407 if (exception) {
0408 printf(
0409 "rtems_cache_invalidate_multiple_data_lines() generated an exception\n"
0410 );
0411 }
0412
0413 rtems_interrupt_lock_destroy(&lock);
0414 }
0415
0416 static void test_cache_aligned_alloc(void)
0417 {
0418 void *p0;
0419 void *p1;
0420 size_t cls;
0421
0422 printf("test rtems_cache_aligned_malloc()\n");
0423
0424 p0 = rtems_cache_aligned_malloc(1);
0425 p1 = rtems_cache_aligned_malloc(1);
0426
0427 rtems_test_assert(p0 != NULL);
0428 rtems_test_assert(p1 != NULL);
0429
0430 cls = rtems_cache_get_data_line_size();
0431 if (cls > 0) {
0432 size_t m = cls - 1;
0433 uintptr_t a0 = (uintptr_t) p0;
0434 uintptr_t a1 = (uintptr_t) p1;
0435
0436 rtems_test_assert(a1 - a0 > cls);
0437 rtems_test_assert((a0 & m) == 0);
0438 rtems_test_assert((a1 & m) == 0);
0439 }
0440
0441 free(p0);
0442 free(p1);
0443 }
0444
0445 #define AREA_SIZE 256
0446
0447 static char cache_coherent_area_0[AREA_SIZE];
0448
0449 static char cache_coherent_area_1[AREA_SIZE];
0450
0451 static char cache_coherent_area_2[AREA_SIZE];
0452
0453 static void add_area(void *begin)
0454 {
0455 rtems_cache_coherent_add_area(NULL, 0);
0456 rtems_cache_coherent_add_area(begin, AREA_SIZE);
0457 }
0458
0459 static void test_cache_coherent_alloc(void)
0460 {
0461 void *p0;
0462 void *p1;
0463 System_state_Codes previous_state;
0464
0465 printf("test cache coherent allocation\n");
0466
0467 p0 = rtems_cache_coherent_allocate(1, 0, 0);
0468 rtems_test_assert(p0 != NULL);
0469
0470 rtems_cache_coherent_free(p0);
0471
0472 p0 = rtems_cache_coherent_allocate(1, 0, 0);
0473 rtems_test_assert(p0 != NULL);
0474
0475 add_area(&cache_coherent_area_0[0]);
0476 add_area(&cache_coherent_area_1[0]);
0477
0478 previous_state = _System_state_Get();
0479 _System_state_Set(previous_state + 1);
0480 add_area(&cache_coherent_area_2[0]);
0481 _System_state_Set(previous_state);
0482
0483 p1 = rtems_cache_coherent_allocate(1, 0, 0);
0484 rtems_test_assert(p1 != NULL);
0485
0486 rtems_cache_coherent_free(p0);
0487 rtems_cache_coherent_free(p1);
0488 }
0489
0490 static void Init(rtems_task_argument arg)
0491 {
0492 TEST_BEGIN();
0493
0494 test_data_flush_and_invalidate();
0495 test_timing();
0496 test_cache_aligned_alloc();
0497 test_cache_coherent_alloc();
0498
0499 TEST_END();
0500
0501 rtems_test_exit(0);
0502 }
0503
0504 static void fatal_extension(
0505 rtems_fatal_source source,
0506 bool always_set_to_false,
0507 rtems_fatal_code error
0508 )
0509 {
0510 if (source == RTEMS_FATAL_SOURCE_EXCEPTION && do_longjmp) {
0511 _ISR_Set_level(0);
0512 longjmp(instruction_invalidate_return_context, 1);
0513 }
0514 }
0515
0516 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0517 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0518
0519 #define CONFIGURE_MAXIMUM_TASKS 1
0520
0521 #define CONFIGURE_INITIAL_EXTENSIONS \
0522 { .fatal = fatal_extension }, \
0523 RTEMS_TEST_INITIAL_EXTENSION
0524
0525 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0526
0527 #define CONFIGURE_INIT
0528
0529 #include <rtems/confdefs.h>