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