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