[3378be95] | 1 | /* |
---|
| 2 | * Copyright (c) 2014 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 |
---|
[c499856] | 12 | * http://www.rtems.org/license/LICENSE. |
---|
[3378be95] | 13 | */ |
---|
| 14 | |
---|
| 15 | #ifdef HAVE_CONFIG_H |
---|
| 16 | #include "config.h" |
---|
| 17 | #endif |
---|
| 18 | |
---|
| 19 | #include <stdio.h> |
---|
| 20 | #include <inttypes.h> |
---|
| 21 | |
---|
| 22 | #include <rtems.h> |
---|
| 23 | #include <rtems/counter.h> |
---|
| 24 | |
---|
| 25 | #define TESTS_USE_PRINTF |
---|
| 26 | #include "tmacros.h" |
---|
| 27 | |
---|
[6c0301d] | 28 | const char rtems_test_name[] = "SPCACHE 1"; |
---|
| 29 | |
---|
[3378be95] | 30 | #define I() __asm__ volatile ("nop") |
---|
| 31 | |
---|
| 32 | #define I8() I(); I(); I(); I(); I(); I(); I(); I() |
---|
| 33 | |
---|
| 34 | #define I64() I8(); I8(); I8(); I8(); I8(); I8(); I8(); I8() |
---|
| 35 | |
---|
| 36 | #define I512() I64(); I64(); I64(); I64(); I64(); I64(); I64(); I64() |
---|
| 37 | |
---|
| 38 | CPU_STRUCTURE_ALIGNMENT static int data[1024]; |
---|
| 39 | |
---|
| 40 | static void test_data_flush_and_invalidate(void) |
---|
| 41 | { |
---|
| 42 | if (rtems_cache_get_data_line_size() > 0) { |
---|
[d50acdbb] | 43 | rtems_interrupt_lock lock; |
---|
| 44 | rtems_interrupt_lock_context lock_context; |
---|
[3378be95] | 45 | volatile int *vdata = &data[0]; |
---|
| 46 | int n = 32; |
---|
| 47 | int i; |
---|
| 48 | size_t data_size = n * sizeof(data[0]); |
---|
[31494ab2] | 49 | bool write_through; |
---|
[3378be95] | 50 | |
---|
| 51 | printf("data cache flush and invalidate test\n"); |
---|
| 52 | |
---|
[53ad908] | 53 | rtems_interrupt_lock_initialize(&lock, "test"); |
---|
[d50acdbb] | 54 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 55 | |
---|
| 56 | for (i = 0; i < n; ++i) { |
---|
| 57 | vdata[i] = i; |
---|
| 58 | } |
---|
| 59 | |
---|
| 60 | rtems_cache_flush_multiple_data_lines(&data[0], data_size); |
---|
| 61 | |
---|
| 62 | for (i = 0; i < n; ++i) { |
---|
| 63 | rtems_test_assert(vdata[i] == i); |
---|
| 64 | } |
---|
| 65 | |
---|
| 66 | for (i = 0; i < n; ++i) { |
---|
| 67 | vdata[i] = ~i; |
---|
| 68 | } |
---|
| 69 | |
---|
| 70 | rtems_cache_invalidate_multiple_data_lines(&data[0], data_size); |
---|
| 71 | |
---|
[31494ab2] | 72 | write_through = vdata[0] == ~0; |
---|
| 73 | if (write_through) { |
---|
| 74 | for (i = 0; i < n; ++i) { |
---|
| 75 | rtems_test_assert(vdata[i] == ~i); |
---|
| 76 | } |
---|
| 77 | } else { |
---|
| 78 | for (i = 0; i < n; ++i) { |
---|
| 79 | rtems_test_assert(vdata[i] == i); |
---|
| 80 | } |
---|
[3378be95] | 81 | } |
---|
| 82 | |
---|
| 83 | for (i = 0; i < n; ++i) { |
---|
| 84 | vdata[i] = ~i; |
---|
| 85 | } |
---|
| 86 | |
---|
| 87 | rtems_cache_flush_multiple_data_lines(&data[0], data_size); |
---|
| 88 | rtems_cache_invalidate_multiple_data_lines(&data[0], data_size); |
---|
| 89 | |
---|
| 90 | for (i = 0; i < n; ++i) { |
---|
| 91 | rtems_test_assert(vdata[i] == ~i); |
---|
| 92 | } |
---|
| 93 | |
---|
[d50acdbb] | 94 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[28779c7] | 95 | rtems_interrupt_lock_destroy(&lock); |
---|
[3378be95] | 96 | |
---|
[31494ab2] | 97 | printf( |
---|
| 98 | "data cache operations by line passed the test (%s cache detected)\n", |
---|
| 99 | write_through ? "write-through" : "copy-back" |
---|
| 100 | ); |
---|
[3378be95] | 101 | } else { |
---|
| 102 | printf( |
---|
| 103 | "skip data cache flush and invalidate test" |
---|
| 104 | " due to cache line size of zero\n" |
---|
| 105 | ); |
---|
| 106 | } |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | static uint64_t do_some_work(void) |
---|
| 110 | { |
---|
| 111 | rtems_counter_ticks a; |
---|
| 112 | rtems_counter_ticks b; |
---|
| 113 | rtems_counter_ticks d; |
---|
| 114 | |
---|
| 115 | /* This gives 1024 nop instructions */ |
---|
| 116 | a = rtems_counter_read(); |
---|
| 117 | I512(); |
---|
| 118 | I512(); |
---|
| 119 | b = rtems_counter_read(); |
---|
| 120 | |
---|
| 121 | d = rtems_counter_difference(b, a); |
---|
| 122 | |
---|
| 123 | return rtems_counter_ticks_to_nanoseconds(d); |
---|
| 124 | } |
---|
| 125 | |
---|
| 126 | static uint64_t load(void) |
---|
| 127 | { |
---|
| 128 | rtems_counter_ticks a; |
---|
| 129 | rtems_counter_ticks b; |
---|
| 130 | rtems_counter_ticks d; |
---|
| 131 | size_t i; |
---|
| 132 | volatile int *vdata = &data[0]; |
---|
| 133 | |
---|
| 134 | a = rtems_counter_read(); |
---|
| 135 | for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) { |
---|
| 136 | vdata[i]; |
---|
| 137 | } |
---|
| 138 | b = rtems_counter_read(); |
---|
| 139 | |
---|
| 140 | d = rtems_counter_difference(b, a); |
---|
| 141 | |
---|
| 142 | return rtems_counter_ticks_to_nanoseconds(d); |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | static uint64_t store(void) |
---|
| 146 | { |
---|
| 147 | rtems_counter_ticks a; |
---|
| 148 | rtems_counter_ticks b; |
---|
| 149 | rtems_counter_ticks d; |
---|
| 150 | size_t i; |
---|
| 151 | volatile int *vdata = &data[0]; |
---|
| 152 | |
---|
| 153 | a = rtems_counter_read(); |
---|
| 154 | for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) { |
---|
| 155 | vdata[i] = 0; |
---|
| 156 | } |
---|
| 157 | b = rtems_counter_read(); |
---|
| 158 | |
---|
| 159 | d = rtems_counter_difference(b, a); |
---|
| 160 | |
---|
| 161 | return rtems_counter_ticks_to_nanoseconds(d); |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | static void test_timing(void) |
---|
| 165 | { |
---|
[d50acdbb] | 166 | rtems_interrupt_lock lock; |
---|
| 167 | rtems_interrupt_lock_context lock_context; |
---|
[3378be95] | 168 | size_t data_size = sizeof(data); |
---|
| 169 | uint64_t d[3]; |
---|
[e1d7bf0] | 170 | uint32_t cache_level; |
---|
| 171 | size_t cache_size; |
---|
[3378be95] | 172 | |
---|
[53ad908] | 173 | rtems_interrupt_lock_initialize(&lock, "test"); |
---|
[d50acdbb] | 174 | |
---|
[3378be95] | 175 | printf( |
---|
[e1d7bf0] | 176 | "data cache line size %zi bytes\n" |
---|
| 177 | "data cache size %zi bytes\n", |
---|
| 178 | rtems_cache_get_data_line_size(), |
---|
| 179 | rtems_cache_get_data_cache_size(0) |
---|
[3378be95] | 180 | ); |
---|
| 181 | |
---|
[e1d7bf0] | 182 | cache_level = 1; |
---|
| 183 | cache_size = rtems_cache_get_data_cache_size(cache_level); |
---|
| 184 | while (cache_size > 0) { |
---|
| 185 | printf( |
---|
| 186 | "data cache level %" PRIu32 " size %zi bytes\n", |
---|
| 187 | cache_level, |
---|
| 188 | cache_size |
---|
| 189 | ); |
---|
| 190 | ++cache_level; |
---|
| 191 | cache_size = rtems_cache_get_data_cache_size(cache_level); |
---|
| 192 | } |
---|
| 193 | |
---|
[d50acdbb] | 194 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 195 | |
---|
| 196 | d[0] = load(); |
---|
| 197 | d[1] = load(); |
---|
| 198 | rtems_cache_flush_entire_data(); |
---|
| 199 | d[2] = load(); |
---|
| 200 | |
---|
[d50acdbb] | 201 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 202 | |
---|
| 203 | printf( |
---|
| 204 | "load %zi bytes with flush entire data\n" |
---|
| 205 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 206 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 207 | " duration with flushed cache %" PRIu64 " ns\n", |
---|
| 208 | data_size, |
---|
| 209 | d[0], |
---|
| 210 | d[1], |
---|
| 211 | d[2] |
---|
| 212 | ); |
---|
| 213 | |
---|
[d50acdbb] | 214 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 215 | |
---|
| 216 | d[0] = load(); |
---|
| 217 | d[1] = load(); |
---|
| 218 | rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data)); |
---|
| 219 | d[2] = load(); |
---|
| 220 | |
---|
[d50acdbb] | 221 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 222 | |
---|
| 223 | printf( |
---|
| 224 | "load %zi bytes with flush multiple data\n" |
---|
| 225 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 226 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 227 | " duration with flushed cache %" PRIu64 " ns\n", |
---|
| 228 | data_size, |
---|
| 229 | d[0], |
---|
| 230 | d[1], |
---|
| 231 | d[2] |
---|
| 232 | ); |
---|
| 233 | |
---|
[d50acdbb] | 234 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 235 | |
---|
| 236 | d[0] = load(); |
---|
| 237 | d[1] = load(); |
---|
| 238 | rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data)); |
---|
| 239 | d[2] = load(); |
---|
| 240 | |
---|
[d50acdbb] | 241 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 242 | |
---|
| 243 | printf( |
---|
| 244 | "load %zi bytes with invalidate multiple data\n" |
---|
| 245 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 246 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 247 | " duration with invalidated cache %" PRIu64 " ns\n", |
---|
| 248 | data_size, |
---|
| 249 | d[0], |
---|
| 250 | d[1], |
---|
| 251 | d[2] |
---|
| 252 | ); |
---|
| 253 | |
---|
[d50acdbb] | 254 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 255 | |
---|
| 256 | d[0] = store(); |
---|
| 257 | d[1] = store(); |
---|
| 258 | rtems_cache_flush_entire_data(); |
---|
| 259 | d[2] = store(); |
---|
| 260 | |
---|
[d50acdbb] | 261 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 262 | |
---|
| 263 | printf( |
---|
| 264 | "store %zi bytes with flush entire data\n" |
---|
| 265 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 266 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 267 | " duration with flushed cache %" PRIu64 " ns\n", |
---|
| 268 | data_size, |
---|
| 269 | d[0], |
---|
| 270 | d[1], |
---|
| 271 | d[2] |
---|
| 272 | ); |
---|
| 273 | |
---|
[d50acdbb] | 274 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 275 | |
---|
| 276 | d[0] = store(); |
---|
| 277 | d[1] = store(); |
---|
| 278 | rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data)); |
---|
| 279 | d[2] = store(); |
---|
| 280 | |
---|
[d50acdbb] | 281 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 282 | |
---|
| 283 | printf( |
---|
| 284 | "store %zi bytes with flush multiple data\n" |
---|
| 285 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 286 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 287 | " duration with flushed cache %" PRIu64 " ns\n", |
---|
| 288 | data_size, |
---|
| 289 | d[0], |
---|
| 290 | d[1], |
---|
| 291 | d[2] |
---|
| 292 | ); |
---|
| 293 | |
---|
[d50acdbb] | 294 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 295 | |
---|
| 296 | d[0] = store(); |
---|
| 297 | d[1] = store(); |
---|
| 298 | rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data)); |
---|
| 299 | d[2] = store(); |
---|
| 300 | |
---|
[d50acdbb] | 301 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 302 | |
---|
| 303 | printf( |
---|
| 304 | "store %zi bytes with invalidate multiple data\n" |
---|
| 305 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 306 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 307 | " duration with invalidated cache %" PRIu64 " ns\n", |
---|
| 308 | data_size, |
---|
| 309 | d[0], |
---|
| 310 | d[1], |
---|
| 311 | d[2] |
---|
| 312 | ); |
---|
| 313 | |
---|
| 314 | printf( |
---|
[e1d7bf0] | 315 | "instruction cache line size %zi bytes\n" |
---|
| 316 | "instruction cache size %zi bytes\n", |
---|
| 317 | rtems_cache_get_instruction_line_size(), |
---|
| 318 | rtems_cache_get_instruction_cache_size(0) |
---|
[3378be95] | 319 | ); |
---|
| 320 | |
---|
[e1d7bf0] | 321 | cache_level = 1; |
---|
| 322 | cache_size = rtems_cache_get_instruction_cache_size(cache_level); |
---|
| 323 | while (cache_size > 0) { |
---|
| 324 | printf( |
---|
| 325 | "instruction cache level %" PRIu32 " size %zi bytes\n", |
---|
| 326 | cache_level, |
---|
| 327 | cache_size |
---|
| 328 | ); |
---|
| 329 | ++cache_level; |
---|
| 330 | cache_size = rtems_cache_get_instruction_cache_size(cache_level); |
---|
| 331 | } |
---|
| 332 | |
---|
[d50acdbb] | 333 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 334 | |
---|
| 335 | d[0] = do_some_work(); |
---|
| 336 | d[1] = do_some_work(); |
---|
| 337 | rtems_cache_invalidate_entire_instruction(); |
---|
| 338 | d[2] = do_some_work(); |
---|
| 339 | |
---|
[d50acdbb] | 340 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 341 | |
---|
| 342 | printf( |
---|
| 343 | "invalidate entire instruction\n" |
---|
| 344 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 345 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 346 | " duration with invalidated cache %" PRIu64 " ns\n", |
---|
| 347 | d[0], |
---|
| 348 | d[1], |
---|
| 349 | d[2] |
---|
| 350 | ); |
---|
| 351 | |
---|
[d50acdbb] | 352 | rtems_interrupt_lock_acquire(&lock, &lock_context); |
---|
[3378be95] | 353 | |
---|
| 354 | d[0] = do_some_work(); |
---|
| 355 | d[1] = do_some_work(); |
---|
| 356 | rtems_cache_invalidate_multiple_instruction_lines(do_some_work, 4096); |
---|
| 357 | d[2] = do_some_work(); |
---|
| 358 | |
---|
[d50acdbb] | 359 | rtems_interrupt_lock_release(&lock, &lock_context); |
---|
[3378be95] | 360 | |
---|
| 361 | printf( |
---|
| 362 | "invalidate multiple instruction\n" |
---|
| 363 | " duration with normal cache %" PRIu64 " ns\n" |
---|
| 364 | " duration with warm cache %" PRIu64 " ns\n" |
---|
| 365 | " duration with invalidated cache %" PRIu64 " ns\n", |
---|
| 366 | d[0], |
---|
| 367 | d[1], |
---|
| 368 | d[2] |
---|
| 369 | ); |
---|
[28779c7] | 370 | |
---|
| 371 | rtems_interrupt_lock_destroy(&lock); |
---|
[3378be95] | 372 | } |
---|
| 373 | |
---|
| 374 | static void Init(rtems_task_argument arg) |
---|
| 375 | { |
---|
[6c0301d] | 376 | TEST_BEGIN(); |
---|
[3378be95] | 377 | |
---|
| 378 | test_data_flush_and_invalidate(); |
---|
| 379 | test_timing(); |
---|
| 380 | |
---|
[6c0301d] | 381 | TEST_END(); |
---|
[3378be95] | 382 | |
---|
| 383 | rtems_test_exit(0); |
---|
| 384 | } |
---|
| 385 | |
---|
| 386 | #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER |
---|
| 387 | #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER |
---|
| 388 | |
---|
| 389 | #define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM |
---|
| 390 | |
---|
| 391 | #define CONFIGURE_MAXIMUM_TASKS 1 |
---|
| 392 | |
---|
[6c0301d] | 393 | #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION |
---|
| 394 | |
---|
[3378be95] | 395 | #define CONFIGURE_RTEMS_INIT_TASKS_TABLE |
---|
| 396 | |
---|
| 397 | #define CONFIGURE_INIT |
---|
| 398 | |
---|
| 399 | #include <rtems/confdefs.h> |
---|