]>
Commit | Line | Data |
---|---|---|
72f58822 L |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Memory Functions | |
10 | * | |
11 | * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) | |
12 | */ | |
13 | ||
14 | #include "common.h" | |
15 | #include <stdlib.h> | |
16 | #include <ctype.h> | |
17 | ||
18 | #include "config.h" | |
19 | #include "debug.h" | |
20 | #include "command.h" | |
21 | #include "cli_readline.h" | |
22 | #include "con-utils.h" | |
23 | #include "z80-if.h" | |
24 | ||
25 | /* | |
26 | * TODO: printf() --> printf_P() | |
27 | */ | |
28 | ||
29 | #ifndef CONFIG_SYS_MEMTEST_SCRATCH | |
30 | #define CONFIG_SYS_MEMTEST_SCRATCH 0 | |
31 | #endif | |
32 | ||
72f58822 L |
33 | /* Display values from last command. |
34 | * Memory modify remembered values are different from display memory. | |
35 | */ | |
36 | static uint32_t dp_last_addr; | |
37 | static uint32_t dp_last_length = 0x100; | |
38 | static uint32_t mm_last_addr; | |
39 | ||
40 | static uint32_t base_address = 0; | |
41 | ||
42 | /*--------------------------------------------------------------------------*/ | |
43 | ||
44 | static void print_blanks(uint_fast8_t count) | |
45 | { | |
46 | while(count--) | |
47 | putchar(' '); | |
48 | } | |
49 | ||
50 | int z180_dump_mem(uint32_t startaddr, uint32_t len, const char *title) | |
51 | { | |
52 | uint8_t buf[16]; | |
53 | uint8_t llen = 16; | |
54 | uint8_t pre = startaddr % 16; | |
55 | uint32_t addr = startaddr & ~0x0f; | |
56 | len += pre; | |
57 | uint8_t i; | |
58 | ||
59 | if (title && *title) | |
60 | printf_P(PSTR("%s\n"),title); | |
61 | ||
62 | while (len) { | |
63 | if (len < 16) | |
64 | llen = len; | |
65 | ||
62f624d3 | 66 | z80_bus_cmd(Request); |
72f58822 L |
67 | for (i = pre; i < llen; i++) |
68 | buf[i] = z80_read(addr + i); | |
62f624d3 | 69 | z80_bus_cmd(Release); |
72f58822 L |
70 | |
71 | printf_P(PSTR("%.5lx:"), addr); | |
72 | #if 0 | |
73 | print_blanks(3 * pre); | |
74 | ||
75 | /* Print hex values */ | |
76 | for (i = pre; i < llen; i++) | |
77 | printf_P(PSTR(" %.2x"), buf[i]); | |
78 | #else | |
79 | for (i = 0; i < llen; i++) { | |
80 | if ((i % 8) == 0) | |
81 | putchar(' '); | |
82 | if (i < pre) | |
83 | printf_P(PSTR(".. ")); | |
84 | else | |
85 | printf_P(PSTR("%.2x "), buf[i]); | |
86 | } | |
87 | #endif | |
88 | /* fill line with whitespace for nice ASCII print */ | |
89 | #if 1 | |
90 | print_blanks(3 * (16u - i) + (16u-i)/8 + 1 + pre); | |
91 | #else | |
92 | ||
93 | #endif | |
94 | /* Print data in ASCII characters */ | |
95 | for (i = pre; i < llen; i++) | |
96 | printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.'); | |
97 | putchar('\n'); | |
98 | ||
99 | pre = 0; | |
100 | addr += 16; | |
101 | len -= llen; | |
102 | ||
103 | if (ctrlc()) | |
104 | return -1; | |
105 | } | |
106 | return 0; | |
107 | } | |
108 | ||
109 | ||
110 | /*--------------------------------------------------------------------------*/ | |
111 | ||
112 | /* Memory Display | |
113 | * | |
114 | * Syntax: | |
115 | * md {addr} {len} | |
116 | */ | |
d0581f88 | 117 | command_ret_t do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
118 | { |
119 | uint32_t addr, length; | |
120 | ||
121 | (void) cmdtp; | |
122 | ||
123 | #if 0 | |
124 | printf_P(PSTR("flag: %d, argc: %d"), flag, argc); | |
125 | for (int i = 0; i < argc; i++) { | |
126 | printf_P(PSTR(", argv[%d]: %s"), i, argv[i] ? argv[i] : "<NULL>"); | |
127 | } | |
128 | putchar('\n'); | |
129 | #endif | |
130 | ||
131 | /* We use the last specified parameters, unless new ones are | |
132 | * entered. | |
133 | */ | |
134 | addr = dp_last_addr; | |
135 | length = dp_last_length; | |
136 | ||
137 | if (argc < 2) | |
138 | return CMD_RET_USAGE; | |
139 | ||
140 | if ((flag & CMD_FLAG_REPEAT) == 0) { | |
141 | /* Address is specified since argc > 1 */ | |
142 | addr = strtoul(argv[1], NULL, 16); | |
143 | addr += base_address; | |
144 | ||
145 | /* If another parameter, it is the length to display. */ | |
146 | if (argc > 2) | |
147 | length = strtoul(argv[2], NULL, 16); | |
148 | } | |
149 | ||
150 | /* Print the lines. */ | |
151 | z180_dump_mem(addr, length, NULL); | |
152 | ||
153 | dp_last_addr = addr + length; | |
154 | dp_last_length = length; | |
d0581f88 | 155 | return CMD_RET_SUCCESS; |
72f58822 L |
156 | } |
157 | ||
d0581f88 L |
158 | /* Modify memory. |
159 | * | |
160 | * Syntax: | |
161 | * mm {addr} | |
162 | * nm {addr} | |
163 | */ | |
164 | static command_ret_t | |
165 | mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[]) | |
166 | { | |
167 | uint32_t addr; | |
168 | uint8_t data; | |
169 | int nbytes; | |
170 | ||
171 | (void) cmdtp; | |
172 | ||
173 | if (argc != 2) | |
174 | return CMD_RET_USAGE; | |
175 | ||
176 | /* We use the last specified parameters, unless new ones are | |
177 | * entered. | |
178 | */ | |
179 | addr = mm_last_addr; | |
180 | ||
181 | if ((flag & CMD_FLAG_REPEAT) == 0) { | |
182 | /* New command specified. | |
183 | */ | |
184 | ||
185 | /* Address is specified since argc > 1 | |
186 | */ | |
187 | addr = strtoul(argv[1], NULL, 16); | |
188 | addr += base_address; | |
189 | } | |
190 | ||
191 | /* Print the address, followed by value. Then accept input for | |
192 | * the next value. A non-converted value exits. | |
193 | */ | |
194 | do { | |
195 | z80_bus_cmd(Request); | |
196 | data = z80_read(addr); | |
69988dc1 | 197 | printf_P(PSTR("%05lx: %02x"), addr, data); |
d0581f88 L |
198 | z80_bus_cmd(Release); |
199 | ||
200 | nbytes = cli_readline(PSTR(" ? ")); | |
201 | if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) { | |
202 | /* <CR> pressed as only input, don't modify current | |
203 | * location and move to next. "-" pressed will go back. | |
204 | */ | |
205 | if (incrflag) | |
206 | addr += nbytes ? -1 : 1; | |
207 | nbytes = 1; | |
208 | } | |
209 | else { | |
210 | char *endp; | |
211 | data = strtoul(console_buffer, &endp, 16); | |
212 | nbytes = endp - console_buffer; | |
213 | if (nbytes) { | |
214 | z80_bus_cmd(Request); | |
215 | z80_write(addr, data); | |
216 | z80_bus_cmd(Release); | |
217 | if (incrflag) | |
218 | addr++; | |
219 | } | |
220 | } | |
221 | } while (nbytes); | |
222 | ||
223 | mm_last_addr = addr; | |
224 | return CMD_RET_SUCCESS; | |
225 | } | |
226 | ||
227 | ||
228 | command_ret_t do_mem_mm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
72f58822 L |
229 | { |
230 | return mod_mem (cmdtp, 1, flag, argc, argv); | |
231 | } | |
d0581f88 | 232 | command_ret_t do_mem_nm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
233 | { |
234 | return mod_mem (cmdtp, 0, flag, argc, argv); | |
235 | } | |
236 | ||
d0581f88 | 237 | command_ret_t do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
238 | { |
239 | uint8_t writeval; | |
240 | uint32_t addr, count; | |
241 | ||
242 | (void) cmdtp; | |
243 | (void) flag; | |
244 | ||
245 | if ((argc < 3) || (argc > 4)) | |
246 | return CMD_RET_USAGE; | |
247 | ||
248 | /* Address is specified since argc > 1 | |
249 | */ | |
250 | addr = strtoul(argv[1], NULL, 16); | |
251 | addr += base_address; | |
252 | ||
253 | /* Get the value to write. | |
254 | */ | |
255 | writeval = (uint8_t) strtoul(argv[2], NULL, 16); | |
256 | ||
257 | /* Count ? */ | |
258 | if (argc == 4) { | |
259 | count = strtoul(argv[3], NULL, 16); | |
260 | } else { | |
261 | count = 1; | |
262 | } | |
263 | ||
62f624d3 | 264 | z80_bus_cmd(Request); |
72f58822 L |
265 | while (count-- > 0) { |
266 | z80_write(addr, writeval); | |
267 | ++addr; | |
268 | } | |
62f624d3 | 269 | z80_bus_cmd(Release); |
72f58822 | 270 | |
d0581f88 | 271 | return CMD_RET_SUCCESS; |
72f58822 L |
272 | } |
273 | ||
274 | #ifdef CONFIG_MX_CYCLIC | |
d0581f88 | 275 | command_ret_t do_mem_mdc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
276 | { |
277 | int i; | |
278 | uint32_t count; | |
279 | ||
280 | if (argc < 4) | |
281 | return CMD_RET_USAGE; | |
282 | ||
283 | count = strtoul(argv[3], NULL, 10); | |
284 | ||
285 | for (;;) { | |
286 | do_mem_md (NULL, 0, 3, argv); | |
287 | ||
288 | /* delay for <count> ms... */ | |
289 | /* TODO: use timer */ | |
290 | for (i=0; i<count; i++) | |
291 | udelay (1000); | |
292 | ||
293 | /* check for ctrl-c to abort... */ | |
294 | if (ctrlc()) { | |
69988dc1 | 295 | my_puts_P(PSTR("Abort\n")); |
d0581f88 | 296 | return CMD_RET_SUCCESS; |
72f58822 L |
297 | } |
298 | } | |
299 | ||
d0581f88 | 300 | return CMD_RET_SUCCESS; |
72f58822 L |
301 | } |
302 | ||
d0581f88 | 303 | command_ret_t do_mem_mwc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
304 | { |
305 | int i; | |
306 | uint32_t count; | |
307 | ||
308 | if (argc < 4) | |
309 | return CMD_RET_USAGE; | |
310 | ||
311 | count = strtoul(argv[3], NULL, 10); | |
312 | ||
313 | for (;;) { | |
314 | do_mem_mw (NULL, 0, 3, argv); | |
315 | ||
316 | /* delay for <count> ms... */ | |
317 | /* TODO: use timer */ | |
318 | for (i=0; i<count; i++) | |
319 | udelay (1000); | |
320 | ||
321 | /* check for ctrl-c to abort... */ | |
322 | if (ctrlc()) { | |
69988dc1 | 323 | my_puts_P(PSTR("Abort\n")); |
d0581f88 | 324 | return CMD_RET_SUCCESS; |
72f58822 L |
325 | } |
326 | } | |
327 | ||
d0581f88 | 328 | return CMD_RET_SUCCESS; |
72f58822 L |
329 | } |
330 | #endif /* CONFIG_MX_CYCLIC */ | |
331 | ||
d0581f88 | 332 | command_ret_t do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
333 | { |
334 | uint32_t addr1, addr2, count, ngood; | |
d0581f88 | 335 | command_ret_t rcode = CMD_RET_SUCCESS; |
72f58822 L |
336 | uint8_t byte1, byte2; |
337 | ||
338 | (void) cmdtp; | |
339 | (void) flag; | |
340 | ||
341 | if (argc != 4) | |
342 | return CMD_RET_USAGE; | |
343 | ||
344 | ||
345 | addr1 = strtoul(argv[1], NULL, 16); | |
346 | addr1 += base_address; | |
347 | addr2 = strtoul(argv[2], NULL, 16); | |
348 | addr2 += base_address; | |
349 | count = strtoul(argv[3], NULL, 16); | |
350 | ||
351 | for (ngood = 0; ngood < count; ++ngood) { | |
62f624d3 | 352 | z80_bus_cmd(Request); |
72f58822 L |
353 | byte1 = z80_read(addr1); |
354 | byte2 = z80_read(addr2); | |
62f624d3 | 355 | z80_bus_cmd(Release); |
72f58822 L |
356 | if (byte1 != byte2) { |
357 | printf( "byte at 0x%05lx (%#02x) != " | |
358 | "byte at 0x%05lx (%#02x)\n", | |
359 | addr1, byte1, addr2, byte2); | |
d0581f88 | 360 | rcode = CMD_RET_FAILURE; |
72f58822 L |
361 | break; |
362 | } | |
363 | addr1++; | |
364 | addr2++; | |
365 | ||
366 | /* check for ctrl-c to abort... */ | |
367 | if (ctrlc()) { | |
69988dc1 | 368 | my_puts_P(PSTR("Abort\n")); |
d0581f88 | 369 | return CMD_RET_SUCCESS; |
72f58822 L |
370 | } |
371 | } | |
372 | ||
69988dc1 | 373 | printf_P(PSTR("Total of %ld byte(s) (0x%lx) were the same\n"), ngood, ngood); |
72f58822 L |
374 | return rcode; |
375 | } | |
376 | ||
d0581f88 | 377 | command_ret_t do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
378 | { |
379 | uint32_t src, dest, count; | |
380 | int_fast8_t step; | |
381 | ||
382 | (void) cmdtp; | |
383 | (void) flag; | |
384 | ||
385 | if (argc != 4) | |
386 | return CMD_RET_USAGE; | |
387 | ||
388 | src = strtoul(argv[1], NULL, 16); | |
389 | src += base_address; | |
390 | dest = strtoul(argv[2], NULL, 16); | |
391 | dest += base_address; | |
392 | count = strtoul(argv[3], NULL, 16); | |
393 | ||
394 | if (count == 0) { | |
69988dc1 | 395 | my_puts_P(PSTR("Zero length?\n")); |
d0581f88 | 396 | return CMD_RET_FAILURE; |
72f58822 L |
397 | } |
398 | ||
399 | if (dest > src) { | |
400 | src += count - 1; | |
401 | dest += count - 1; | |
402 | step = -1; | |
403 | } else | |
404 | step = 1; | |
405 | ||
406 | while (count-- > 0) { | |
407 | uint8_t data; | |
62f624d3 | 408 | z80_bus_cmd(Request); |
72f58822 L |
409 | data = z80_read(src); |
410 | z80_write(dest, data); | |
62f624d3 | 411 | z80_bus_cmd(Release); |
72f58822 L |
412 | src += step; |
413 | dest += step; | |
414 | ||
415 | /* check for ctrl-c to abort... */ | |
416 | if (ctrlc()) { | |
69988dc1 | 417 | my_puts_P(PSTR("Abort\n")); |
d0581f88 | 418 | return CMD_RET_SUCCESS; |
72f58822 L |
419 | } |
420 | } | |
d0581f88 | 421 | return CMD_RET_SUCCESS; |
72f58822 L |
422 | } |
423 | ||
d0581f88 | 424 | command_ret_t do_mem_base(cmd_tbl_t *cmdtp, int flag, int argc, |
72f58822 L |
425 | char * const argv[]) |
426 | { | |
427 | (void) cmdtp; | |
428 | (void) flag; | |
429 | ||
430 | if (argc > 1) { | |
431 | /* Set new base address. */ | |
432 | base_address = strtoul(argv[1], NULL, 16); | |
433 | } | |
434 | /* Print the current base address. */ | |
69988dc1 | 435 | printf_P(PSTR("Base Address: 0x%05lx\n"), base_address); |
d0581f88 | 436 | return CMD_RET_SUCCESS; |
72f58822 L |
437 | } |
438 | ||
d0581f88 | 439 | command_ret_t do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc, |
72f58822 L |
440 | char * const argv[]) |
441 | { | |
442 | uint32_t addr, length; | |
443 | ||
444 | (void) cmdtp; | |
445 | (void) flag; | |
446 | ||
447 | if (argc < 3) | |
448 | return CMD_RET_USAGE; | |
449 | ||
450 | /* Address is always specified. */ | |
451 | addr = strtoul(argv[1], NULL, 16); | |
452 | ||
453 | /* Length is the number of bytes. */ | |
454 | length = strtoul(argv[2], NULL, 16); | |
455 | ||
456 | ||
457 | /* We want to optimize the loops to run as fast as possible. | |
458 | * If we have only one object, just run infinite loops. | |
459 | */ | |
460 | if (length == 1) { | |
62f624d3 | 461 | z80_bus_cmd(Request); |
72f58822 L |
462 | for (;;) |
463 | z80_read(addr); | |
62f624d3 | 464 | z80_bus_cmd(Release); |
72f58822 L |
465 | } |
466 | ||
62f624d3 | 467 | z80_bus_cmd(Request); |
72f58822 L |
468 | for (;;) { |
469 | uint32_t i = length; | |
470 | uint32_t p = addr; | |
471 | while (i-- > 0) | |
472 | z80_read(p++); | |
473 | } | |
62f624d3 | 474 | z80_bus_cmd(Release); |
72f58822 | 475 | |
d0581f88 | 476 | return CMD_RET_SUCCESS; |
72f58822 L |
477 | } |
478 | ||
479 | #ifdef CONFIG_LOOPW | |
d0581f88 | 480 | command_ret_t do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
72f58822 L |
481 | { |
482 | uint32_t addr, length; | |
483 | uint8_t data; | |
484 | ||
485 | (void) cmdtp; | |
486 | (void) flag; | |
487 | ||
488 | if (argc < 4) | |
489 | return CMD_RET_USAGE; | |
490 | ||
491 | /* Address is always specified. */ | |
492 | addr = strtoul(argv[1], NULL, 16); | |
493 | ||
494 | /* Length is the number of bytes. */ | |
495 | length = strtoul(argv[2], NULL, 16); | |
496 | ||
497 | data = strtoul(argv[3], NULL, 16); | |
498 | ||
499 | /* We want to optimize the loops to run as fast as possible. | |
500 | * If we have only one object, just run infinite loops. | |
501 | */ | |
502 | if (length == 1) { | |
62f624d3 | 503 | z80_bus_cmd(Request); |
72f58822 L |
504 | for (;;) |
505 | z80_write(addr, data); | |
506 | } | |
507 | ||
508 | for (;;) { | |
509 | uint32_t i = length; | |
510 | uint32_t p = addr; | |
511 | while (i-- > 0) | |
512 | z80_write(p++, data); | |
513 | } | |
514 | } | |
515 | #endif /* CONFIG_LOOPW */ | |
516 | ||
517 | #ifdef CONFIG_CMD_MEMTEST | |
518 | static uint32_t mem_test_alt(vu_long *buf, uint32_t start_addr, uint32_t end_addr, | |
519 | vu_long *dummy) | |
520 | { | |
521 | vu_long *addr; | |
522 | uint32_t errs = 0; | |
523 | uint32_t val, readback; | |
524 | int j; | |
525 | vu_long offset; | |
526 | vu_long test_offset; | |
527 | vu_long pattern; | |
528 | vu_long temp; | |
529 | vu_long anti_pattern; | |
530 | vu_long num_words; | |
531 | static const FLASH uint32_t bitpattern[] = { | |
532 | 0x00000001, /* single bit */ | |
533 | 0x00000003, /* two adjacent bits */ | |
534 | 0x00000007, /* three adjacent bits */ | |
535 | 0x0000000F, /* four adjacent bits */ | |
536 | 0x00000005, /* two non-adjacent bits */ | |
537 | 0x00000015, /* three non-adjacent bits */ | |
538 | 0x00000055, /* four non-adjacent bits */ | |
539 | 0xaaaaaaaa, /* alternating 1/0 */ | |
540 | }; | |
541 | ||
542 | num_words = (end_addr - start_addr) / sizeof(vu_long); | |
543 | ||
544 | /* | |
545 | * Data line test: write a pattern to the first | |
546 | * location, write the 1's complement to a 'parking' | |
547 | * address (changes the state of the data bus so a | |
548 | * floating bus doesn't give a false OK), and then | |
549 | * read the value back. Note that we read it back | |
550 | * into a variable because the next time we read it, | |
551 | * it might be right (been there, tough to explain to | |
552 | * the quality guys why it prints a failure when the | |
553 | * "is" and "should be" are obviously the same in the | |
554 | * error message). | |
555 | * | |
556 | * Rather than exhaustively testing, we test some | |
557 | * patterns by shifting '1' bits through a field of | |
558 | * '0's and '0' bits through a field of '1's (i.e. | |
559 | * pattern and ~pattern). | |
560 | */ | |
561 | addr = buf; | |
562 | for (j = 0; j < sizeof(bitpattern) / sizeof(bitpattern[0]); j++) { | |
563 | val = bitpattern[j]; | |
564 | for (; val != 0; val <<= 1) { | |
565 | *addr = val; | |
566 | *dummy = ~val; /* clear the test data off the bus */ | |
567 | readback = *addr; | |
568 | if (readback != val) { | |
69988dc1 L |
569 | printf_P(PSTR("FAILURE (data line): " |
570 | "expected %05lx, actual %05lx\n"), | |
72f58822 L |
571 | val, readback); |
572 | errs++; | |
573 | if (ctrlc()) | |
574 | return -1; | |
575 | } | |
576 | *addr = ~val; | |
577 | *dummy = val; | |
578 | readback = *addr; | |
579 | if (readback != ~val) { | |
69988dc1 L |
580 | printf_P(PSTR("FAILURE (data line): " |
581 | "Is %05lx, should be %05lx\n"), | |
72f58822 L |
582 | readback, ~val); |
583 | errs++; | |
584 | if (ctrlc()) | |
585 | return -1; | |
586 | } | |
587 | } | |
588 | } | |
589 | ||
590 | /* | |
591 | * Based on code whose Original Author and Copyright | |
592 | * information follows: Copyright (c) 1998 by Michael | |
593 | * Barr. This software is placed into the public | |
594 | * domain and may be used for any purpose. However, | |
595 | * this notice must not be changed or removed and no | |
596 | * warranty is either expressed or implied by its | |
597 | * publication or distribution. | |
598 | */ | |
599 | ||
600 | /* | |
601 | * Address line test | |
602 | ||
603 | * Description: Test the address bus wiring in a | |
604 | * memory region by performing a walking | |
605 | * 1's test on the relevant bits of the | |
606 | * address and checking for aliasing. | |
607 | * This test will find single-bit | |
608 | * address failures such as stuck-high, | |
609 | * stuck-low, and shorted pins. The base | |
610 | * address and size of the region are | |
611 | * selected by the caller. | |
612 | ||
613 | * Notes: For best results, the selected base | |
614 | * address should have enough LSB 0's to | |
615 | * guarantee single address bit changes. | |
616 | * For example, to test a 64-Kbyte | |
617 | * region, select a base address on a | |
618 | * 64-Kbyte boundary. Also, select the | |
619 | * region size as a power-of-two if at | |
620 | * all possible. | |
621 | * | |
622 | * Returns: 0 if the test succeeds, 1 if the test fails. | |
623 | */ | |
624 | pattern = (vu_long) 0xaaaaaaaa; | |
625 | anti_pattern = (vu_long) 0x55555555; | |
626 | ||
627 | debug("%s:%d: length = 0x%.5lx\n", __func__, __LINE__, num_words); | |
628 | /* | |
629 | * Write the default pattern at each of the | |
630 | * power-of-two offsets. | |
631 | */ | |
632 | for (offset = 1; offset < num_words; offset <<= 1) | |
633 | addr[offset] = pattern; | |
634 | ||
635 | /* | |
636 | * Check for address bits stuck high. | |
637 | */ | |
638 | test_offset = 0; | |
639 | addr[test_offset] = anti_pattern; | |
640 | ||
641 | for (offset = 1; offset < num_words; offset <<= 1) { | |
642 | temp = addr[offset]; | |
643 | if (temp != pattern) { | |
69988dc1 L |
644 | printf_P(PSTR("\nFAILURE: Address bit stuck high @ 0x%.5lx:" |
645 | " expected 0x%.5lx, actual 0x%.5lx\n"), | |
72f58822 L |
646 | start_addr + offset*sizeof(vu_long), |
647 | pattern, temp); | |
648 | errs++; | |
649 | if (ctrlc()) | |
650 | return -1; | |
651 | } | |
652 | } | |
653 | addr[test_offset] = pattern; | |
654 | ||
655 | /* | |
656 | * Check for addr bits stuck low or shorted. | |
657 | */ | |
658 | for (test_offset = 1; test_offset < num_words; test_offset <<= 1) { | |
659 | addr[test_offset] = anti_pattern; | |
660 | ||
661 | for (offset = 1; offset < num_words; offset <<= 1) { | |
662 | temp = addr[offset]; | |
663 | if ((temp != pattern) && (offset != test_offset)) { | |
69988dc1 | 664 | printf_P(PSTR("\nFAILURE: Address bit stuck low or" |
72f58822 | 665 | " shorted @ 0x%.5lx: expected 0x%.5lx," |
69988dc1 | 666 | " actual 0x%.5lx\n"), |
72f58822 L |
667 | start_addr + offset*sizeof(vu_long), |
668 | pattern, temp); | |
669 | errs++; | |
670 | if (ctrlc()) | |
671 | return -1; | |
672 | } | |
673 | } | |
674 | addr[test_offset] = pattern; | |
675 | } | |
676 | ||
677 | /* | |
678 | * Description: Test the integrity of a physical | |
679 | * memory device by performing an | |
680 | * increment/decrement test over the | |
681 | * entire region. In the process every | |
682 | * storage bit in the device is tested | |
683 | * as a zero and a one. The base address | |
684 | * and the size of the region are | |
685 | * selected by the caller. | |
686 | * | |
687 | * Returns: 0 if the test succeeds, 1 if the test fails. | |
688 | */ | |
689 | num_words++; | |
690 | ||
691 | /* | |
692 | * Fill memory with a known pattern. | |
693 | */ | |
694 | for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { | |
695 | addr[offset] = pattern; | |
696 | } | |
697 | ||
698 | /* | |
699 | * Check each location and invert it for the second pass. | |
700 | */ | |
701 | for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { | |
702 | temp = addr[offset]; | |
703 | if (temp != pattern) { | |
69988dc1 L |
704 | printf_P(PSTR("\nFAILURE (read/write) @ 0x%.5lx:" |
705 | " expected 0x%.5lx, actual 0x%.5lx)\n"), | |
72f58822 L |
706 | start_addr + offset*sizeof(vu_long), |
707 | pattern, temp); | |
708 | errs++; | |
709 | if (ctrlc()) | |
710 | return -1; | |
711 | } | |
712 | ||
713 | anti_pattern = ~pattern; | |
714 | addr[offset] = anti_pattern; | |
715 | } | |
716 | ||
717 | /* | |
718 | * Check each location for the inverted pattern and zero it. | |
719 | */ | |
720 | for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { | |
721 | WATCHDOG_RESET(); | |
722 | anti_pattern = ~pattern; | |
723 | temp = addr[offset]; | |
724 | if (temp != anti_pattern) { | |
69988dc1 L |
725 | printf_P(PSTR("\nFAILURE (read/write): @ 0x%.5lx:" |
726 | " expected 0x%.5lx, actual 0x%.5lx)\n"), | |
72f58822 L |
727 | start_addr + offset*sizeof(vu_long), |
728 | anti_pattern, temp); | |
729 | errs++; | |
730 | if (ctrlc()) | |
731 | return -1; | |
732 | } | |
733 | addr[offset] = 0; | |
734 | } | |
735 | ||
736 | return 0; | |
737 | } | |
738 | ||
739 | static uint32_t mem_test_quick(vu_long *buf, uint32_t start_addr, uint32_t end_addr, | |
740 | vu_long pattern, int iteration) | |
741 | { | |
742 | vu_long *end; | |
743 | vu_long *addr; | |
744 | uint32_t errs = 0; | |
745 | uint32_t incr, length; | |
746 | uint32_t val, readback; | |
747 | ||
748 | /* Alternate the pattern */ | |
749 | incr = 1; | |
750 | if (iteration & 1) { | |
751 | incr = -incr; | |
752 | /* | |
753 | * Flip the pattern each time to make lots of zeros and | |
754 | * then, the next time, lots of ones. We decrement | |
755 | * the "negative" patterns and increment the "positive" | |
756 | * patterns to preserve this feature. | |
757 | */ | |
758 | if (pattern & 0x80000000) | |
759 | pattern = -pattern; /* complement & increment */ | |
760 | else | |
761 | pattern = ~pattern; | |
762 | } | |
763 | length = (end_addr - start_addr) / sizeof(uint32_t); | |
764 | end = buf + length; | |
69988dc1 | 765 | printf_P(PSTR("\rPattern %08lX Writing..." |
72f58822 | 766 | "%12s" |
69988dc1 | 767 | "\b\b\b\b\b\b\b\b\b\b"), |
72f58822 L |
768 | pattern, ""); |
769 | ||
770 | for (addr = buf, val = pattern; addr < end; addr++) { | |
771 | *addr = val; | |
772 | val += incr; | |
773 | } | |
774 | ||
69988dc1 | 775 | my_puts_P(PSTR("Reading...")); |
72f58822 L |
776 | |
777 | for (addr = buf, val = pattern; addr < end; addr++) { | |
778 | readback = *addr; | |
779 | if (readback != val) { | |
780 | uint32_t offset = addr - buf; | |
781 | ||
69988dc1 L |
782 | printf_P(PSTR("\nMem error @ 0x%08X: " |
783 | "found %08lX, expected %08lX\n"), | |
72f58822 L |
784 | (unsigned int)(uintptr_t)(start_addr + offset*sizeof(vu_long)), |
785 | readback, val); | |
786 | errs++; | |
787 | if (ctrlc()) | |
788 | return -1; | |
789 | } | |
790 | val += incr; | |
791 | } | |
792 | ||
793 | return 0; | |
794 | } | |
795 | ||
796 | /* | |
797 | * Perform a memory test. A more complete alternative test can be | |
798 | * configured using CONFIG_SYS_ALT_MEMTEST. The complete test loops until | |
799 | * interrupted by ctrl-c or by a failure of one of the sub-tests. | |
800 | */ | |
d0581f88 | 801 | command_ret_t do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc, |
72f58822 L |
802 | char * const argv[]) |
803 | { | |
804 | uint32_t start, end; | |
805 | vu_long *buf, *dummy; | |
806 | int iteration_limit; | |
d0581f88 | 807 | /* TODO: command_ret_t */ |
72f58822 L |
808 | int ret; |
809 | uint32_t errs = 0; /* number of errors, or -1 if interrupted */ | |
810 | uint32_t pattern; | |
811 | int iteration; | |
812 | #if defined(CONFIG_SYS_ALT_MEMTEST) | |
813 | const int alt_test = 1; | |
814 | #else | |
815 | const int alt_test = 0; | |
816 | #endif | |
817 | ||
818 | if (argc > 1) | |
819 | start = strtoul(argv[1], NULL, 16); | |
820 | else | |
821 | start = CONFIG_SYS_MEMTEST_START; | |
822 | ||
823 | if (argc > 2) | |
824 | end = strtoul(argv[2], NULL, 16); | |
825 | else | |
826 | end = CONFIG_SYS_MEMTEST_END; | |
827 | ||
828 | if (argc > 3) | |
829 | pattern = (uint32_t)strtoul(argv[3], NULL, 16); | |
830 | else | |
831 | pattern = 0; | |
832 | ||
833 | if (argc > 4) | |
834 | iteration_limit = (uint32_t)strtoul(argv[4], NULL, 16); | |
835 | else | |
836 | iteration_limit = 0; | |
837 | ||
69988dc1 | 838 | printf_P(PSTR("Testing %08x ... %08x:\n"), (unsigned int)start, (unsigned int)end); |
72f58822 L |
839 | debug("%s:%d: start %#05lx end %#05lx\n", __func__, __LINE__, |
840 | start, end); | |
841 | ||
842 | /* TODO: */ | |
843 | // buf = map_sysmem(start, end - start); | |
844 | // dummy = map_sysmem(CONFIG_SYS_MEMTEST_SCRATCH, sizeof(vu_long)); | |
845 | for (iteration = 0; | |
846 | !iteration_limit || iteration < iteration_limit; | |
847 | iteration++) { | |
848 | if (ctrlc()) { | |
849 | errs = -1UL; | |
850 | break; | |
851 | } | |
852 | ||
69988dc1 | 853 | printf_P(PSTR("Iteration: %6d\r"), iteration + 1); |
72f58822 L |
854 | debug("\n"); |
855 | if (alt_test) { | |
856 | errs = mem_test_alt(buf, start, end, dummy); | |
857 | } else { | |
858 | errs = mem_test_quick(buf, start, end, pattern, | |
859 | iteration); | |
860 | } | |
861 | if (errs == -1UL) | |
862 | break; | |
863 | } | |
864 | ||
865 | if (errs == -1UL) { | |
866 | /* Memory test was aborted - write a newline to finish off */ | |
867 | putc('\n'); | |
868 | ret = 1; | |
869 | } else { | |
69988dc1 | 870 | printf_P(PSTR("Tested %d iteration(s) with %lu errors.\n"), |
72f58822 L |
871 | iteration, errs); |
872 | ret = errs != 0; | |
873 | } | |
874 | ||
875 | return ret; /* not reached */ | |
876 | } | |
877 | #endif /* CONFIG_CMD_MEMTEST */ | |
878 |