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