fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/spectrum/cmd.c *
7 * Created: 2022-02-02 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2022-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 "snapshot.h"
25#include "spectrum.h"
26#include "video.h"
27
28#include <stdio.h>
29#include <string.h>
30
31#include <lib/brkpt.h>
32#include <lib/cmd.h>
33#include <lib/console.h>
34#include <lib/log.h>
35#include <lib/monitor.h>
36#include <lib/sysdep.h>
37
38
39static mon_cmd_t par_cmd[] = {
40 { "c", "[cnt]", "clock" },
41 { "gb", "[addr...]", "run with breakpoints" },
42 { "g", "", "run" },
43 { "hm", "", "print help on messages" },
44 { "i", "port", "input a byte from a port" },
45 { "last", "on|off", "start/stop recording pc values" },
46 { "last", "[cnt [idx]]", "print last pc values [80 0]" },
47 { "n", "[0|1]", "execute to next instruction" },
48 { "o", "port val", "output a byte to a port" },
49 { "p", "[cnt]", "execute cnt instructions, skip calls [1]" },
50 { "r", "reg [val]", "set a register" },
51 { "s", "[what]", "print status (cpu|mem)" },
52 { "t", "[cnt]", "execute cnt instructions [1]" },
53 { "u", "[addr [cnt]]", "disassemble" },
54 { "xl", "fname", "load a snapshot" },
55 { "xs", "fname", "save a snapshot" }
56};
57
58
59void spec_last_set (spectrum_t *sim, unsigned pc);
60
61
62static
63void spec_disasm_str (char *dst, e8080_disasm_t *op, int with_pc, int with_comment)
64{
65 unsigned i, k, n;
66 char comment[256];
67
68 comment[0] = 0;
69
70 if (with_pc) {
71 n = sprintf (dst, "%04X ", (unsigned) op->pc);
72 }
73 else {
74 n = 0;
75 }
76
77 for (i = 0; i < op->data_cnt; i++) {
78 n += sprintf (dst + n, "%02X ", (unsigned) op->data[i]);
79 }
80
81 for (i = op->data_cnt; i < 4; i++) {
82 dst[n++] = ' ';
83 dst[n++] = ' ';
84 dst[n++] = ' ';
85 }
86
87 k = n + 8;
88 n += sprintf (dst + n, "%s", op->op);
89
90 if (op->arg_cnt > 0) {
91 while (n < k) {
92 dst[n++] = ' ';
93 }
94
95 n += sprintf (dst + n, "%s", op->arg[0]);
96
97 for (i = 1; i < op->arg_cnt; i++) {
98 n += sprintf (dst + n, ", %s", op->arg[i]);
99 }
100 }
101
102 if (with_comment && (comment[0] != 0)) {
103 while (n < 40) {
104 dst[n++] = ' ';
105 }
106
107 dst[n++] = ';';
108 }
109
110 dst[n] = 0;
111}
112
113static
114void spec_disasm_cur (e8080_t *c, e8080_disasm_t *op)
115{
116 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
117 z80_disasm_cur (c, op);
118 }
119 else {
120 e8080_disasm_cur (c, op);
121 }
122}
123
124static
125void spec_disasm_mem (e8080_t *c, e8080_disasm_t *op, unsigned short addr)
126{
127 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
128 z80_disasm_mem (c, op, addr);
129 }
130 else {
131 e8080_disasm_mem (c, op, addr);
132 }
133}
134
135static
136void spec_print_cpu_z80_1 (e8080_t *c)
137{
138 e8080_disasm_t op;
139 char str[256];
140
141 spec_disasm_cur (c, &op);
142 spec_disasm_str (str, &op, 0, 0);
143
144 if (c->halt) {
145 pce_printf ("HALT=1 ");
146 }
147
148 pce_printf (
149 "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",
150 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
151 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
152 (unsigned) e8080_get_ix (c), (unsigned) e8080_get_iy (c),
153 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
154 (unsigned) e8080_get_psw (c),
155 (e8080_get_sf (c)) ? 'S' : '-',
156 (e8080_get_zf (c)) ? 'Z' : '-',
157 (e8080_get_af (c)) ? 'A' : '-',
158 (e8080_get_pf (c)) ? 'P' : '-',
159 (e8080_get_cf (c)) ? 'C' : '-',
160 str
161 );
162}
163
164static
165void spec_print_cpu_8080_1 (e8080_t *c)
166{
167 e8080_disasm_t op;
168 char str[256];
169
170 spec_disasm_cur (c, &op);
171 spec_disasm_str (str, &op, 0, 0);
172
173 if (c->halt) {
174 pce_printf ("HALT=1 ");
175 }
176
177 pce_printf (
178 "A=%02X BC=%04X DE=%04X HL=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c] %s\n",
179 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
180 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
181 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
182 (unsigned) e8080_get_psw (c),
183 (e8080_get_sf (c)) ? 'S' : '-',
184 (e8080_get_zf (c)) ? 'Z' : '-',
185 (e8080_get_af (c)) ? 'A' : '-',
186 (e8080_get_pf (c)) ? 'P' : '-',
187 (e8080_get_cf (c)) ? 'C' : '-',
188 str
189 );
190}
191
192static
193void spec_print_cpu_z80_2 (e8080_t *c)
194{
195 e8080_disasm_t op;
196 char str[256];
197
198 spec_disasm_cur (c, &op);
199 spec_disasm_str (str, &op, 1, 1);
200
201 pce_printf (
202 "A=%02X BC=%04X DE=%04X HL=%04X IX=%04X IY=%04X"
203 " SP=%04X PC=%04X F=%02X[%c%c%c%c%c] [%c%c]\n"
204 "R=%02X I=%02X IM=%u IFF=%u/%u IPC=%04X ICNT=%u HALT=%u\n"
205 "%s\n",
206 e8080_get_a (c), e8080_get_bc (c), e8080_get_de (c),
207 e8080_get_hl (c), e8080_get_ix (c), e8080_get_iy (c),
208 e8080_get_sp (c), e8080_get_pc (c),
209 e8080_get_psw (c),
210 (e8080_get_sf (c)) ? 'S' : '-',
211 (e8080_get_zf (c)) ? 'Z' : '-',
212 (e8080_get_af (c)) ? 'A' : '-',
213 (e8080_get_pf (c)) ? 'P' : '-',
214 (e8080_get_cf (c)) ? 'C' : '-',
215 c->int_val ? 'I' : '-',
216 c->nmi_val ? 'N' : '-',
217 e8080_get_r (c),
218 e8080_get_i (c),
219 e8080_get_im (c),
220 e8080_get_iff1 (c), e8080_get_iff2 (c),
221 e8080_get_int_pc (c), e8080_get_int_cnt (c),
222 e8080_get_halt (c),
223 str
224 );
225
226}
227
228static
229void spec_print_cpu_8080_2 (e8080_t *c)
230{
231 e8080_disasm_t op;
232 char str[256];
233
234 spec_disasm_cur (c, &op);
235 spec_disasm_str (str, &op, 1, 1);
236
237 pce_printf (
238 "A=%02X BC=%04X DE=%04X HL=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c]\n"
239 "%s\n",
240 (unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
241 (unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
242 (unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
243 (unsigned) e8080_get_psw (c),
244 (e8080_get_sf (c)) ? 'S' : '-',
245 (e8080_get_zf (c)) ? 'Z' : '-',
246 (e8080_get_af (c)) ? 'A' : '-',
247 (e8080_get_pf (c)) ? 'P' : '-',
248 (e8080_get_cf (c)) ? 'C' : '-',
249 str
250 );
251
252 if (c->halt) {
253 pce_printf ("HALT=1\n");
254 }
255}
256
257void spec_print_cpu (e8080_t *c, int oneline)
258{
259 if (oneline) {
260 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
261 spec_print_cpu_z80_1 (c);
262 }
263 else {
264 spec_print_cpu_8080_1 (c);
265 }
266 }
267 else {
268 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
269 spec_print_cpu_z80_2 (c);
270 }
271 else {
272 spec_print_cpu_8080_2 (c);
273 }
274 }
275}
276
277void print_state_cpu (e8080_t *c)
278{
279 if (e8080_get_flags (c) & E8080_FLAG_Z80) {
280 pce_prt_sep ("Z80");
281 }
282 else {
283 pce_prt_sep ("8080");
284 }
285
286 spec_print_cpu (c, 0);
287}
288
289static
290void print_state_mem (spectrum_t *sim)
291{
292 pce_prt_sep ("MEMORY");
293 mem_prt_state (sim->mem, stdout);
294}
295
296static
297void print_state_system (spectrum_t *sim)
298{
299 pce_prt_sep ("SPECTRUM");
300
301 pce_printf ("IM=%u\n", e8080_get_im (sim->cpu));
302 pce_printf ("FE = %02X\n", sim->port_fe);
303 pce_printf ("KEY=[%02X %02X %02X %02X %02X %02X %02X %02X]\n",
304 sim->keys[0], sim->keys[1], sim->keys[2], sim->keys[3],
305 sim->keys[4], sim->keys[5], sim->keys[6], sim->keys[7]
306 );
307}
308
309static
310void print_state_video (spectrum_t *sim)
311{
312 spec_video_t *vid;
313
314 vid = &sim->video;
315
316 pce_prt_sep ("VIDEO");
317
318 pce_printf ("FRAME=%lu+%lu ROW=%u+%u COL=%u DE=%d\n",
319 vid->frame_counter, vid->frame_clock, vid->row, vid->row_clock, 2 * vid->row_clock, vid->de
320 );
321}
322
323static
324void print_state (spectrum_t *sim, const char *str)
325{
326 cmd_t cmd;
327
328 cmd_set_str (&cmd, str);
329
330 if (cmd_match_eol (&cmd)) {
331 return;
332 }
333
334 while (!cmd_match_eol (&cmd)) {
335 if (cmd_match (&cmd, "cpu")) {
336 print_state_cpu (sim->cpu);
337 }
338 else if (cmd_match (&cmd, "mem")) {
339 print_state_mem (sim);
340 }
341 else if (cmd_match (&cmd, "sys")) {
342 print_state_system (sim);
343 }
344 else if (cmd_match (&cmd, "video")) {
345 print_state_video (sim);
346 }
347 else {
348 printf ("unknown component (%s)\n", cmd_get_str (&cmd));
349 return;
350 }
351 }
352}
353
354static
355int spec_check_break (spectrum_t *sim)
356{
357 if (bps_check (&sim->bps, 0, e8080_get_pc (sim->cpu), stdout)) {
358 return (1);
359 }
360
361 if (sim->brk) {
362 return (1);
363 }
364
365 return (0);
366}
367
368static
369int spec_exec (spectrum_t *sim)
370{
371 unsigned n1, n2;
372
373 n1 = e8080_get_opcnt (sim->cpu);
374
375 do {
376 spec_clock (sim);
377
378 if (sim->brk) {
379 return (1);
380 }
381
382 n2 = e8080_get_opcnt (sim->cpu);
383 } while (n1 == n2);
384
385 return (0);
386}
387
388static
389int spec_exec_to (spectrum_t *sim, unsigned short addr)
390{
391 while (e8080_get_pc (sim->cpu) != addr) {
392 spec_exec (sim);
393
394 if (spec_check_break (sim)) {
395 return (1);
396 }
397 }
398
399 return (0);
400}
401
402static
403int spec_exec_off (spectrum_t *sim, unsigned short addr)
404{
405 unsigned icnt;
406
407 icnt = e8080_get_int_cnt (sim->cpu);
408
409 while (e8080_get_pc (sim->cpu) == addr) {
410 spec_exec (sim);
411
412 if (spec_check_break (sim)) {
413 return (1);
414 }
415
416 if (e8080_get_int_cnt (sim->cpu) != icnt) {
417 if (spec_exec_to (sim, e8080_get_int_pc (sim->cpu))) {
418 return (1);
419 }
420
421 icnt = e8080_get_int_cnt (sim->cpu);
422 }
423 }
424
425 return (0);
426}
427
428void spec_run (spectrum_t *sim)
429{
430 pce_start (&sim->brk);
431
432 spec_clock_discontinuity (sim);
433
434 while (1) {
435 spec_clock (sim);
436
437 if (sim->brk) {
438 break;
439 }
440 }
441
442 pce_stop();
443}
444
445static
446int spec_hook_exec (void *ext)
447{
448 spectrum_t *sim = ext;
449
450 spec_last_set (sim, e8080_get_pc (sim->cpu));
451
452 return (0);
453}
454
455static
456int spec_hook_undef (void *ext, unsigned op)
457{
458 spectrum_t *sim = ext;
459
460 pce_log (MSG_DEB,
461 "%04X: undefined operation [%02X %02X %02X %02X]\n",
462 (unsigned) e8080_get_pc (sim->cpu),
463 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu)),
464 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 1),
465 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 2),
466 (unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 3)
467 );
468
469 /* pce_usleep (5000); */
470
471 return (0);
472}
473
474static
475int spec_hook_rst (void *ext, unsigned n)
476{
477 return (0);
478}
479
480void spec_last_enable (spectrum_t *sim, int enable)
481{
482 unsigned i;
483
484 enable = (enable != 0);
485
486 if (sim->last_enabled == enable) {
487 return;
488 }
489
490 sim->last_enabled = enable;
491 sim->last_idx = 0;
492
493 for (i = 0; i < SPEC_LAST_CNT; i++) {
494 sim->last[i] = 0;
495 }
496
497 if (sim->last_enabled) {
498 e8080_set_hook_exec_fct (sim->cpu, sim, spec_hook_exec);
499 }
500 else {
501 e8080_set_hook_exec_fct (sim->cpu, NULL, NULL);
502 }
503}
504
505unsigned spec_last_get (spectrum_t *sim, unsigned idx)
506{
507 if (sim->last_enabled == 0) {
508 return (0);
509 }
510
511 if (idx == 0) {
512 return (e8080_get_pc (sim->cpu));
513 }
514
515 if (idx > SPEC_LAST_CNT) {
516 return (0);
517 }
518
519 idx = (sim->last_idx + SPEC_LAST_CNT - (idx - 1)) % SPEC_LAST_CNT;
520
521 return (sim->last[idx]);
522}
523
524void spec_last_set (spectrum_t *sim, unsigned pc)
525{
526 if (sim->last[sim->last_idx] == pc) {
527 return;
528 }
529
530 sim->last_idx = (sim->last_idx + 1) % SPEC_LAST_CNT;
531 sim->last[sim->last_idx] = pc;
532}
533
534static
535void spec_cmd_c (cmd_t *cmd, spectrum_t *sim)
536{
537 unsigned short cnt;
538
539 cnt = 1;
540
541 cmd_match_uint16 (cmd, &cnt);
542
543 if (!cmd_match_end (cmd)) {
544 return;
545 }
546
547 while (cnt > 0) {
548 spec_clock (sim);
549 cnt -= 1;
550 }
551
552 print_state_cpu (sim->cpu);
553}
554
555static
556void spec_cmd_g_b (cmd_t *cmd, spectrum_t *sim)
557{
558 unsigned short addr;
559 breakpoint_t *bp;
560
561 while (cmd_match_uint16 (cmd, &addr)) {
562 bp = bp_addr_new (addr);
563 bps_bp_add (&sim->bps, bp);
564 }
565
566 if (!cmd_match_end (cmd)) {
567 return;
568 }
569
570 pce_start (&sim->brk);
571
572 spec_clock_discontinuity (sim);
573
574 while (1) {
575 spec_exec (sim);
576
577 if (spec_check_break (sim)) {
578 break;
579 }
580 }
581
582 pce_stop();
583}
584
585static
586void spec_cmd_g (cmd_t *cmd, spectrum_t *sim)
587{
588 if (cmd_match (cmd, "b")) {
589 spec_cmd_g_b (cmd, sim);
590 return;
591 }
592
593 if (!cmd_match_end (cmd)) {
594 return;
595 }
596
597 spec_run (sim);
598}
599
600static
601void spec_cmd_hm (cmd_t *cmd)
602{
603 pce_puts (
604 "emu.exit\n"
605 "emu.reset\n"
606 "emu.stop\n"
607 "\n"
608 "emu.cas.commit\n"
609 "emu.cas.create <filename>\n"
610 "emu.cas.play\n"
611 "emu.cas.load [<pos>]\n"
612 "emu.cas.read <filename>\n"
613 "emu.cas.record\n"
614 "emu.cas.space\n"
615 "emu.cas.state\n"
616 "emu.cas.stop\n"
617 "emu.cas.truncate\n"
618 "emu.cas.write <filename>\n"
619 "\n"
620 "emu.term.fullscreen \"0\" | \"1\"\n"
621 "emu.term.fullscreen.toggle\n"
622 "emu.term.grab\n"
623 "emu.term.release\n"
624 "emu.term.screenshot [<filename>]\n"
625 "emu.term.title <title>\n"
626 );
627}
628
629static
630void spec_cmd_i (cmd_t *cmd, spectrum_t *sim)
631{
632 unsigned short port;
633
634 while (cmd_match_uint16 (cmd, &port)) {
635 pce_printf ("%04X: %02X\n",
636 port, e8080_get_port8 (sim->cpu, port)
637 );
638 }
639
640 cmd_match_end (cmd);
641}
642
643static
644void spec_cmd_last (cmd_t *cmd, spectrum_t *sim)
645{
646 unsigned i, j, k;
647 unsigned col, pc;
648 unsigned short idx, cnt;
649
650 if (cmd_match (cmd, "on")) {
651 spec_last_enable (sim, 1);
652 cmd_match_end (cmd);
653 return;
654 }
655
656 if (cmd_match (cmd, "off")) {
657 spec_last_enable (sim, 0);
658 cmd_match_end (cmd);
659 return;
660 }
661
662 if (sim->last_enabled == 0) {
663 return;
664 }
665
666 col = 8;
667 cnt = 128;
668 idx = 0;
669
670 cmd_match_uint16 (cmd, &cnt);
671 cmd_match_uint16 (cmd, &idx);
672
673 if (!cmd_match_end (cmd)) {
674 return;
675 }
676
677 cnt = (cnt + col - 1) / col;
678
679 for (i = cnt; i > 0; i--) {
680 for (j = col; j > 0; j--) {
681 k = idx + (j - 1) * cnt + i - 1;
682 pc = spec_last_get (sim, k);
683 pce_printf (" %04X", pc);
684 }
685 pce_putc ('\n');
686 }
687}
688
689static
690void spec_cmd_n (cmd_t *cmd, spectrum_t *sim)
691{
692 int s;
693 unsigned pc;
694 unsigned short i, n;
695 e8080_disasm_t dis;
696
697 n = 1;
698 s = 0;
699
700 if (cmd_match_uint16 (cmd, &n)) {
701 s = 1;
702 }
703
704 if (!cmd_match_end (cmd)) {
705 return;
706 }
707
708 pce_start (&sim->brk);
709
710 spec_clock_discontinuity (sim);
711
712 for (i = 0; i < n; i++) {
713 spec_disasm_cur (sim->cpu, &dis);
714
715 if (s) {
716 spec_print_cpu (sim->cpu, 1);
717 }
718
719 pc = (e8080_get_pc (sim->cpu) + dis.data_cnt) & 0xffff;
720
721 if (spec_exec_to (sim, pc)) {
722 pce_printf ("T %04X\n", pc);
723 break;
724 }
725 }
726
727 if (s) {
728 spec_print_cpu (sim->cpu, 1);
729 }
730
731 pce_stop();
732
733 print_state_cpu (sim->cpu);
734}
735
736static
737void spec_cmd_o (cmd_t *cmd, spectrum_t *sim)
738{
739 unsigned short port, val;
740
741 if (!cmd_match_uint16 (cmd, &port)) {
742 cmd_error (cmd, "need a port address");
743 return;
744 }
745
746 if (!cmd_match_uint16 (cmd, &val)) {
747 cmd_error (cmd, "need a value");
748 return;
749 }
750
751 if (!cmd_match_end (cmd)) {
752 return;
753 }
754
755 e8080_set_port8 (sim->cpu, port, val);
756}
757
758static
759void spec_cmd_p (cmd_t *cmd, spectrum_t *sim)
760{
761 int s;
762 unsigned short i, n;
763 unsigned pc, to, op;
764
765 if (cmd_match (cmd, "o")) {
766 spec_cmd_n (cmd, sim);
767 return;
768 }
769
770 n = 1;
771 s = 0;
772
773 if (cmd_match_uint16 (cmd, &n)) {
774 s = 1;
775 }
776
777 if (!cmd_match_end (cmd)) {
778 return;
779 }
780
781 pce_start (&sim->brk);
782
783 spec_clock_discontinuity (sim);
784
785 for (i = 0; i < n; i++) {
786 if (s) {
787 spec_print_cpu (sim->cpu, 1);
788 }
789
790 pc = e8080_get_pc (sim->cpu);
791 op = e8080_get_mem8 (sim->cpu, pc);
792 to = pc;
793
794 if ((op == 0xcd) || ((op & 0xc7) == 0xc4)) {
795 /* call */
796 to = (pc + 3) & 0xffff;
797 }
798 else if ((op & 0xc7) == 0xc7) {
799 /* rst */
800 to = (pc + 1) & 0xffff;
801 }
802 else if (op == 0x10) {
803 /* djnz */
804 to = (pc + 2) & 0xffff;
805 }
806
807 if (to != pc) {
808 if (spec_exec_to (sim, to)) {
809 pce_printf ("T %04X\n", pc);
810 break;
811 }
812 }
813 else {
814 if (spec_exec_off (sim, pc)) {
815 pce_printf ("F %04X\n", pc);
816 break;
817 }
818 }
819 }
820
821 if (s) {
822 spec_print_cpu (sim->cpu, 1);
823 }
824
825 pce_stop();
826
827 print_state_cpu (sim->cpu);
828}
829
830static
831void spec_cmd_r (cmd_t *cmd, spectrum_t *sim)
832{
833 unsigned long val;
834 char sym[256];
835
836 if (cmd_match_eol (cmd)) {
837 print_state_cpu (sim->cpu);
838 return;
839 }
840
841 if (!cmd_match_ident (cmd, sym, 256)) {
842 cmd_error (cmd, "missing register");
843 return;
844 }
845
846 if (e8080_get_reg (sim->cpu, sym, &val)) {
847 cmd_error (cmd, "bad register\n");
848 return;
849 }
850
851 if (cmd_match_eol (cmd)) {
852 pce_printf ("%02lX\n", val);
853 return;
854 }
855
856 if (!cmd_match_uint32 (cmd, &val)) {
857 cmd_error (cmd, "missing value\n");
858 return;
859 }
860
861 if (!cmd_match_end (cmd)) {
862 return;
863 }
864
865 e8080_set_reg (sim->cpu, sym, val);
866
867 print_state_cpu (sim->cpu);
868}
869
870static
871void spec_cmd_s (cmd_t *cmd, spectrum_t *sim)
872{
873 if (cmd_match_eol (cmd)) {
874 print_state_cpu (sim->cpu);
875 return;
876 }
877
878 print_state (sim, cmd_get_str (cmd));
879}
880
881static
882void spec_cmd_t (cmd_t *cmd, spectrum_t *sim)
883{
884 int s;
885 unsigned short i, n;
886
887 n = 1;
888 s = 0;
889
890 if (cmd_match_uint16 (cmd, &n)) {
891 s = 1;
892 }
893
894 if (!cmd_match_end (cmd)) {
895 return;
896 }
897
898 pce_start (&sim->brk);
899
900 spec_clock_discontinuity (sim);
901
902 for (i = 0; i < n; i++) {
903 if (s) {
904 spec_print_cpu (sim->cpu, 1);
905 }
906
907 if (spec_exec (sim)) {
908 break;
909 }
910 }
911
912 if (s) {
913 spec_print_cpu (sim->cpu, 1);
914 }
915
916 pce_stop();
917
918 print_state_cpu (sim->cpu);
919}
920
921static
922void spec_cmd_u (cmd_t *cmd, spectrum_t *sim)
923{
924 int to;
925 unsigned i;
926 unsigned short addr, cnt, taddr;
927 static unsigned int first = 1;
928 static unsigned short saddr = 0;
929 e8080_disasm_t op;
930 char str[256];
931
932 if (first) {
933 first = 0;
934 saddr = e8080_get_pc (sim->cpu);
935 }
936
937 to = 0;
938 addr = saddr;
939 cnt = 16;
940
941 if (cmd_match (cmd, "t")) {
942 to = 1;
943 }
944
945 if (cmd_match_uint16 (cmd, &addr)) {
946 cmd_match_uint16 (cmd, &cnt);
947 }
948
949 if (!cmd_match_end (cmd)) {
950 return;
951 }
952
953 if (to) {
954 if (addr < (2 * cnt)) {
955 taddr = 0;
956 }
957 else {
958 taddr = addr - 2 * cnt;
959 }
960
961 while (taddr <= addr) {
962 spec_disasm_mem (sim->cpu, &op, taddr);
963 spec_disasm_str (str, &op, 1, 1);
964
965 pce_printf ("%s\n", str);
966
967 taddr += op.data_cnt;
968 }
969 }
970 else {
971 for (i = 0; i < cnt; i++) {
972 spec_disasm_mem (sim->cpu, &op, addr);
973 spec_disasm_str (str, &op, 1, 1);
974
975 pce_printf ("%s\n", str);
976
977 addr += op.data_cnt;
978 }
979 }
980
981 saddr = addr;
982}
983
984static
985void spec_cmd_xl (cmd_t *cmd, spectrum_t *sim)
986{
987 char name[256];
988
989 if (!cmd_match_str (cmd, name, 256)) {
990 return;
991 }
992
993 if (!cmd_match_end (cmd)) {
994 return;
995 }
996
997 if (spec_snap_load (sim, name)) {
998 pce_printf ("load error (%s)\n", name);
999 }
1000}
1001
1002static
1003void spec_cmd_xs (cmd_t *cmd, spectrum_t *sim)
1004{
1005 char name[256];
1006
1007 if (!cmd_match_str (cmd, name, 256)) {
1008 return;
1009 }
1010
1011 if (!cmd_match_end (cmd)) {
1012 return;
1013 }
1014
1015 if (spec_snap_save (sim, name)) {
1016 pce_printf ("load error (%s)\n", name);
1017 }
1018}
1019
1020static
1021void spec_cmd_x (cmd_t *cmd, spectrum_t *sim)
1022{
1023 if (cmd_match (cmd, "l")) {
1024 spec_cmd_xl (cmd, sim);
1025 }
1026 else if (cmd_match (cmd, "s")) {
1027 spec_cmd_xs (cmd, sim);
1028 }
1029 else {
1030 cmd_error (cmd, "\n");
1031 }
1032}
1033
1034int spec_cmd (spectrum_t *sim, cmd_t *cmd)
1035{
1036 if (sim->term != NULL) {
1037 trm_check (sim->term);
1038 }
1039
1040 if (cmd_match (cmd, "b")) {
1041 cmd_do_b (cmd, &sim->bps);
1042 }
1043 else if (cmd_match (cmd, "c")) {
1044 spec_cmd_c (cmd, sim);
1045 }
1046 else if (cmd_match (cmd, "g")) {
1047 spec_cmd_g (cmd, sim);
1048 }
1049 else if (cmd_match (cmd, "hm")) {
1050 spec_cmd_hm (cmd);
1051 }
1052 else if (cmd_match (cmd, "i")) {
1053 spec_cmd_i (cmd, sim);
1054 }
1055 else if (cmd_match (cmd, "last")) {
1056 spec_cmd_last (cmd, sim);
1057 }
1058 else if (cmd_match (cmd, "n")) {
1059 spec_cmd_n (cmd, sim);
1060 }
1061 else if (cmd_match (cmd, "o")) {
1062 spec_cmd_o (cmd, sim);
1063 }
1064 else if (cmd_match (cmd, "p")) {
1065 spec_cmd_p (cmd, sim);
1066 }
1067 else if (cmd_match (cmd, "r")) {
1068 spec_cmd_r (cmd, sim);
1069 }
1070 else if (cmd_match (cmd, "s")) {
1071 spec_cmd_s (cmd, sim);
1072 }
1073 else if (cmd_match (cmd, "t")) {
1074 spec_cmd_t (cmd, sim);
1075 }
1076 else if (cmd_match (cmd, "u")) {
1077 spec_cmd_u (cmd, sim);
1078 }
1079 else if (cmd_match (cmd, "x")) {
1080 spec_cmd_x (cmd, sim);
1081 }
1082 else {
1083 return (1);
1084 }
1085
1086 return (0);
1087}
1088
1089void spec_cmd_init (spectrum_t *sim, monitor_t *mon)
1090{
1091 mon_cmd_add (mon, par_cmd, sizeof (par_cmd) / sizeof (par_cmd[0]));
1092 mon_cmd_add_bp (mon);
1093
1094 e8080_set_hook_exec_fct (sim->cpu, NULL, NULL);
1095 e8080_set_hook_undef_fct (sim->cpu, sim, spec_hook_undef);
1096 e8080_set_hook_rst_fct (sim->cpu, sim, spec_hook_rst);
1097}