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