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