blob: a91b3fe9b4f5e9a7ef6d07b1da4a3d0f7adfcb3b [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* test.c - MemTest-86 Version 3.4
2 *
3 * Released under version 2 of the Gnu Public License.
4 * By Chris Brady
5 * ----------------------------------------------------
6 * MemTest86+ V5 Specific code (GPL V2.0)
7 * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
8 * http://www.canardpc.com - http://www.memtest.org
9 * Thanks to Passmark for calculate_chunk() and various comments !
10 */
Martin Roth4dcd13d2016-02-24 13:53:07 -080011
Martin Roth9b1b3352016-02-24 12:27:06 -080012#include "test.h"
13#include "config.h"
14#include "stdint.h"
15#include "cpuid.h"
16#include "smp.h"
Martin Roth74d881d2016-02-28 09:37:19 -080017#include "io.h"
Martin Roth9b1b3352016-02-24 12:27:06 -080018
19extern struct cpu_ident cpu_id;
20extern volatile int mstr_cpu;
21extern volatile int run_cpus;
22extern volatile int test;
23extern volatile int segs, bail;
24extern int test_ticks, nticks;
25extern struct tseq tseq[];
26extern void update_err_counts(void);
27extern void print_err_counts(void);
28void rand_seed( unsigned int seed1, unsigned int seed2, int me);
29ulong rand(int me);
30void poll_errors();
31
32static inline ulong roundup(ulong value, ulong mask)
33{
34 return (value + mask) & ~mask;
35}
36
37// start / end - return values for range to test
38// me - this threads CPU number
39// j - index into v->map for current segment we are testing
40// align - number of bytes to align each block to
41void calculate_chunk(ulong** start, ulong** end, int me, int j, int makeMultipleOf)
42{
43 ulong chunk;
44
45
46 // If we are only running 1 CPU then test the whole block
47 if (run_cpus == 1) {
48 *start = v->map[j].start;
49 *end = v->map[j].end;
Martin Roth4dcd13d2016-02-24 13:53:07 -080050 }
Martin Roth9b1b3352016-02-24 12:27:06 -080051 else{
52
53 // Divide the current segment by the number of CPUs
54 chunk = (ulong)v->map[j].end-(ulong)v->map[j].start;
55 chunk /= run_cpus;
Martin Roth4dcd13d2016-02-24 13:53:07 -080056
Martin Roth9b1b3352016-02-24 12:27:06 -080057 // Round down to the nearest desired bitlength multiple
58 chunk = (chunk + (makeMultipleOf-1)) & ~(makeMultipleOf-1);
59
60 // Figure out chunk boundaries
61 *start = (ulong*)((ulong)v->map[j].start+(chunk*me));
62 /* Set end addrs for the highest CPU num to the
63 * end of the segment for rounding errors */
64 // Also rounds down to boundary if needed, may miss some ram but better than crashing or producing false errors.
65 // This rounding probably will never happen as the segments should be in 4096 bytes pages if I understand correctly.
66 if (me == mstr_cpu) {
67 *end = (ulong*)(v->map[j].end);
68 } else {
69 *end = (ulong*)((ulong)(*start) + chunk);
70 (*end)--;
71 }
72 }
73}
74
75/*
76 * Memory address test, walking ones
77 */
78void addr_tst1(int me)
79{
80 int i, j, k;
81 volatile ulong *p, *pt, *end;
82 ulong bad, mask, bank, p1;
83
84 /* Test the global address bits */
85 for (p1=0, j=0; j<2; j++) {
86 hprint(LINE_PAT, COL_PAT, p1);
87
88 /* Set pattern in our lowest multiple of 0x20000 */
89 p = (ulong *)roundup((ulong)v->map[0].start, 0x1ffff);
90 *p = p1;
Martin Roth4dcd13d2016-02-24 13:53:07 -080091
Martin Roth9b1b3352016-02-24 12:27:06 -080092 /* Now write pattern compliment */
93 p1 = ~p1;
94 end = v->map[segs-1].end;
95 for (i=0; i<100; i++) {
96 mask = 4;
97 do {
98 pt = (ulong *)((ulong)p | mask);
99 if (pt == p) {
100 mask = mask << 1;
101 continue;
102 }
103 if (pt >= end) {
104 break;
105 }
106 *pt = p1;
107 if ((bad = *p) != ~p1) {
108 ad_err1((ulong *)p, (ulong *)mask,
109 bad, ~p1);
110 i = 1000;
111 }
112 mask = mask << 1;
113 } while(mask);
114 }
115 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600116 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800117 }
118
119 /* Now check the address bits in each bank */
120 /* If we have more than 8mb of memory then the bank size must be */
121 /* bigger than 256k. If so use 1mb for the bank size. */
122 if (v->pmap[v->msegs - 1].end > (0x800000 >> 12)) {
123 bank = 0x100000;
124 } else {
125 bank = 0x40000;
126 }
127 for (p1=0, k=0; k<2; k++) {
128 hprint(LINE_PAT, COL_PAT, p1);
129
130 for (j=0; j<segs; j++) {
131 p = v->map[j].start;
132 /* Force start address to be a multiple of 256k */
133 p = (ulong *)roundup((ulong)p, bank - 1);
134 end = v->map[j].end;
135 /* Redundant checks for overflow */
136 while (p < end && p > v->map[j].start && p != 0) {
137 *p = p1;
138
139 p1 = ~p1;
140 for (i=0; i<50; i++) {
141 mask = 4;
142 do {
143 pt = (ulong *)
144 ((ulong)p | mask);
145 if (pt == p) {
146 mask = mask << 1;
147 continue;
148 }
149 if (pt >= end) {
150 break;
151 }
152 *pt = p1;
153 if ((bad = *p) != ~p1) {
154 ad_err1((ulong *)p,
155 (ulong *)mask,
156 bad,~p1);
157 i = 200;
158 }
159 mask = mask << 1;
160 } while(mask);
161 }
162 if (p + bank > p) {
163 p += bank;
164 } else {
165 p = end;
166 }
167 p1 = ~p1;
168 }
169 }
170 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600171 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800172 p1 = ~p1;
173 }
174}
175
176/*
177 * Memory address test, own address
178 */
179void addr_tst2(int me)
180{
181 int j, done;
182 ulong *p, *pe, *end, *start;
183
184 cprint(LINE_PAT, COL_PAT, "address ");
185
186 /* Write each address with it's own address */
187 for (j=0; j<segs; j++) {
188 start = v->map[j].start;
189 end = v->map[j].end;
190 pe = (ulong *)start;
191 p = start;
192 done = 0;
193 do {
194 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600195 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800196
197 /* Check for overflow */
198 if (pe + SPINSZ > pe && pe != 0) {
199 pe += SPINSZ;
200 } else {
201 pe = end;
202 }
203 if (pe >= end) {
204 pe = end;
205 done++;
206 }
207 if (p == pe ) {
208 break;
209 }
210
211/* Original C code replaced with hand tuned assembly code
212 * for (; p <= pe; p++) {
213 * *p = (ulong)p;
214 * }
215 */
216 asm __volatile__ (
217 "jmp L91\n\t"
218 ".p2align 4,,7\n\t"
219 "L90:\n\t"
220 "addl $4,%%edi\n\t"
221 "L91:\n\t"
222 "movl %%edi,(%%edi)\n\t"
223 "cmpl %%edx,%%edi\n\t"
224 "jb L90\n\t"
225 : : "D" (p), "d" (pe)
226 );
227 p = pe + 1;
228 } while (!done);
229 }
230
231 /* Each address should have its own address */
232 for (j=0; j<segs; j++) {
233 start = v->map[j].start;
234 end = v->map[j].end;
235 pe = (ulong *)start;
236 p = start;
237 done = 0;
238 do {
239 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600240 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800241
242 /* Check for overflow */
243 if (pe + SPINSZ > pe && pe != 0) {
244 pe += SPINSZ;
245 } else {
246 pe = end;
247 }
248 if (pe >= end) {
249 pe = end;
250 done++;
251 }
252 if (p == pe ) {
253 break;
254 }
255/* Original C code replaced with hand tuned assembly code
256 * for (; p <= pe; p++) {
257 * if((bad = *p) != (ulong)p) {
258 * ad_err2((ulong)p, bad);
259 * }
260 * }
261 */
262 asm __volatile__ (
263 "jmp L95\n\t"
264 ".p2align 4,,7\n\t"
265 "L99:\n\t"
266 "addl $4,%%edi\n\t"
267 "L95:\n\t"
268 "movl (%%edi),%%ecx\n\t"
269 "cmpl %%edi,%%ecx\n\t"
270 "jne L97\n\t"
271 "L96:\n\t"
272 "cmpl %%edx,%%edi\n\t"
273 "jb L99\n\t"
274 "jmp L98\n\t"
Martin Roth4dcd13d2016-02-24 13:53:07 -0800275
Martin Roth9b1b3352016-02-24 12:27:06 -0800276 "L97:\n\t"
277 "pushl %%edx\n\t"
278 "pushl %%ecx\n\t"
279 "pushl %%edi\n\t"
280 "call ad_err2\n\t"
281 "popl %%edi\n\t"
282 "popl %%ecx\n\t"
283 "popl %%edx\n\t"
284 "jmp L96\n\t"
285
286 "L98:\n\t"
287 : : "D" (p), "d" (pe)
288 : "ecx"
289 );
290 p = pe + 1;
291 } while (!done);
292 }
293}
294
295/*
296 * Test all of memory using a "half moving inversions" algorithm using random
297 * numbers and their complment as the data pattern. Since we are not able to
298 * produce random numbers in reverse order testing is only done in the forward
299 * direction.
300 */
301void movinvr(int me)
302{
303 int i, j, done, seed1, seed2;
304 ulong *p;
305 ulong *pe;
306 ulong *start,*end;
307 ulong xorVal;
308 //ulong num, bad;
309
310 /* Initialize memory with initial sequence of random numbers. */
311 if (cpu_id.fid.bits.rdtsc) {
312 asm __volatile__ ("rdtsc":"=a" (seed1),"=d" (seed2));
313 } else {
314 seed1 = 521288629 + v->pass;
315 seed2 = 362436069 - v->pass;
316 }
317
318 /* Display the current seed */
319 if (mstr_cpu == me) hprint(LINE_PAT, COL_PAT, seed1);
320 rand_seed(seed1, seed2, me);
321 for (j=0; j<segs; j++) {
322 calculate_chunk(&start, &end, me, j, 4);
323 pe = start;
324 p = start;
325 done = 0;
326 do {
327 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600328 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800329
330 /* Check for overflow */
331 if (pe + SPINSZ > pe && pe != 0) {
332 pe += SPINSZ;
333 } else {
334 pe = end;
335 }
336 if (pe >= end) {
337 pe = end;
338 done++;
339 }
340 if (p == pe ) {
341 break;
342 }
343/* Original C code replaced with hand tuned assembly code */
344/*
345 for (; p <= pe; p++) {
346 *p = rand(me);
347 }
348 */
349
350 asm __volatile__ (
351 "jmp L200\n\t"
352 ".p2align 4,,7\n\t"
353 "L201:\n\t"
354 "addl $4,%%edi\n\t"
355 "L200:\n\t"
356 "pushl %%ecx\n\t" \
357 "call rand\n\t"
358 "popl %%ecx\n\t" \
359 "movl %%eax,(%%edi)\n\t"
360 "cmpl %%ebx,%%edi\n\t"
361 "jb L201\n\t"
362 : : "D" (p), "b" (pe), "c" (me)
363 : "eax"
364 );
365 p = pe + 1;
366 } while (!done);
367 }
368
369 /* Do moving inversions test. Check for initial pattern and then
370 * write the complement for each memory location.
371 */
372 for (i=0; i<2; i++) {
373 rand_seed(seed1, seed2, me);
374 for (j=0; j<segs; j++) {
375 calculate_chunk(&start, &end, me, j, 4);
376 pe = start;
377 p = start;
378 done = 0;
379 do {
380 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600381 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800382
383 /* Check for overflow */
384 if (pe + SPINSZ > pe && pe != 0) {
385 pe += SPINSZ;
386 } else {
387 pe = end;
388 }
389 if (pe >= end) {
390 pe = end;
391 done++;
392 }
393 if (p == pe ) {
394 break;
395 }
396/* Original C code replaced with hand tuned assembly code */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800397
Martin Roth9b1b3352016-02-24 12:27:06 -0800398 /*for (; p <= pe; p++) {
399 num = rand(me);
400 if (i) {
401 num = ~num;
402 }
403 if ((bad=*p) != num) {
404 error((ulong*)p, num, bad);
405 }
406 *p = ~num;
407 }*/
408
409 if (i) {
410 xorVal = 0xffffffff;
411 } else {
412 xorVal = 0;
413 }
414 asm __volatile__ (
Martin Roth4dcd13d2016-02-24 13:53:07 -0800415
Martin Roth9b1b3352016-02-24 12:27:06 -0800416 "pushl %%ebp\n\t"
417
418 // Skip first increment
419 "jmp L26\n\t"
420 ".p2align 4,,7\n\t"
421
422 // increment 4 bytes (32-bits)
423 "L27:\n\t"
424 "addl $4,%%edi\n\t"
425
426 // Check this byte
427 "L26:\n\t"
428
429 // Get next random number, pass in me(edx), random value returned in num(eax)
430 // num = rand(me);
431 // cdecl call maintains all registers except eax, ecx, and edx
432 // We maintain edx with a push and pop here using it also as an input
433 // we don't need the current eax value and want it to change to the return value
434 // we overwrite ecx shortly after this discarding its current value
435 "pushl %%edx\n\t" // Push function inputs onto stack
436 "call rand\n\t"
437 "popl %%edx\n\t" // Remove function inputs from stack
438
439 // XOR the random number with xorVal(ebx), which is either 0xffffffff or 0 depending on the outer loop
440 // if (i) { num = ~num; }
441 "xorl %%ebx,%%eax\n\t"
442
443 // Move the current value of the current position p(edi) into bad(ecx)
444 // (bad=*p)
445 "movl (%%edi),%%ecx\n\t"
446
447 // Compare bad(ecx) to num(eax)
448 "cmpl %%eax,%%ecx\n\t"
449
450 // If not equal jump the error case
451 "jne L23\n\t"
452
453 // Set a new value or not num(eax) at the current position p(edi)
454 // *p = ~num;
455 "L25:\n\t"
456 "movl $0xffffffff,%%ebp\n\t"
457 "xorl %%ebp,%%eax\n\t"
458 "movl %%eax,(%%edi)\n\t"
459
460 // Loop until current position p(edi) equals the end position pe(esi)
461 "cmpl %%esi,%%edi\n\t"
462 "jb L27\n\t"
463 "jmp L24\n"
464
465 // Error case
466 "L23:\n\t"
467 // Must manually maintain eax, ecx, and edx as part of cdecl call convention
468 "pushl %%edx\n\t"
469 "pushl %%ecx\n\t" // Next three pushes are functions input
470 "pushl %%eax\n\t"
471 "pushl %%edi\n\t"
472 "call error\n\t"
473 "popl %%edi\n\t" // Remove function inputs from stack and restore register values
474 "popl %%eax\n\t"
475 "popl %%ecx\n\t"
476 "popl %%edx\n\t"
Martin Roth4dcd13d2016-02-24 13:53:07 -0800477 "jmp L25\n"
Martin Roth9b1b3352016-02-24 12:27:06 -0800478
479 "L24:\n\t"
480 "popl %%ebp\n\t"
481 :: "D" (p), "S" (pe), "b" (xorVal),
482 "d" (me)
483 : "eax", "ecx"
484 );
485 p = pe + 1;
486 } while (!done);
487 }
488 }
489}
490
491/*
492 * Test all of memory using a "moving inversions" algorithm using the
493 * pattern in p1 and it's complement in p2.
494 */
495void movinv1 (int iter, ulong p1, ulong p2, int me)
496{
497 int i, j, done;
498 ulong *p, *pe, len, *start, *end;
499
500 /* Display the current pattern */
501 if (mstr_cpu == me) hprint(LINE_PAT, COL_PAT, p1);
502
503 /* Initialize memory with the initial pattern. */
504 for (j=0; j<segs; j++) {
505 calculate_chunk(&start, &end, me, j, 4);
506
507
508 pe = start;
509 p = start;
510 done = 0;
511 do {
512 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600513 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800514
515 /* Check for overflow */
516 if (pe + SPINSZ > pe && pe != 0) {
517 pe += SPINSZ;
518 } else {
519 pe = end;
520 }
521 if (pe >= end) {
522 pe = end;
523 done++;
524 }
525 len = pe - p + 1;
526 if (p == pe ) {
527 break;
528 }
529
530 //Original C code replaced with hand tuned assembly code
531 // seems broken
532 /*for (; p <= pe; p++) {
533 *p = p1;
534 }*/
535
536 asm __volatile__ (
537 "rep\n\t" \
538 "stosl\n\t"
539 : : "c" (len), "D" (p), "a" (p1)
540 );
541
542 p = pe + 1;
543 } while (!done);
544 }
545
546 /* Do moving inversions test. Check for initial pattern and then
547 * write the complement for each memory location. Test from bottom
548 * up and then from the top down. */
549 for (i=0; i<iter; i++) {
550 for (j=0; j<segs; j++) {
551 calculate_chunk(&start, &end, me, j, 4);
552 pe = start;
553 p = start;
554 done = 0;
555 do {
556 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600557 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800558
559 /* Check for overflow */
560 if (pe + SPINSZ > pe && pe != 0) {
561 pe += SPINSZ;
562 } else {
563 pe = end;
564 }
565 if (pe >= end) {
566 pe = end;
567 done++;
568 }
569 if (p == pe ) {
570 break;
571 }
572
Martin Roth4dcd13d2016-02-24 13:53:07 -0800573 // Original C code replaced with hand tuned assembly code
Martin Roth9b1b3352016-02-24 12:27:06 -0800574 // seems broken
575 /*for (; p <= pe; p++) {
576 if ((bad=*p) != p1) {
577 error((ulong*)p, p1, bad);
578 }
579 *p = p2;
580 }*/
581
582 asm __volatile__ (
583 "jmp L2\n\t" \
584 ".p2align 4,,7\n\t" \
585 "L0:\n\t" \
586 "addl $4,%%edi\n\t" \
587 "L2:\n\t" \
588 "movl (%%edi),%%ecx\n\t" \
589 "cmpl %%eax,%%ecx\n\t" \
590 "jne L3\n\t" \
591 "L5:\n\t" \
592 "movl %%ebx,(%%edi)\n\t" \
593 "cmpl %%edx,%%edi\n\t" \
594 "jb L0\n\t" \
595 "jmp L4\n" \
596
597 "L3:\n\t" \
598 "pushl %%edx\n\t" \
599 "pushl %%ebx\n\t" \
600 "pushl %%ecx\n\t" \
601 "pushl %%eax\n\t" \
602 "pushl %%edi\n\t" \
603 "call error\n\t" \
604 "popl %%edi\n\t" \
605 "popl %%eax\n\t" \
606 "popl %%ecx\n\t" \
607 "popl %%ebx\n\t" \
608 "popl %%edx\n\t" \
609 "jmp L5\n" \
610
611 "L4:\n\t" \
612 :: "a" (p1), "D" (p), "d" (pe), "b" (p2)
613 : "ecx"
614 );
615 p = pe + 1;
616 } while (!done);
617 }
618 for (j=segs-1; j>=0; j--) {
619 calculate_chunk(&start, &end, me, j, 4);
620 pe = end;
621 p = end;
622 done = 0;
623 do {
624 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600625 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800626
627 /* Check for underflow */
628 if (pe - SPINSZ < pe && pe != 0) {
629 pe -= SPINSZ;
630 } else {
631 pe = start;
632 done++;
633 }
634
Martin Roth4dcd13d2016-02-24 13:53:07 -0800635 /* Since we are using unsigned addresses a
Martin Roth9b1b3352016-02-24 12:27:06 -0800636 * redundent check is required */
637 if (pe < start || pe > end) {
638 pe = start;
639 done++;
640 }
641 if (p == pe ) {
642 break;
643 }
644
645 //Original C code replaced with hand tuned assembly code
646 // seems broken
647 /*do {
648 if ((bad=*p) != p2) {
649 error((ulong*)p, p2, bad);
650 }
651 *p = p1;
652 } while (--p >= pe);*/
653
654 asm __volatile__ (
655 "jmp L9\n\t"
656 ".p2align 4,,7\n\t"
657 "L11:\n\t"
658 "subl $4, %%edi\n\t"
659 "L9:\n\t"
660 "movl (%%edi),%%ecx\n\t"
661 "cmpl %%ebx,%%ecx\n\t"
662 "jne L6\n\t"
663 "L10:\n\t"
664 "movl %%eax,(%%edi)\n\t"
665 "cmpl %%edi, %%edx\n\t"
666 "jne L11\n\t"
667 "jmp L7\n\t"
668
669 "L6:\n\t"
670 "pushl %%edx\n\t"
671 "pushl %%eax\n\t"
672 "pushl %%ecx\n\t"
673 "pushl %%ebx\n\t"
674 "pushl %%edi\n\t"
675 "call error\n\t"
676 "popl %%edi\n\t"
677 "popl %%ebx\n\t"
678 "popl %%ecx\n\t"
679 "popl %%eax\n\t"
680 "popl %%edx\n\t"
681 "jmp L10\n"
682
683 "L7:\n\t"
684 :: "a" (p1), "D" (p), "d" (pe), "b" (p2)
685 : "ecx"
686 );
687 p = pe - 1;
688 } while (!done);
689 }
690 }
691}
692
693void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off,int me)
694{
695 int i, j, k=0, n=0, done;
696 ulong *p, *pe, *start, *end, pat = 0, p3;
697
698 p3 = sval << 31;
699 /* Display the current pattern */
700 if (mstr_cpu == me) hprint(LINE_PAT, COL_PAT, p1);
701
702 /* Initialize memory with the initial pattern. */
703 for (j=0; j<segs; j++) {
704 calculate_chunk(&start, &end, me, j, 64);
705 pe = start;
706 p = start;
707 done = 0;
708 k = off;
709 pat = p1;
710 do {
711 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600712 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800713
714 /* Check for overflow */
715 if (pe + SPINSZ > pe && pe != 0) {
716 pe += SPINSZ;
717 } else {
718 pe = end;
719 }
720 if (pe >= end) {
721 pe = end;
722 done++;
723 }
724 if (p == pe ) {
725 break;
726 }
727 /* Do a SPINSZ section of memory */
728/* Original C code replaced with hand tuned assembly code
729 * while (p <= pe) {
730 * *p = pat;
731 * if (++k >= 32) {
732 * pat = lb;
733 * k = 0;
734 * } else {
735 * pat = pat << 1;
736 * pat |= sval;
737 * }
738 * p++;
739 * }
740 */
741 asm __volatile__ (
742 "jmp L20\n\t"
743 ".p2align 4,,7\n\t"
744 "L923:\n\t"
745 "addl $4,%%edi\n\t"
746 "L20:\n\t"
747 "movl %%ecx,(%%edi)\n\t"
748 "addl $1,%%ebx\n\t"
749 "cmpl $32,%%ebx\n\t"
750 "jne L21\n\t"
751 "movl %%esi,%%ecx\n\t"
752 "xorl %%ebx,%%ebx\n\t"
753 "jmp L22\n"
754 "L21:\n\t"
755 "shll $1,%%ecx\n\t"
756 "orl %%eax,%%ecx\n\t"
757 "L22:\n\t"
758 "cmpl %%edx,%%edi\n\t"
759 "jb L923\n\t"
760 : "=b" (k), "=c" (pat)
761 : "D" (p),"d" (pe),"b" (k),"c" (pat),
762 "a" (sval), "S" (lb)
763 );
764 p = pe + 1;
765 } while (!done);
766 }
767
768 /* Do moving inversions test. Check for initial pattern and then
769 * write the complement for each memory location. Test from bottom
770 * up and then from the top down. */
771 for (i=0; i<iter; i++) {
772 for (j=0; j<segs; j++) {
773 calculate_chunk(&start, &end, me, j, 64);
774 pe = start;
775 p = start;
776 done = 0;
777 k = off;
778 pat = p1;
779 do {
780 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600781 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800782
783 /* Check for overflow */
784 if (pe + SPINSZ > pe && pe != 0) {
785 pe += SPINSZ;
786 } else {
787 pe = end;
788 }
789 if (pe >= end) {
790 pe = end;
791 done++;
792 }
793 if (p == pe ) {
794 break;
795 }
796/* Original C code replaced with hand tuned assembly code
797 * while (1) {
798 * if ((bad=*p) != pat) {
799 * error((ulong*)p, pat, bad);
800 * }
801 * *p = ~pat;
802 * if (p >= pe) break;
803 * p++;
804 *
805 * if (++k >= 32) {
806 * pat = lb;
807 * k = 0;
808 * } else {
809 * pat = pat << 1;
810 * pat |= sval;
811 * }
812 * }
813 */
814 asm __volatile__ (
815 "pushl %%ebp\n\t"
816 "jmp L30\n\t"
817 ".p2align 4,,7\n\t"
818 "L930:\n\t"
819 "addl $4,%%edi\n\t"
820 "L30:\n\t"
821 "movl (%%edi),%%ebp\n\t"
822 "cmpl %%ecx,%%ebp\n\t"
823 "jne L34\n\t"
824
825 "L35:\n\t"
826 "notl %%ecx\n\t"
827 "movl %%ecx,(%%edi)\n\t"
828 "notl %%ecx\n\t"
829 "incl %%ebx\n\t"
830 "cmpl $32,%%ebx\n\t"
831 "jne L31\n\t"
832 "movl %%esi,%%ecx\n\t"
833 "xorl %%ebx,%%ebx\n\t"
834 "jmp L32\n"
835 "L31:\n\t"
836 "shll $1,%%ecx\n\t"
837 "orl %%eax,%%ecx\n\t"
838 "L32:\n\t"
839 "cmpl %%edx,%%edi\n\t"
840 "jb L930\n\t"
841 "jmp L33\n\t"
842
843 "L34:\n\t" \
844 "pushl %%esi\n\t"
845 "pushl %%eax\n\t"
846 "pushl %%ebx\n\t"
847 "pushl %%edx\n\t"
848 "pushl %%ebp\n\t"
849 "pushl %%ecx\n\t"
850 "pushl %%edi\n\t"
851 "call error\n\t"
852 "popl %%edi\n\t"
853 "popl %%ecx\n\t"
854 "popl %%ebp\n\t"
855 "popl %%edx\n\t"
856 "popl %%ebx\n\t"
857 "popl %%eax\n\t"
858 "popl %%esi\n\t"
859 "jmp L35\n"
860
861 "L33:\n\t"
862 "popl %%ebp\n\t"
863 : "=b" (k),"=c" (pat)
864 : "D" (p),"d" (pe),"b" (k),"c" (pat),
865 "a" (sval), "S" (lb)
866 );
867 p = pe + 1;
868 } while (!done);
869 }
870
871 if (--k < 0) {
872 k = 31;
873 }
874 for (pat = lb, n = 0; n < k; n++) {
875 pat = pat << 1;
876 pat |= sval;
877 }
878 k++;
879
880 for (j=segs-1; j>=0; j--) {
881 calculate_chunk(&start, &end, me, j, 64);
882 p = end;
883 pe = end;
884 done = 0;
885 do {
886 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -0600887 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -0800888
889 /* Check for underflow */
890 if (pe - SPINSZ < pe && pe != 0) {
891 pe -= SPINSZ;
892 } else {
893 pe = start;
894 done++;
895 }
896 /* We need this redundant check because we are
897 * using unsigned longs for the address.
898 */
899 if (pe < start || pe > end) {
900 pe = start;
901 done++;
902 }
903 if (p == pe ) {
904 break;
905 }
906/* Original C code replaced with hand tuned assembly code
907 * while(1) {
908 * if ((bad=*p) != ~pat) {
909 * error((ulong*)p, ~pat, bad);
910 * }
911 * *p = pat;
912 if (p >= pe) break;
913 p++;
914 * if (--k <= 0) {
915 * pat = hb;
916 * k = 32;
917 * } else {
918 * pat = pat >> 1;
919 * pat |= p3;
920 * }
921 * };
922 */
923 asm __volatile__ (
924 "pushl %%ebp\n\t"
925 "jmp L40\n\t"
926 ".p2align 4,,7\n\t"
927 "L49:\n\t"
928 "subl $4,%%edi\n\t"
929 "L40:\n\t"
930 "movl (%%edi),%%ebp\n\t"
931 "notl %%ecx\n\t"
932 "cmpl %%ecx,%%ebp\n\t"
933 "jne L44\n\t"
934
935 "L45:\n\t"
936 "notl %%ecx\n\t"
937 "movl %%ecx,(%%edi)\n\t"
938 "decl %%ebx\n\t"
939 "cmpl $0,%%ebx\n\t"
940 "jg L41\n\t"
941 "movl %%esi,%%ecx\n\t"
942 "movl $32,%%ebx\n\t"
943 "jmp L42\n"
944 "L41:\n\t"
945 "shrl $1,%%ecx\n\t"
946 "orl %%eax,%%ecx\n\t"
947 "L42:\n\t"
948 "cmpl %%edx,%%edi\n\t"
949 "ja L49\n\t"
950 "jmp L43\n\t"
951
952 "L44:\n\t" \
953 "pushl %%esi\n\t"
954 "pushl %%eax\n\t"
955 "pushl %%ebx\n\t"
956 "pushl %%edx\n\t"
957 "pushl %%ebp\n\t"
958 "pushl %%ecx\n\t"
959 "pushl %%edi\n\t"
960 "call error\n\t"
961 "popl %%edi\n\t"
962 "popl %%ecx\n\t"
963 "popl %%ebp\n\t"
964 "popl %%edx\n\t"
965 "popl %%ebx\n\t"
966 "popl %%eax\n\t"
967 "popl %%esi\n\t"
968 "jmp L45\n"
969
970 "L43:\n\t"
971 "popl %%ebp\n\t"
972 : "=b" (k), "=c" (pat)
973 : "D" (p),"d" (pe),"b" (k),"c" (pat),
974 "a" (p3), "S" (hb)
975 );
976 p = pe - 1;
977 } while (!done);
978 }
979 }
980}
981
982/*
983 * Test all of memory using modulo X access pattern.
984 */
985void modtst(int offset, int iter, ulong p1, ulong p2, int me)
986{
987 int j, k, l, done;
988 ulong *p;
989 ulong *pe;
990 ulong *start, *end;
991
992 /* Display the current pattern */
993 if (mstr_cpu == me) {
994 hprint(LINE_PAT, COL_PAT-2, p1);
995 cprint(LINE_PAT, COL_PAT+6, "-");
996 dprint(LINE_PAT, COL_PAT+7, offset, 2, 1);
997 }
998
999 /* Write every nth location with pattern */
1000 for (j=0; j<segs; j++) {
1001 calculate_chunk(&start, &end, me, j, 4);
1002 end -= MOD_SZ; /* adjust the ending address */
1003 pe = (ulong *)start;
1004 p = start+offset;
1005 done = 0;
1006 do {
1007 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001008 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001009
1010 /* Check for overflow */
1011 if (pe + SPINSZ > pe && pe != 0) {
1012 pe += SPINSZ;
1013 } else {
1014 pe = end;
1015 }
1016 if (pe >= end) {
1017 pe = end;
1018 done++;
1019 }
1020 if (p == pe ) {
1021 break;
1022 }
1023/* Original C code replaced with hand tuned assembly code
1024 * for (; p <= pe; p += MOD_SZ) {
1025 * *p = p1;
1026 * }
1027 */
1028 asm __volatile__ (
1029 "jmp L60\n\t" \
1030 ".p2align 4,,7\n\t" \
1031
1032 "L60:\n\t" \
1033 "movl %%eax,(%%edi)\n\t" \
1034 "addl $80,%%edi\n\t" \
1035 "cmpl %%edx,%%edi\n\t" \
1036 "jb L60\n\t" \
1037 : "=D" (p)
1038 : "D" (p), "d" (pe), "a" (p1)
1039 );
1040 } while (!done);
1041 }
1042
1043 /* Write the rest of memory "iter" times with the pattern complement */
1044 for (l=0; l<iter; l++) {
1045 for (j=0; j<segs; j++) {
1046 calculate_chunk(&start, &end, me, j, 4);
1047 pe = (ulong *)start;
1048 p = start;
1049 done = 0;
1050 k = 0;
1051 do {
1052 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001053 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001054
1055 /* Check for overflow */
1056 if (pe + SPINSZ > pe && pe != 0) {
1057 pe += SPINSZ;
1058 } else {
1059 pe = end;
1060 }
1061 if (pe >= end) {
1062 pe = end;
1063 done++;
1064 }
1065 if (p == pe ) {
1066 break;
1067 }
1068/* Original C code replaced with hand tuned assembly code
1069 * for (; p <= pe; p++) {
1070 * if (k != offset) {
1071 * *p = p2;
1072 * }
1073 * if (++k > MOD_SZ-1) {
1074 * k = 0;
1075 * }
1076 * }
1077 */
1078 asm __volatile__ (
1079 "jmp L50\n\t" \
1080 ".p2align 4,,7\n\t" \
1081
1082 "L54:\n\t" \
1083 "addl $4,%%edi\n\t" \
1084 "L50:\n\t" \
1085 "cmpl %%ebx,%%ecx\n\t" \
1086 "je L52\n\t" \
1087 "movl %%eax,(%%edi)\n\t" \
1088 "L52:\n\t" \
1089 "incl %%ebx\n\t" \
1090 "cmpl $19,%%ebx\n\t" \
1091 "jle L53\n\t" \
1092 "xorl %%ebx,%%ebx\n\t" \
1093 "L53:\n\t" \
1094 "cmpl %%edx,%%edi\n\t" \
1095 "jb L54\n\t" \
1096 : "=b" (k)
1097 : "D" (p), "d" (pe), "a" (p2),
1098 "b" (k), "c" (offset)
1099 );
1100 p = pe + 1;
1101 } while (!done);
1102 }
1103 }
1104
1105 /* Now check every nth location */
1106 for (j=0; j<segs; j++) {
1107 calculate_chunk(&start, &end, me, j, 4);
1108 pe = (ulong *)start;
1109 p = start+offset;
1110 done = 0;
1111 end -= MOD_SZ; /* adjust the ending address */
1112 do {
1113 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001114 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001115
1116 /* Check for overflow */
1117 if (pe + SPINSZ > pe && pe != 0) {
1118 pe += SPINSZ;
1119 } else {
1120 pe = end;
1121 }
1122 if (pe >= end) {
1123 pe = end;
1124 done++;
1125 }
1126 if (p == pe ) {
1127 break;
1128 }
1129/* Original C code replaced with hand tuned assembly code
1130 * for (; p <= pe; p += MOD_SZ) {
1131 * if ((bad=*p) != p1) {
1132 * error((ulong*)p, p1, bad);
1133 * }
1134 * }
1135 */
1136 asm __volatile__ (
1137 "jmp L70\n\t" \
1138 ".p2align 4,,7\n\t" \
1139
1140 "L70:\n\t" \
1141 "movl (%%edi),%%ecx\n\t" \
1142 "cmpl %%eax,%%ecx\n\t" \
1143 "jne L71\n\t" \
1144 "L72:\n\t" \
1145 "addl $80,%%edi\n\t" \
1146 "cmpl %%edx,%%edi\n\t" \
1147 "jb L70\n\t" \
1148 "jmp L73\n\t" \
1149
1150 "L71:\n\t" \
1151 "pushl %%edx\n\t"
1152 "pushl %%ecx\n\t"
1153 "pushl %%eax\n\t"
1154 "pushl %%edi\n\t"
1155 "call error\n\t"
1156 "popl %%edi\n\t"
1157 "popl %%eax\n\t"
1158 "popl %%ecx\n\t"
1159 "popl %%edx\n\t"
1160 "jmp L72\n"
1161
1162 "L73:\n\t" \
1163 : "=D" (p)
1164 : "D" (p), "d" (pe), "a" (p1)
1165 : "ecx"
1166 );
1167 } while (!done);
1168 }
1169}
1170
1171/*
Martin Roth4dcd13d2016-02-24 13:53:07 -08001172 * Test memory using block moves
Martin Roth9b1b3352016-02-24 12:27:06 -08001173 * Adapted from Robert Redelmeier's burnBX test
1174 */
1175void block_move(int iter, int me)
1176{
1177 int i, j, done;
1178 ulong len;
1179 ulong *p, *pe, pp;
1180 ulong *start, *end;
1181
1182 cprint(LINE_PAT, COL_PAT-2, " ");
1183
1184 /* Initialize memory with the initial pattern. */
1185 for (j=0; j<segs; j++) {
1186 calculate_chunk(&start, &end, me, j, 64);
1187
1188 // end is always xxxxxffc, so increment so that length calculations are correct
1189 end = end + 1;
1190
1191 pe = start;
1192 p = start;
1193
1194 done = 0;
1195 do {
1196 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001197 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001198
1199 /* Check for overflow */
1200 if (pe + SPINSZ > pe && pe != 0) {
1201 pe += SPINSZ;
1202 } else {
1203 pe = end;
1204 }
Martin Roth5ca4eb92018-01-13 15:17:26 -08001205 if ((pe >= end && end != 0) || (pe < p && end == 0)) {
Martin Roth9b1b3352016-02-24 12:27:06 -08001206 pe = end;
1207 done++;
1208 }
1209 if (p == pe ) {
1210 break;
1211 }
1212 len = ((ulong)pe - (ulong)p) / 64;
1213 //len++;
1214 asm __volatile__ (
1215 "jmp L100\n\t"
1216
1217 ".p2align 4,,7\n\t"
1218 "L100:\n\t"
1219
1220 // First loop eax is 0x00000001, edx is 0xfffffffe
1221 "movl %%eax, %%edx\n\t"
1222 "notl %%edx\n\t"
1223
Martin Roth4dcd13d2016-02-24 13:53:07 -08001224 // Set a block of 64-bytes // First loop DWORDS are
Martin Roth9b1b3352016-02-24 12:27:06 -08001225 "movl %%eax,0(%%edi)\n\t" // 0x00000001
1226 "movl %%eax,4(%%edi)\n\t" // 0x00000001
1227 "movl %%eax,8(%%edi)\n\t" // 0x00000001
1228 "movl %%eax,12(%%edi)\n\t" // 0x00000001
1229 "movl %%edx,16(%%edi)\n\t" // 0xfffffffe
1230 "movl %%edx,20(%%edi)\n\t" // 0xfffffffe
1231 "movl %%eax,24(%%edi)\n\t" // 0x00000001
1232 "movl %%eax,28(%%edi)\n\t" // 0x00000001
1233 "movl %%eax,32(%%edi)\n\t" // 0x00000001
1234 "movl %%eax,36(%%edi)\n\t" // 0x00000001
1235 "movl %%edx,40(%%edi)\n\t" // 0xfffffffe
1236 "movl %%edx,44(%%edi)\n\t" // 0xfffffffe
1237 "movl %%eax,48(%%edi)\n\t" // 0x00000001
1238 "movl %%eax,52(%%edi)\n\t" // 0x00000001
1239 "movl %%edx,56(%%edi)\n\t" // 0xfffffffe
1240 "movl %%edx,60(%%edi)\n\t" // 0xfffffffe
1241
Martin Roth4dcd13d2016-02-24 13:53:07 -08001242 // rotate left with carry,
Martin Roth9b1b3352016-02-24 12:27:06 -08001243 // second loop eax is 0x00000002
1244 // second loop edx is (~eax) 0xfffffffd
Martin Roth4dcd13d2016-02-24 13:53:07 -08001245 "rcll $1, %%eax\n\t"
1246
Martin Roth9b1b3352016-02-24 12:27:06 -08001247 // Move current position forward 64-bytes (to start of next block)
1248 "leal 64(%%edi), %%edi\n\t"
1249
1250 // Loop until end
1251 "decl %%ecx\n\t"
1252 "jnz L100\n\t"
1253
1254 : "=D" (p)
1255 : "D" (p), "c" (len), "a" (1)
1256 : "edx"
1257 );
1258 } while (!done);
1259 }
1260 s_barrier();
1261
Martin Roth4dcd13d2016-02-24 13:53:07 -08001262 /* Now move the data around
Martin Roth9b1b3352016-02-24 12:27:06 -08001263 * First move the data up half of the segment size we are testing
1264 * Then move the data to the original location + 32 bytes
1265 */
1266 for (j=0; j<segs; j++) {
1267 calculate_chunk(&start, &end, me, j, 64);
1268
1269 // end is always xxxxxffc, so increment so that length calculations are correct
1270 end = end + 1;
1271 pe = start;
1272 p = start;
1273 done = 0;
1274
1275 do {
1276
1277 /* Check for overflow */
1278 if (pe + SPINSZ > pe && pe != 0) {
1279 pe += SPINSZ;
1280 } else {
1281 pe = end;
1282 }
Martin Roth5ca4eb92018-01-13 15:17:26 -08001283 if ((pe >= end && end != 0) || (pe < p && end == 0)) {
Martin Roth9b1b3352016-02-24 12:27:06 -08001284 pe = end;
1285 done++;
1286 }
1287 if (p == pe ) {
1288 break;
1289 }
1290 pp = (ulong)p + (((ulong)pe - (ulong)p) / 2); // Mid-point of this block
1291 len = ((ulong)pe - (ulong)p) / 8; // Half the size of this block in DWORDS
1292 for(i=0; i<iter; i++) {
1293 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001294 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001295 asm __volatile__ (
1296 "cld\n"
1297 "jmp L110\n\t"
1298
1299 ".p2align 4,,7\n\t"
1300 "L110:\n\t"
1301
1302 //
Martin Roth4dcd13d2016-02-24 13:53:07 -08001303 // At the end of all this
Elyes HAOUAS54506bf2018-08-24 09:17:59 +02001304 // - the second half equals the initial value of the first half
Martin Roth9b1b3352016-02-24 12:27:06 -08001305 // - the first half is right shifted 32-bytes (with wrapping)
1306 //
1307
1308 // Move first half to second half
Elyes HAOUAS54506bf2018-08-24 09:17:59 +02001309 "movl %1,%%edi\n\t" // Destination, pp (mid point)
Martin Roth9b1b3352016-02-24 12:27:06 -08001310 "movl %0,%%esi\n\t" // Source, p (start point)
1311 "movl %2,%%ecx\n\t" // Length, len (size of a half in DWORDS)
1312 "rep\n\t"
1313 "movsl\n\t"
1314
1315 // Move the second half, less the last 32-bytes. To the first half, offset plus 32-bytes
1316 "movl %0,%%edi\n\t"
1317 "addl $32,%%edi\n\t" // Destination, p(start-point) plus 32 bytes
1318 "movl %1,%%esi\n\t" // Source, pp(mid-point)
1319 "movl %2,%%ecx\n\t"
1320 "subl $8,%%ecx\n\t" // Length, len(size of a half in DWORDS) minus 8 DWORDS (32 bytes)
1321 "rep\n\t"
1322 "movsl\n\t"
1323
1324 // Move last 8 DWORDS (32-bytes) of the second half to the start of the first half
1325 "movl %0,%%edi\n\t" // Destination, p(start-point)
1326 // Source, 8 DWORDS from the end of the second half, left over by the last rep/movsl
1327 "movl $8,%%ecx\n\t" // Length, 8 DWORDS (32-bytes)
1328 "rep\n\t"
1329 "movsl\n\t"
1330
1331 :: "g" (p), "g" (pp), "g" (len)
1332 : "edi", "esi", "ecx"
1333 );
1334 }
1335 p = pe;
1336 } while (!done);
1337 }
1338 s_barrier();
1339
Martin Roth4dcd13d2016-02-24 13:53:07 -08001340 /* Now check the data
Martin Roth9b1b3352016-02-24 12:27:06 -08001341 * The error checking is rather crude. We just check that the
1342 * adjacent words are the same.
1343 */
1344 for (j=0; j<segs; j++) {
1345 calculate_chunk(&start, &end, me, j, 64);
1346
1347 // end is always xxxxxffc, so increment so that length calculations are correct
1348 end = end + 1;
1349 pe = start;
1350 p = start;
1351 done = 0;
1352 do {
1353 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001354 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001355
1356 /* Check for overflow */
1357 if (pe + SPINSZ > pe && pe != 0) {
1358 pe += SPINSZ;
1359 } else {
1360 pe = end;
1361 }
Martin Roth5ca4eb92018-01-13 15:17:26 -08001362 if ((pe >= end && end != 0) || (pe < p && end == 0)) {
Martin Roth9b1b3352016-02-24 12:27:06 -08001363 pe = end;
1364 done++;
1365 }
1366 if (p == pe ) {
1367 break;
1368 }
1369 pe-=2; /* the last dwords to test are pe[0] and pe[1] */
1370 asm __volatile__ (
1371 "jmp L120\n\t"
1372
1373 ".p2align 4,,7\n\t"
1374 "L124:\n\t"
1375 "addl $8,%%edi\n\t" // Next QWORD
1376 "L120:\n\t"
1377
1378 // Compare adjacent DWORDS
1379 "movl (%%edi),%%ecx\n\t"
1380 "cmpl 4(%%edi),%%ecx\n\t"
1381 "jnz L121\n\t" // Print error if they don't match
1382
1383 // Loop until end of block
1384 "L122:\n\t"
1385 "cmpl %%edx,%%edi\n\t"
1386 "jb L124\n"
1387 "jmp L123\n\t"
1388
1389 "L121:\n\t"
1390 // eax not used so we don't need to save it as per cdecl
1391 // ecx is used but not restored, however we don't need it's value anymore after this point
1392 "pushl %%edx\n\t"
1393 "pushl 4(%%edi)\n\t"
1394 "pushl %%ecx\n\t"
1395 "pushl %%edi\n\t"
1396 "call error\n\t"
1397 "popl %%edi\n\t"
1398 "addl $8,%%esp\n\t"
1399 "popl %%edx\n\t"
1400 "jmp L122\n"
1401 "L123:\n\t"
1402 : "=D" (p)
1403 : "D" (p), "d" (pe)
1404 : "ecx"
1405 );
1406 } while (!done);
1407 }
1408}
1409
1410/*
1411 * Test memory for bit fade, fill memory with pattern.
1412 */
1413void bit_fade_fill(ulong p1, int me)
1414{
1415 int j, done;
1416 ulong *p, *pe;
1417 ulong *start,*end;
1418
1419 /* Display the current pattern */
1420 hprint(LINE_PAT, COL_PAT, p1);
1421
1422 /* Initialize memory with the initial pattern. */
1423 for (j=0; j<segs; j++) {
1424 start = v->map[j].start;
1425 end = v->map[j].end;
1426 pe = (ulong *)start;
1427 p = start;
1428 done = 0;
1429 do {
1430 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001431 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001432
1433 /* Check for overflow */
1434 if (pe + SPINSZ > pe && pe != 0) {
1435 pe += SPINSZ;
1436 } else {
1437 pe = end;
1438 }
1439 if (pe >= end) {
1440 pe = end;
1441 done++;
1442 }
1443 if (p == pe ) {
1444 break;
1445 }
1446 for (; p < pe;) {
1447 *p = p1;
1448 p++;
1449 }
1450 p = pe + 1;
1451 } while (!done);
1452 }
1453}
1454
1455void bit_fade_chk(ulong p1, int me)
1456{
1457 int j, done;
1458 ulong *p, *pe, bad;
1459 ulong *start,*end;
1460
1461 /* Make sure that nothing changed while sleeping */
1462 for (j=0; j<segs; j++) {
1463 start = v->map[j].start;
1464 end = v->map[j].end;
1465 pe = (ulong *)start;
1466 p = start;
1467 done = 0;
1468 do {
1469 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001470 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001471
1472 /* Check for overflow */
1473 if (pe + SPINSZ > pe && pe != 0) {
1474 pe += SPINSZ;
1475 } else {
1476 pe = end;
1477 }
1478 if (pe >= end) {
1479 pe = end;
1480 done++;
1481 }
1482 if (p == pe ) {
1483 break;
1484 }
1485 for (; p < pe;) {
1486 if ((bad=*p) != p1) {
1487 error((ulong*)p, p1, bad);
1488 }
1489 p++;
1490 }
1491 p = pe + 1;
1492 } while (!done);
1493 }
1494}
1495
1496
1497
1498
1499/* Sleep for N seconds */
1500void sleep(long n, int flag, int me, int sms)
1501{
1502 ulong sh, sl, l, h, t, ip=0;
1503
1504 /* save the starting time */
1505 asm __volatile__(
1506 "rdtsc":"=a" (sl),"=d" (sh));
1507
1508 /* loop for n seconds */
1509 while (1) {
1510 asm __volatile__(
1511 "rep ; nop\n\t"
1512 "rdtsc":"=a" (l),"=d" (h));
1513 asm __volatile__ (
1514 "subl %2,%0\n\t"
1515 "sbbl %3,%1"
1516 :"=a" (l), "=d" (h)
1517 :"g" (sl), "g" (sh),
1518 "0" (l), "1" (h));
1519
1520 if (sms != 0) {
1521 t = h * ((unsigned)0xffffffff / v->clks_msec);
1522 t += (l / v->clks_msec);
1523 } else {
1524 t = h * ((unsigned)0xffffffff / v->clks_msec) / 1000;
1525 t += (l / v->clks_msec) / 1000;
1526 }
Martin Roth4dcd13d2016-02-24 13:53:07 -08001527
Martin Roth9b1b3352016-02-24 12:27:06 -08001528 /* Is the time up? */
1529 if (t >= n) {
1530 break;
1531 }
1532
1533 /* Only display elapsed time if flag is set */
1534 if (flag == 0) {
1535 continue;
1536 }
1537
1538 if (t != ip) {
1539 do_tick(me);
Ben Gardnerb6621c32016-03-08 08:47:58 -06001540 BAILR;
Martin Roth9b1b3352016-02-24 12:27:06 -08001541 ip = t;
1542 }
1543 }
1544}
1545
1546/* Beep function */
1547
1548void beep(unsigned int frequency)
1549{
Martin Roth4dcd13d2016-02-24 13:53:07 -08001550
Martin Roth9b1b3352016-02-24 12:27:06 -08001551 unsigned int count = 1193180 / frequency;
1552
1553 // Switch on the speaker
Martin Roth74d881d2016-02-28 09:37:19 -08001554 outb(inb(0x61)|3, 0x61);
Martin Roth9b1b3352016-02-24 12:27:06 -08001555
1556 // Set command for counter 2, 2 byte write
Martin Roth74d881d2016-02-28 09:37:19 -08001557 outb(0xB6, 0x43);
Martin Roth9b1b3352016-02-24 12:27:06 -08001558
1559 // Select desired Hz
Martin Roth74d881d2016-02-28 09:37:19 -08001560 outb(count & 0xff, 0x42);
Martin Roth9b1b3352016-02-24 12:27:06 -08001561 outb((count >> 8) & 0xff, 0x42);
1562
1563 // Block for 100 microseconds
1564 sleep(100, 0, 0, 1);
1565
1566 // Switch off the speaker
Martin Roth74d881d2016-02-28 09:37:19 -08001567 outb(inb(0x61)&0xFC, 0x61);
Martin Roth9b1b3352016-02-24 12:27:06 -08001568}