fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/cpm80/cmd.c *
7 * Created: 2012-11-28 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2012-2025 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "bios.h"
25#include "cpm80.h"
26
27#include <stdio.h>
28#include <string.h>
29
30#include <lib/brkpt.h>
31#include <lib/cmd.h>
32#include <lib/console.h>
33#include <lib/log.h>
34#include <lib/monitor.h>
35#include <lib/sysdep.h>
36
37
38static mon_cmd_t par_cmd[] = {
39 { "c", "[cnt]", "clock" },
40 { "gb", "[addr...]", "run with breakpoints" },
41 { "g", "", "run" },
42 { "i", "port", "input a byte from a port" },
43 { "o", "port val", "output a byte to a port" },
44 { "p", "[cnt]", "execute cnt instructions, skip calls [1]" },
45 { "r", "reg [val]", "set a register" },
46 { "s", "[what]", "print status (cpu|mem)" },
47 { "trace", "on|off|expr", "turn trace on or off" },
48 { "t", "[cnt]", "execute cnt instructions [1]" },
49 { "u", "[addr [cnt]]", "disassemble" }
50};
51
52
53static
54void c80_disasm_str (char *dst, e8080_disasm_t *op, int with_pc, int with_comment)
55{
56 unsigned i, k, n;
57 char comment[256];
58
59 comment[0] = 0;
60
61 if (with_pc) {
62 n = sprintf (dst, "%04X ", (unsigned) op->pc);
63 }
64 else {
65 n = 0;
66 }
67
68 for (i = 0; i < op->data_cnt; i++) {
69 n += sprintf (dst + n, "%02X ", (unsigned) op->data[i]);
70 }
71
72 for (i = op->data_cnt; i < 4; i++) {
73 dst[n++] = ' ';
74 dst[n++] = ' ';
75 dst[n++] = ' ';
76 }
77
78 k = n + 8;
79 n += sprintf (dst + n, "%s", op->op);
80
81 if (op->arg_cnt > 0) {
82 while (n < k) {
83 dst[n++] = ' ';
84 }
85
86 n += sprintf (dst + n, "%s", op->arg[0]);
87
88 for (i = 1; i < op->arg_cnt; i++) {
89 n += sprintf (dst + n, ", %s", op->arg[i]);
90 }
91 }
92
93 if (with_comment && (comment[0] != 0)) {
94 while (n < 40) {
95 dst[n++] = ' ';
96 }
97
98 dst[n++] = ';';
99 }
100
101 dst[n] = 0;
102}
103
104static
105void c80_disasm_cur (e8080_t *c, e8080_disasm_t *op)
106{
107 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
108 z80_disasm_cur (c, op);
109 }
110 else {
111 e8080_disasm_cur (c, op);
112 }
113}
114
115static
116void c80_disasm_mem (e8080_t *c, e8080_disasm_t *op, unsigned short addr)
117{
118 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
119 z80_disasm_mem (c, op, addr);
120 }
121 else {
122 e8080_disasm_mem (c, op, addr);
123 }
124}
125
126static
127void c80_print_cpu_z80_1 (e8080_t *c)
128{
129 e8080_disasm_t op;
130 char str[256];
131
132 c80_disasm_cur (c, &op);
133 c80_disasm_str (str, &op, 0, 0);
134
135 if (c->halt) {
136 pce_printf ("HALT=1 ");
137 }
138
139 pce_printf (
140 "A=%02X BC=%04X DE=%04X HL=%04X IX=%04X IY=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c] %s\n",
141 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
142 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
143 (unsigned) e8080_get_ix (c), (unsigned) e8080_get_iy (c),
144 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
145 (unsigned) e8080_get_psw (c),
146 (e8080_get_sf (c)) ? 'S' : '-',
147 (e8080_get_zf (c)) ? 'Z' : '-',
148 (e8080_get_af (c)) ? 'A' : '-',
149 (e8080_get_pf (c)) ? 'P' : '-',
150 (e8080_get_cf (c)) ? 'C' : '-',
151 str
152 );
153}
154
155static
156void c80_print_cpu_8080_1 (e8080_t *c)
157{
158 e8080_disasm_t op;
159 char str[256];
160
161 c80_disasm_cur (c, &op);
162 c80_disasm_str (str, &op, 0, 0);
163
164 if (c->halt) {
165 pce_printf ("HALT=1 ");
166 }
167
168 pce_printf (
169 "A=%02X BC=%04X DE=%04X HL=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c] %s\n",
170 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
171 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
172 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
173 (unsigned) e8080_get_psw (c),
174 (e8080_get_sf (c)) ? 'S' : '-',
175 (e8080_get_zf (c)) ? 'Z' : '-',
176 (e8080_get_af (c)) ? 'A' : '-',
177 (e8080_get_pf (c)) ? 'P' : '-',
178 (e8080_get_cf (c)) ? 'C' : '-',
179 str
180 );
181}
182
183static
184void c80_print_cpu_z80_2 (e8080_t *c)
185{
186 e8080_disasm_t op;
187 char str[256];
188
189 c80_disasm_cur (c, &op);
190 c80_disasm_str (str, &op, 1, 1);
191
192 pce_printf (
193 "A=%02X BC=%04X DE=%04X HL=%04X IX=%04X IY=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c]\n"
194 "%s\n",
195 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
196 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
197 (unsigned) e8080_get_ix (c), (unsigned) e8080_get_iy (c),
198 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
199 (unsigned) e8080_get_psw (c),
200 (e8080_get_sf (c)) ? 'S' : '-',
201 (e8080_get_zf (c)) ? 'Z' : '-',
202 (e8080_get_af (c)) ? 'A' : '-',
203 (e8080_get_pf (c)) ? 'P' : '-',
204 (e8080_get_cf (c)) ? 'C' : '-',
205 str
206 );
207
208 if (c->halt) {
209 pce_printf ("HALT=1\n");
210 }
211}
212
213static
214void c80_print_cpu_8080_2 (e8080_t *c)
215{
216 e8080_disasm_t op;
217 char str[256];
218
219 c80_disasm_cur (c, &op);
220 c80_disasm_str (str, &op, 1, 1);
221
222 pce_printf (
223 "A=%02X BC=%04X DE=%04X HL=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c]\n"
224 "%s\n",
225 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
226 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
227 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
228 (unsigned) e8080_get_psw (c),
229 (e8080_get_sf (c)) ? 'S' : '-',
230 (e8080_get_zf (c)) ? 'Z' : '-',
231 (e8080_get_af (c)) ? 'A' : '-',
232 (e8080_get_pf (c)) ? 'P' : '-',
233 (e8080_get_cf (c)) ? 'C' : '-',
234 str
235 );
236
237 if (c->halt) {
238 pce_printf ("HALT=1\n");
239 }
240}
241
242void c80_print_cpu (e8080_t *c, int oneline)
243{
244 if (oneline) {
245 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
246 c80_print_cpu_z80_1 (c);
247 }
248 else {
249 c80_print_cpu_8080_1 (c);
250 }
251 }
252 else {
253 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
254 c80_print_cpu_z80_2 (c);
255 }
256 else {
257 c80_print_cpu_8080_2 (c);
258 }
259 }
260}
261
262void print_state_cpu (e8080_t *c)
263{
264 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
265 pce_prt_sep ("Z80");
266 }
267 else {
268 pce_prt_sep ("8080");
269 }
270
271 c80_print_cpu (c, 0);
272}
273
274void c80_print_trace (cpm80_t *sim)
275{
276 c80_print_cpu (sim->cpu, 1);
277}
278
279static
280void print_state_mem (cpm80_t *sim)
281{
282 pce_prt_sep ("MEMORY");
283 mem_prt_state (sim->mem, stdout);
284}
285
286static
287void print_state (cpm80_t *sim, const char *str)
288{
289 cmd_t cmd;
290
291 cmd_set_str (&cmd, str);
292
293 if (cmd_match_eol (&cmd)) {
294 return;
295 }
296
297 while (!cmd_match_eol (&cmd)) {
298 if (cmd_match (&cmd, "cpu")) {
299 print_state_cpu (sim->cpu);
300 }
301 else if (cmd_match (&cmd, "mem")) {
302 print_state_mem (sim);
303 }
304 else {
305 printf ("unknown component (%s)\n", cmd_get_str (&cmd));
306 return;
307 }
308 }
309}
310
311static
312int c80_check_break (cpm80_t *sim)
313{
314 if (bps_check (&sim->bps, 0, e8080_get_pc (sim->cpu), stdout)) {
315 return (1);
316 }
317
318 if (sim->brk) {
319 return (1);
320 }
321
322 return (0);
323}
324
325static
326void c80_exec (cpm80_t *sim)
327{
328 unsigned long old;
329
330 old = e8080_get_opcnt (sim->cpu);
331
332 while (e8080_get_opcnt (sim->cpu) == old) {
333 c80_clock (sim, 4);
334
335 if (sim->brk) {
336 break;
337 }
338 }
339}
340
341static
342int c80_exec_to (cpm80_t *sim, unsigned short addr)
343{
344 while (e8080_get_pc (sim->cpu) != addr) {
345 c80_clock (sim, 4);
346
347 if (sim->brk) {
348 return (1);
349 }
350 }
351
352 return (0);
353}
354
355static
356int c80_exec_off (cpm80_t *sim, unsigned short addr)
357{
358 while (e8080_get_pc (sim->cpu) == addr) {
359 c80_clock (sim, 4);
360
361 if (sim->brk) {
362 return (1);
363 }
364 }
365
366 return (0);
367}
368
369void c80_run (cpm80_t *sim)
370{
371 pce_start (&sim->brk);
372
373 c80_clock_discontinuity (sim);
374
375 while (1) {
376 c80_clock (sim, 64);
377
378 if (sim->brk) {
379 break;
380 }
381 }
382
383 pce_stop();
384}
385
386
387static
388int c80_hook_undef (void *ext, unsigned op)
389{
390 cpm80_t *sim = ext;
391
392 pce_log (MSG_DEB,
393 "%04X: undefined operation [%02X %02X %02X %02X]\n",
394 (unsigned) e8080_get_pc (sim->cpu),
395 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu)),
396 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 1),
397 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 2),
398 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 3)
399 );
400
401 pce_usleep (5000);
402
403 return (0);
404}
405
406static
407int c80_hook_rst (void *ext, unsigned n)
408{
409 cpm80_t *sim = ext;
410 unsigned fct;
411
412 if (n == 0) {
413 fct = e8080_get_pc (sim->cpu);
414
415 if (fct < sim->addr_bios) {
416 return (0);
417 }
418
419 fct = (fct & 0x3f) / 2;
420
421 c80_bios (sim, fct);
422
423 return (1);
424 }
425 else if (n == 7) {
426 if (mem_get_uint16_le (sim->mem, 56) == 0) {
427 c80_stop (sim);
428 return (1);
429 }
430 }
431
432 return (0);
433}
434
435
436static
437void c80_cmd_c (cpm80_t *sim, cmd_t *cmd)
438{
439 unsigned short cnt;
440
441 cnt = 1;
442
443 cmd_match_uint16 (cmd, &cnt);
444
445 if (!cmd_match_end (cmd)) {
446 return;
447 }
448
449 while (cnt > 0) {
450 c80_clock (sim, 1);
451 cnt -= 1;
452 }
453
454 print_state_cpu (sim->cpu);
455}
456
457static
458void c80_cmd_g_b (cpm80_t *sim, cmd_t *cmd)
459{
460 unsigned short addr;
461 breakpoint_t *bp;
462
463 while (cmd_match_uint16 (cmd, &addr)) {
464 bp = bp_addr_new (addr);
465 bps_bp_add (&sim->bps, bp);
466 }
467
468 if (!cmd_match_end (cmd)) {
469 return;
470 }
471
472 pce_start (&sim->brk);
473
474 c80_clock_discontinuity (sim);
475
476 while (1) {
477 if (sim->trace) {
478 c80_print_trace (sim);
479 }
480
481 c80_exec (sim);
482
483 if (c80_check_break (sim)) {
484 break;
485 }
486 }
487
488 pce_stop();
489}
490
491static
492void c80_cmd_g (cpm80_t *sim, cmd_t *cmd)
493{
494 if (cmd_match (cmd, "b")) {
495 c80_cmd_g_b (sim, cmd);
496 return;
497 }
498
499 if (!cmd_match_end (cmd)) {
500 return;
501 }
502
503 c80_run (sim);
504}
505
506static
507void c80_cmd_i (cpm80_t *sim, cmd_t *cmd)
508{
509 unsigned short port;
510
511 if (!cmd_match_uint16 (cmd, &port)) {
512 cmd_error (cmd, "need a port address");
513 return;
514 }
515
516 if (!cmd_match_end (cmd)) {
517 return;
518 }
519
520 pce_printf ("%04X: %02X\n", port, e8080_get_port8 (sim->cpu, port));
521}
522
523static
524void c80_cmd_o (cpm80_t *sim, cmd_t *cmd)
525{
526 unsigned short port, val;
527
528 if (!cmd_match_uint16 (cmd, &port)) {
529 cmd_error (cmd, "need a port address");
530 return;
531 }
532
533 if (!cmd_match_uint16 (cmd, &val)) {
534 cmd_error (cmd, "need a value");
535 return;
536 }
537
538 if (!cmd_match_end (cmd)) {
539 return;
540 }
541
542 e8080_set_port8 (sim->cpu, port, val);
543}
544
545static
546void c80_cmd_p (cpm80_t *sim, cmd_t *cmd)
547{
548 int s;
549 unsigned short i, n;
550 e8080_disasm_t dis;
551
552 n = 1;
553 s = 0;
554
555 if (cmd_match_uint16 (cmd, &n)) {
556 s = 1;
557 }
558
559 if (!cmd_match_end (cmd)) {
560 return;
561 }
562
563 pce_start (&sim->brk);
564
565 c80_clock_discontinuity (sim);
566
567 for (i = 0; i < n; i++) {
568 c80_disasm_cur (sim->cpu, &dis);
569
570 if (s) {
571 c80_print_trace (sim);
572 }
573
574 if (dis.flags & E8080_OPF_CALL) {
575 if (c80_exec_to (sim, dis.pc + dis.data_cnt)) {
576 break;
577 }
578 }
579 else {
580 if (c80_exec_off (sim, dis.pc)) {
581 break;
582 }
583 }
584 }
585
586 if (s) {
587 c80_print_cpu (sim->cpu, 1);
588 }
589
590 pce_stop();
591
592 print_state_cpu (sim->cpu);
593}
594
595static
596void c80_cmd_r (cpm80_t *sim, cmd_t *cmd)
597{
598 unsigned long val;
599 char sym[256];
600
601 if (cmd_match_eol (cmd)) {
602 print_state_cpu (sim->cpu);
603 return;
604 }
605
606 if (!cmd_match_ident (cmd, sym, 256)) {
607 cmd_error (cmd, "missing register");
608 return;
609 }
610
611 if (e8080_get_reg (sim->cpu, sym, &val)) {
612 cmd_error (cmd, "bad register\n");
613 return;
614 }
615
616 if (cmd_match_eol (cmd)) {
617 pce_printf ("%02lX\n", val);
618 return;
619 }
620
621 if (!cmd_match_uint32 (cmd, &val)) {
622 cmd_error (cmd, "missing value\n");
623 return;
624 }
625
626 if (!cmd_match_end (cmd)) {
627 return;
628 }
629
630 e8080_set_reg (sim->cpu, sym, val);
631
632 print_state_cpu (sim->cpu);
633}
634
635static
636void c80_cmd_s (cpm80_t *sim, cmd_t *cmd)
637{
638 if (cmd_match_eol (cmd)) {
639 print_state_cpu (sim->cpu);
640 return;
641 }
642
643 print_state (sim, cmd_get_str (cmd));
644}
645
646static
647void c80_cmd_trace (cpm80_t *sim, cmd_t *cmd)
648{
649 unsigned short v;
650
651 if (cmd_match_eol (cmd)) {
652 pce_printf ("trace is %s\n", sim->trace ? "on" : "off");
653 return;
654 }
655
656 if (cmd_match (cmd, "on")) {
657 sim->trace = 1;
658 }
659 else if (cmd_match (cmd, "off")) {
660 sim->trace = 0;
661 }
662 else if (cmd_match_uint16 (cmd, &v)) {
663 sim->trace = (v != 0);
664 }
665 else {
666 cmd_error (cmd, "on or off expected\n");
667 }
668}
669
670static
671void c80_cmd_t (cpm80_t *sim, cmd_t *cmd)
672{
673 int s;
674 unsigned short i, n;
675
676 n = 1;
677 s = 0;
678
679 if (cmd_match_uint16 (cmd, &n)) {
680 s = 1;
681 }
682
683 if (!cmd_match_end (cmd)) {
684 return;
685 }
686
687 pce_start (&sim->brk);
688
689 c80_clock_discontinuity (sim);
690
691 for (i = 0; i < n; i++) {
692 if (s) {
693 c80_print_trace (sim);
694 }
695
696 c80_exec (sim);
697 }
698
699 if (s) {
700 c80_print_cpu (sim->cpu, 1);
701 }
702
703 pce_stop();
704
705 print_state_cpu (sim->cpu);
706}
707
708static
709void c80_cmd_u (cpm80_t *sim, cmd_t *cmd)
710{
711 int to;
712 unsigned i;
713 unsigned short addr, cnt, taddr;
714 static unsigned int first = 1;
715 static unsigned short saddr = 0;
716 e8080_disasm_t op;
717 char str[256];
718
719 if (first) {
720 first = 0;
721 saddr = e8080_get_pc (sim->cpu);
722 }
723
724 to = 0;
725 addr = saddr;
726 cnt = 16;
727
728 if (cmd_match (cmd, "t")) {
729 to = 1;
730 }
731
732 if (cmd_match_uint16 (cmd, &addr)) {
733 cmd_match_uint16 (cmd, &cnt);
734 }
735
736 if (!cmd_match_end (cmd)) {
737 return;
738 }
739
740 if (to) {
741 if (addr < (2 * cnt)) {
742 taddr = 0;
743 }
744 else {
745 taddr = addr - 2 * cnt;
746 }
747
748 while (taddr <= addr) {
749 c80_disasm_mem (sim->cpu, &op, taddr);
750 c80_disasm_str (str, &op, 1, 1);
751
752 pce_printf ("%s\n", str);
753
754 taddr += op.data_cnt;
755 }
756 }
757 else {
758 for (i = 0; i < cnt; i++) {
759 c80_disasm_mem (sim->cpu, &op, addr);
760 c80_disasm_str (str, &op, 1, 1);
761
762 pce_printf ("%s\n", str);
763
764 addr += op.data_cnt;
765 }
766 }
767
768 saddr = addr;
769}
770
771int c80_cmd (cpm80_t *sim, cmd_t *cmd)
772{
773 if (cmd_match (cmd, "b")) {
774 cmd_do_b (cmd, &sim->bps);
775 }
776 else if (cmd_match (cmd, "c")) {
777 c80_cmd_c (sim, cmd);
778 }
779 else if (cmd_match (cmd, "g")) {
780 c80_cmd_g (sim, cmd);
781 }
782 else if (cmd_match (cmd, "i")) {
783 c80_cmd_i (sim, cmd);
784 }
785 else if (cmd_match (cmd, "o")) {
786 c80_cmd_o (sim, cmd);
787 }
788 else if (cmd_match (cmd, "p")) {
789 c80_cmd_p (sim, cmd);
790 }
791 else if (cmd_match (cmd, "r")) {
792 c80_cmd_r (sim, cmd);
793 }
794 else if (cmd_match (cmd, "s")) {
795 c80_cmd_s (sim, cmd);
796 }
797 else if (cmd_match (cmd, "trace")) {
798 c80_cmd_trace (sim, cmd);
799 }
800 else if (cmd_match (cmd, "t")) {
801 c80_cmd_t (sim, cmd);
802 }
803 else if (cmd_match (cmd, "u")) {
804 c80_cmd_u (sim, cmd);
805 }
806 else {
807 return (1);
808 }
809
810 return (0);
811}
812
813void c80_cmd_init (cpm80_t *sim, monitor_t *mon)
814{
815 mon_cmd_add (mon, par_cmd, sizeof (par_cmd) / sizeof (par_cmd[0]));
816 mon_cmd_add_bp (mon);
817
818 e8080_set_hook_undef_fct (sim->cpu, sim, c80_hook_undef);
819 e8080_set_hook_rst_fct (sim->cpu, sim, c80_hook_rst);
820}