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