]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_mem.c
new command: dissassemle - Disassemble Z180 code from memory
[z180-stamp.git] / avr / cmd_mem.c
1 /*
2 * (C) Copyright 2014,2018 Leo C. <erbl259-lmu@yahoo.de>
3 *
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 "cmd_mem.h"
17 #include <avr/interrupt.h>
18
19 #include "cli_readline.h"
20 #include "print-utils.h"
21 #include "con-utils.h"
22 #include "getopt-min.h"
23 #include "eval_arg.h"
24 #include "timer.h"
25 #include "z80-if.h"
26 #include "disas_z180.h"
27 #include "debug.h"
28
29
30 #ifndef CONFIG_SYS_MEMTEST_SCRATCH
31 #define CONFIG_SYS_MEMTEST_SCRATCH 0
32 #endif
33
34 /* Display values from last command.
35 * Memory modify remembered values are different from display memory.
36 */
37 static uint32_t disas_last_addr;
38 static uint32_t dp_last_addr;
39 static uint32_t dp_last_length = 0x100;
40 static uint32_t mm_last_addr;
41
42 static uint32_t base_address = 0;
43
44 /*--------------------------------------------------------------------------*/
45
46 static ERRNUM z180_read_buf(uint8_t *buf, uint32_t addr, uint8_t count)
47 {
48 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
49 return EBUSTO;
50
51 z80_read_block (buf, addr, count);
52 z80_bus_cmd(Release);
53 return ESUCCESS;
54 }
55
56 /*--------------------------------------------------------------------------*/
57
58 command_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
71 /*
72 * Disassemble code from memory
73 *
74 * Usage:
75 * disassemble address [# of lines]
76 *
77 */
78 command_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
117 /* Memory Display
118 *
119 * Syntax:
120 * md {addr} {len}
121 */
122 command_ret_t do_mem_md(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
123 {
124 uint32_t addr, length;
125
126 (void) cmdtp;
127
128 #if 0
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 */
147 addr = eval_arg(argv[1], NULL);
148 addr += base_address;
149
150 /* If another parameter, it is the length to display. */
151 if (argc > 2)
152 length = eval_arg(argv[2], NULL);
153 }
154
155 /* Print the lines. */
156 ERRNUM ret = dump_mem(addr, addr, length, z180_read_buf, NULL);
157 if (ret == EBUSTO)
158 cmd_error(CMD_RET_FAILURE, ret, NULL);
159
160 if (ret == ESUCCESS) {
161 dp_last_addr = addr + length;
162 dp_last_length = length;
163 }
164 return CMD_RET_SUCCESS;
165 }
166
167 /* Modify memory.
168 *
169 * Syntax:
170 * mm {addr}
171 * nm {addr}
172 */
173 static command_ret_t
174 mod_mem(cmd_tbl_t *cmdtp, int incrflag, uint_fast8_t flag, int argc, char * const argv[])
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 */
196 addr = eval_arg(argv[1], NULL);
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 {
204 z80_bus_request_or_exit();
205 data = z80_read(addr);
206 z80_bus_cmd(Release);
207 printf_P(PSTR("%05lx: %02x"), addr, data);
208
209 nbytes = cli_readline(PSTR(" ? "), 0);
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;
217
218 } else {
219 char *endp;
220 data = eval_arg(console_buffer, &endp);
221 nbytes = endp - console_buffer;
222 if (nbytes) {
223 z80_bus_request_or_exit();
224 z80_write(addr, data);
225 z80_bus_cmd(Release);
226 if (incrflag)
227 addr++;
228 }
229 }
230 } while (nbytes > 0);
231
232 mm_last_addr = addr;
233 return CMD_RET_SUCCESS;
234 }
235
236
237 command_ret_t do_mem_mm(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
238 {
239 return mod_mem (cmdtp, 1, flag, argc, argv);
240 }
241 command_ret_t do_mem_nm(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
242 {
243 return mod_mem (cmdtp, 0, flag, argc, argv);
244 }
245
246 command_ret_t do_mem_mw(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
247 {
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
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 }
271
272 /* remaining arguments */
273 argc -= optind;
274 if ((argc < 2) || (argc > 3))
275 return CMD_RET_USAGE;
276
277 /* Address and value are specified since (adjusted) argc >= 2 */
278 addr = eval_arg(argv[optind++], NULL);
279 addr += base_address;
280 writeval = eval_arg(argv[optind++], NULL);
281
282 /* Count ? */
283 if (argc == 3)
284 count = eval_arg(argv[optind], NULL);
285
286 z80_bus_request_or_exit();
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 }
295 z80_bus_cmd(Release);
296
297 return CMD_RET_SUCCESS;
298 }
299
300 #ifdef CONFIG_MX_CYCLIC
301 command_ret_t do_mem_mdc ( cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
302 {
303 uint32_t count;
304 uint32_t ts;
305
306 (void) cmdtp;
307 (void) flag;
308
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
317 if (argc-optind != 4)
318 return CMD_RET_USAGE;
319
320 count = eval_arg(argv[optind + 3], NULL);
321
322 clear_ctrlc(); /* forget any previous Control C */
323 for (;;) {
324
325 if (argv[0][1] == 'd')
326 do_mem_md (NULL, 0, argc-1, argv); /* memory display */
327 else
328 do_mem_mw (NULL, 0, argc-1, argv); /* memory write */
329
330
331 /* delay for <count> ms... */
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);
340 }
341
342 return CMD_RET_SUCCESS;
343 }
344 #endif /* CONFIG_MX_CYCLIC */
345
346 command_ret_t do_mem_cmp(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
347 {
348 uint32_t addr1, addr2, count, ngood;
349 command_ret_t rcode = CMD_RET_SUCCESS;
350 uint8_t byte1, byte2;
351
352 (void) cmdtp;
353 (void) flag;
354
355 if (argc != 4)
356 return CMD_RET_USAGE;
357
358
359 addr1 = eval_arg(argv[1], NULL);
360 addr1 += base_address;
361 addr2 = eval_arg(argv[2], NULL);
362 addr2 += base_address;
363 count = eval_arg(argv[3], NULL);
364
365 for (ngood = 0; ngood < count; ++ngood) {
366 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
367 my_puts_P(PSTR("Bus timeout\n"));
368 rcode = CMD_RET_FAILURE;
369 break;
370 }
371 byte1 = z80_read(addr1);
372 byte2 = z80_read(addr2);
373 z80_bus_cmd(Release);
374 if (byte1 != byte2) {
375 printf_P(PSTR("byte at 0x%05lx (%#02x) != "
376 "byte at 0x%05lx (%#02x)\n"),
377 addr1, byte1, addr2, byte2);
378 rcode = CMD_RET_FAILURE;
379 break;
380 }
381 addr1++;
382 addr2++;
383
384 /* check for ctrl-c to abort... */
385 if (ctrlc()) {
386 my_puts_P(PSTR("Abort\n"));
387 return CMD_RET_SUCCESS;
388 }
389 }
390
391 printf_P(PSTR("Total of %ld byte(s) (0x%lx) were the same\n"), ngood, ngood);
392 return rcode;
393 }
394
395 command_ret_t do_mem_cp(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
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
406 src = eval_arg(argv[1], NULL);
407 src += base_address;
408 dest = eval_arg(argv[2], NULL);
409 dest += base_address;
410 count = eval_arg(argv[3], NULL);
411
412 if (count == 0) {
413 my_puts_P(PSTR("Zero length?\n"));
414 return CMD_RET_FAILURE;
415 }
416
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;
426 z80_bus_request_or_exit();
427 data = z80_read(src);
428 z80_write(dest, data);
429 z80_bus_cmd(Release);
430 src += step;
431 dest += step;
432
433 /* check for ctrl-c to abort... */
434 if (ctrlc()) {
435 my_puts_P(PSTR("Abort\n"));
436 return CMD_RET_SUCCESS;
437 }
438 }
439 return CMD_RET_SUCCESS;
440 }
441
442 command_ret_t do_mem_base(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc,
443 char * const argv[])
444 {
445 (void) cmdtp;
446 (void) flag;
447
448 if (argc > 1) {
449 /* Set new base address. */
450 base_address = eval_arg(argv[1], NULL);
451 }
452 /* Print the current base address. */
453 printf_P(PSTR("Base Address: 0x%05lx\n"), base_address);
454 return CMD_RET_SUCCESS;
455 }
456
457 command_ret_t do_mem_loop(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc,
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. */
469 addr = eval_arg(argv[1], NULL);
470
471 /* Length is the number of bytes. */
472 length = eval_arg(argv[2], NULL);
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) {
479 z80_bus_request_or_exit();
480 cli();
481 for (;;)
482 z80_read(addr);
483 }
484
485 z80_bus_request_or_exit();
486 cli();
487 for (;;) {
488 uint32_t i = length;
489 uint32_t p = addr;
490 while (i-- > 0)
491 z80_read(p++);
492 }
493
494 return CMD_RET_SUCCESS;
495 }
496
497 command_ret_t do_mem_loopw (cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
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. */
509 addr = eval_arg(argv[1], NULL);
510
511 /* Length is the number of bytes. */
512 length = eval_arg(argv[2], NULL);
513
514 data = eval_arg(argv[3], NULL);
515
516 /*
517 * We want to optimize the loops to run as fast as possible.
518 * If we have only one object, just run infinite loops.
519 */
520 if (length == 1) {
521 z80_bus_request_or_exit();
522 cli();
523 for (;;)
524 z80_write(addr, data);
525 }
526
527 z80_bus_request_or_exit();
528 cli();
529 for (;;) {
530 uint32_t i = length;
531 uint32_t p = addr;
532 while (i-- > 0)
533 z80_write(p++, data);
534 }
535 }
536
537 //#define CONFIG_SYS_ALT_MEMTEST
538
539 #ifdef CONFIG_CMD_MEMTEST
540 static uint32_t mem_test_alt(uint32_t start_addr, uint32_t end_addr)
541 {
542 uint32_t addr;
543 uint32_t dummy;
544 uint32_t errs = 0;
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 */
561 };
562
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 */
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) {
590 printf_P(PSTR("FAILURE (data line): "
591 "expected %02x, actual %02x\n"),
592 pattern, temp);
593 errs++;
594 }
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) {
599 printf_P(PSTR("FAILURE (data line): "
600 "Is %02x, should be %02x\n"),
601 temp, anti_pattern);
602 errs++;
603 }
604 }
605
606 if (ctrlc())
607 return -1;
608 }
609
610 if (errs)
611 return errs;
612
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 */
647
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);
654 /*
655 * Write the default pattern at each of the
656 * power-of-two offsets.
657 */
658 for (offset = 1; offset < num_bytes; offset <<= 1)
659 z80_write(addr+offset, pattern);
660
661 /*
662 * Check for address bits stuck high.
663 */
664 z80_write(start_addr, anti_pattern);
665
666 for (offset = 1; offset < num_bytes; offset <<= 1) {
667 temp = z80_read(start_addr + offset);
668 if (temp != pattern) {
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);
672 errs++;
673 if (ctrlc())
674 return -1;
675 }
676 }
677 z80_write(start_addr, pattern);
678
679 /*
680 * Check for addr bits stuck low or shorted.
681 */
682 for (test_offset = 1; test_offset < num_bytes; test_offset <<= 1) {
683 z80_write(start_addr + test_offset, anti_pattern);
684
685 for (offset = 1; offset < num_bytes; offset <<= 1) {
686 temp = z80_read(start_addr + offset);
687 if ((temp != pattern) && (offset != test_offset)) {
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);
691 errs++;
692 if (ctrlc())
693 return -1;
694 }
695 }
696 z80_write(start_addr + test_offset, pattern);
697 }
698
699 if (errs)
700 return errs;
701
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 */
714 num_bytes++;
715
716 /*
717 * Fill memory with a known pattern.
718 */
719 for (pattern = 1, addr = start_addr; addr <= end_addr; pattern++, addr++)
720 z80_write(addr, pattern);
721
722 /*
723 * Check each location and invert it for the second pass.
724 */
725 for (pattern = 1, addr = start_addr; addr <= end_addr; pattern++, addr++) {
726 temp = z80_read(addr);
727 if (temp != pattern) {
728 printf_P(PSTR("FAILURE (read/write) @ 0x%.5lx:"
729 " expected 0x%.2x, actual 0x%.2x)\n"),
730 addr, pattern, temp);
731 errs++;
732 if (ctrlc())
733 return -1;
734 }
735
736 anti_pattern = ~pattern;
737 z80_write(addr, anti_pattern);
738 }
739
740 /*
741 * Check each location for the inverted pattern and zero it.
742 */
743 for (pattern = 1, addr = start_addr; addr <= end_addr; pattern++, addr++) {
744 anti_pattern = ~pattern;
745 temp = z80_read(addr);
746 if (temp != anti_pattern) {
747 printf_P(PSTR("FAILURE (read/write) @ 0x%.5lx:"
748 " expected 0x%.2x, actual 0x%.2x)\n"),
749 start_addr, anti_pattern, temp);
750 errs++;
751 if (ctrlc())
752 return -1;
753 }
754 z80_write(addr, 0);
755 }
756
757 return errs;
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 */
765 command_ret_t do_mem_mtest(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc,
766 char * const argv[])
767 {
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 */
773 int ret;
774
775 (void) cmdtp;
776 (void) flag;
777
778 if (argc > 1)
779 start = eval_arg(argv[1], NULL);
780
781 if (argc > 2)
782 end = eval_arg(argv[2], NULL);
783 else
784 end = CONFIG_SYS_RAMSIZE_MAX - 1;
785
786 if (argc > 3)
787 iteration_limit = (unsigned int) eval_arg(argv[3], NULL);
788
789 printf_P(PSTR("Testing %05lx ... %05lx:\n"), start, end);
790 // debug("## %s:%d: start %#05lx end %#05lx\n", __func__, __LINE__, start, end);
791
792 clear_ctrlc(); /* forget any previous Control C */
793
794 for (iteration = 0;
795 !iteration_limit || iteration < iteration_limit;
796 iteration++) {
797
798 printf_P(PSTR("Iteration: %6d\r"), iteration + 1);
799 // debug("\n");
800
801 z80_bus_request_or_exit();
802 errs += mem_test_alt(start, end);
803 z80_bus_cmd(Release);
804
805 if (had_ctrlc() || ctrlc()) {
806 break;
807 }
808 }
809
810 if (had_ctrlc()) {
811 /* Memory test was aborted - write a newline to finish off */
812 putchar('\n');
813 ret = CMD_RET_FAILURE;
814 } else {
815 printf_P(PSTR("Tested %d iteration(s) with %lu errors.\n"),
816 iteration, errs);
817 ret = errs ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
818 }
819
820 return ret;
821 }
822 #endif /* CONFIG_CMD_MEMTEST */