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