fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/vic20/cmd.c *
7 * Created: 2020-04-18 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2020-2022 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 "cmd.h"
25#include "vic20.h"
26
27#include <string.h>
28
29#include <lib/console.h>
30#include <lib/log.h>
31#include <lib/monitor.h>
32#include <lib/sysdep.h>
33
34
35static mon_cmd_t par_cmd[] = {
36 { "c", "[cnt]", "clock" },
37 { "gb", "[addr...]", "run with breakpoints" },
38 { "g", "", "run" },
39 { "hm", "", "print help on messages" },
40 { "p", "[cnt]", "execute cnt instructions, skip calls [1]" },
41 { "r", "reg [val]", "get or set a register" },
42 { "s", "[what]", "print status (cpu|mem)" },
43 { "trace", "[on|off|expr]", "turn trace on or off" },
44 { "t", "[cnt]", "execute cnt instructions [1]" },
45 { "u", "[addr [cnt]]", "disassemble" },
46 { "vsync", "[cnt]", "clock until vsync" }
47};
48
49
50static
51void v20_disasm_str (char *dst, e6502_disasm_t *op)
52{
53 unsigned i, n;
54
55 n = sprintf (dst, "%04X ", (unsigned) op->pc);
56
57 for (i = 0; i < op->dat_n; i++) {
58 n += sprintf (dst + n, " %02X", (unsigned) op->dat[i]);
59 }
60
61 while (n < 15) {
62 dst[n++] = ' ';
63 }
64
65 if (op->flags & E6502_OPF_UND) {
66 dst[n++] = '*';
67 }
68 else {
69 dst[n++] = ' ';
70 }
71
72 n += sprintf (dst + n, "%s", op->op);
73
74 if (op->arg_n > 0) {
75 while (n < 21) {
76 dst[n++] = ' ';
77 }
78
79 n += sprintf (dst + n, "%s", op->arg1);
80 }
81
82 dst[n] = 0;
83}
84
85void v20_print_state_cpu (e6502_t *c)
86{
87 e6502_disasm_t op;
88 char str[256];
89
90 pce_prt_sep ("6502");
91
92 pce_printf (
93 "A=%02X X=%02X Y=%02X S=%02X P=%02X "
94 "[%c%c-%c%c%c%c%c] PC=%04X CLK=%lX\n",
95 (unsigned) e6502_get_a (c),
96 (unsigned) e6502_get_x (c),
97 (unsigned) e6502_get_y (c),
98 (unsigned) e6502_get_s (c),
99 (unsigned) e6502_get_p (c),
100 (e6502_get_nf (c)) ? 'N' : '-',
101 (e6502_get_vf (c)) ? 'V' : '-',
102 (e6502_get_bf (c)) ? 'B' : '-',
103 (e6502_get_df (c)) ? 'D' : '-',
104 (e6502_get_if (c)) ? 'I' : '-',
105 (e6502_get_cf (c)) ? 'C' : '-',
106 (e6502_get_zf (c)) ? 'Z' : '-',
107 (unsigned) e6502_get_pc (c),
108 e6502_get_clock (c)
109 );
110
111 e6502_disasm_cur (c, &op);
112 v20_disasm_str (str, &op);
113
114 pce_printf ("%s\n", str);
115}
116
117void v20_print_trace (e6502_t *c)
118{
119 e6502_disasm_t op;
120 char str[256];
121
122 e6502_disasm_cur (c, &op);
123
124 switch (op.arg_n) {
125 case 0:
126 strcpy (str, op.op);
127 break;
128
129 case 1:
130 sprintf (str, "%-4s %s", op.op, op.arg1);
131 break;
132
133 default:
134 strcpy (str, "****");
135 break;
136 }
137
138 pce_printf ("%c%c-%c%c%c%c%c P=%02X S=%02X A=%02X X=%02X Y=%02X %04X %s\n",
139 (e6502_get_nf (c)) ? 'N' : '-',
140 (e6502_get_vf (c)) ? 'V' : '-',
141 (e6502_get_bf (c)) ? 'B' : '-',
142 (e6502_get_df (c)) ? 'D' : '-',
143 (e6502_get_if (c)) ? 'I' : '-',
144 (e6502_get_cf (c)) ? 'C' : '-',
145 (e6502_get_zf (c)) ? 'Z' : '-',
146 (unsigned) e6502_get_p (c),
147 (unsigned) e6502_get_s (c),
148 (unsigned) e6502_get_a (c),
149 (unsigned) e6502_get_x (c),
150 (unsigned) e6502_get_y (c),
151 (unsigned) e6502_get_pc (c),
152 str
153 );
154}
155
156static
157void v20_print_state_mem (vic20_t *sim)
158{
159 pce_prt_sep ("6502 MEM");
160 mem_prt_state (sim->mem, stdout);
161}
162
163static
164void v20_print_state_via (vic20_t *sim, unsigned idx)
165{
166 unsigned char pa, pb;
167 e6522_t *via;
168
169 if (idx == 1) {
170 via = &sim->via1;
171 pce_prt_sep ("6522 VIA 1");
172 }
173 else if (idx == 2) {
174 via = &sim->via2;
175 pce_prt_sep ("6522 VIA 2");
176 }
177 else {
178 return;
179 }
180
181 pa = (via->ora & via->ddra) | (via->ira & ~via->ddra);
182 pb = (via->orb & via->ddrb) | (via->irb & ~via->ddrb);
183
184 pce_printf ("DDA=%02X ORA=%02X IRA=%02X VAL=%02X\n",
185 via->ddra, via->ora, via->ira, pa
186 );
187
188 pce_printf ("DDB=%02X ORB=%02X IRB=%02X VAL=%02X\n",
189 via->ddrb, via->orb, via->irb, pb
190 );
191
192 pce_printf ("CA1=%X CB1=%X\n",
193 via->ca1_inp, via->cb1_inp
194 );
195
196 pce_printf ("ACR=%02X PCR=%02X\n", via->acr, via->pcr);
197
198 pce_printf ("T1V=%04X T1L=%04X T1H=%d\n",
199 via->t1_val, via->t1_latch, via->t1_hot
200 );
201
202 pce_printf ("T2V=%04X T2L=%04X T2H=%d\n",
203 via->t2_val, via->t2_latch, via->t2_hot
204 );
205
206 pce_printf ("IER=%02X IFR=%02X IRQ=%d\n",
207 via->ier, via->ifr, via->irq_val
208 );
209}
210
211static
212void v20_print_state (vic20_t *sim, const char *str)
213{
214 cmd_t cmd;
215
216 cmd_set_str (&cmd, str);
217
218 if (cmd_match_eol (&cmd)) {
219 return;
220 }
221
222 while (!cmd_match_eol (&cmd)) {
223 if (cmd_match (&cmd, "cpu")) {
224 v20_print_state_cpu (sim->cpu);
225 }
226 else if (cmd_match (&cmd, "mem")) {
227 v20_print_state_mem (sim);
228 }
229 else if (cmd_match (&cmd, "via1")) {
230 v20_print_state_via (sim, 1);
231 }
232 else if (cmd_match (&cmd, "via2")) {
233 v20_print_state_via (sim, 2);
234 }
235 else if (cmd_match (&cmd, "via")) {
236 v20_print_state_via (sim, 1);
237 v20_print_state_via (sim, 2);
238 }
239 else if (cmd_match (&cmd, "vic")) {
240 v20_video_print_state (&sim->video);
241 }
242 else {
243 pce_printf ("unknown component (%s)\n", cmd_get_str (&cmd));
244 return;
245 }
246 }
247}
248
249/*
250 * Check if a breakpoint has triggered
251 */
252static
253int v20_check_break (vic20_t *sim)
254{
255 unsigned pc;
256
257 pc = e6502_get_pc (sim->cpu) & 0xffff;
258
259 if (bps_check (&sim->bps, 0, pc, stdout)) {
260 return (1);
261 }
262
263 if (sim->brk) {
264 return (1);
265 }
266
267 return (0);
268}
269
270static
271void v20_exec (vic20_t *sim)
272{
273 unsigned long old;
274
275 old = e6502_get_opcnt (sim->cpu);
276
277 while (e6502_get_opcnt (sim->cpu) == old) {
278 v20_clock (sim);
279 }
280}
281
282static
283int v20_exec_to (vic20_t *sim, unsigned short addr)
284{
285 while (e6502_get_pc (sim->cpu) != addr) {
286 v20_clock (sim);
287
288 if (sim->brk) {
289 return (1);
290 }
291 }
292
293 return (0);
294}
295
296static
297int v20_exec_off (vic20_t *sim, unsigned short addr)
298{
299 while (e6502_get_pc (sim->cpu) == addr) {
300 v20_clock (sim);
301
302 if (sim->brk) {
303 return (1);
304 }
305 }
306
307 return (0);
308}
309
310void v20_run (vic20_t *sim)
311{
312 pce_start (&sim->brk);
313
314 v20_clock_resync (sim);
315
316 while (1) {
317 v20_clock (sim);
318
319 if (sim->brk) {
320 break;
321 }
322 }
323
324 pce_stop();
325}
326
327
328static
329int v20_op_undef (void *ext, unsigned char op)
330{
331 vic20_t *sim;
332
333 sim = ext;
334
335 pce_log (MSG_DEB,
336 "%04X: undefined operation [%02X]\n",
337 (unsigned) e6502_get_pc (sim->cpu), (unsigned) op
338 );
339
340 sim->brk = PCE_BRK_STOP;
341
342 return (0);
343}
344
345static
346int v20_op_brk (void *ext, unsigned char op)
347{
348 vic20_t *sim;
349
350 sim = ext;
351 sim->brk = PCE_BRK_STOP;
352
353 return (1);
354}
355
356static
357void v20_cmd_bsave (cmd_t *cmd, vic20_t *sim)
358{
359 unsigned i, val;
360 unsigned addr1, addr2;
361 char fname[256];
362 FILE *fp;
363
364 if (!cmd_match_str (cmd, fname, 256)) {
365 cmd_error (cmd, "need a file name");
366 return;
367 }
368
369 if (!cmd_match_end (cmd)) {
370 return;
371 }
372
373 addr1 = mem_get_uint16_le (sim->mem, 0x2b);
374 addr2 = mem_get_uint16_le (sim->mem, 0x2d);
375
376 if ((fp = fopen (fname, "wb")) == NULL) {
377 pce_printf ("can't open file (%s)\n", fname);
378 return;
379 }
380
381 fputc (addr1 & 0xff, fp);
382 fputc ((addr1 >> 8) & 0xff, fp);
383
384 for (i = addr1; i < addr2; i++) {
385 val = mem_get_uint8 (sim->mem, i);
386
387 fputc (val, fp);
388 }
389
390 fclose (fp);
391}
392
393static
394void v20_cmd_vsync (cmd_t *cmd, vic20_t *sim)
395{
396 unsigned short cnt;
397 unsigned vs;
398
399 cnt = 1;
400
401 cmd_match_uint16 (cmd, &cnt);
402
403 if (!cmd_match_end (cmd)) {
404 return;
405 }
406
407 v20_clock_resync (sim);
408
409 while (cnt-- > 0) {
410 vs = sim->video.vsync_cnt;
411
412 while (sim->video.vsync_cnt == vs) {
413 v20_clock (sim);
414 }
415 }
416
417 v20_print_state_cpu (sim->cpu);
418}
419
420static
421void v20_cmd_c (cmd_t *cmd, vic20_t *sim)
422{
423 unsigned short cnt;
424
425 cnt = 1;
426
427 cmd_match_uint16 (cmd, &cnt);
428
429 if (!cmd_match_end (cmd)) {
430 return;
431 }
432
433 v20_clock_resync (sim);
434
435 while (cnt-- > 0) {
436 v20_clock (sim);
437 }
438
439 v20_print_state_cpu (sim->cpu);
440}
441
442static
443void v20_cmd_gb (cmd_t *cmd, vic20_t *sim)
444{
445 unsigned short addr;
446 breakpoint_t *bp;
447
448 while (cmd_match_uint16 (cmd, &addr)) {
449 bp = bp_addr_new (addr);
450 bps_bp_add (&sim->bps, bp);
451 }
452
453 if (!cmd_match_end (cmd)) {
454 return;
455 }
456
457 pce_start (&sim->brk);
458
459 v20_clock_resync (sim);
460
461 while (1) {
462 if (sim->trace) {
463 v20_print_trace (sim->cpu);
464 }
465
466 v20_exec (sim);
467
468 if (v20_check_break (sim)) {
469 break;
470 }
471 }
472
473 pce_stop();
474}
475
476static
477void v20_cmd_g (cmd_t *cmd, vic20_t *sim)
478{
479 if (cmd_match (cmd, "b")) {
480 v20_cmd_gb (cmd, sim);
481 return;
482 }
483
484 if (!cmd_match_end (cmd)) {
485 return;
486 }
487
488 v20_run (sim);
489}
490
491static
492void v20_cmd_hm (cmd_t *cmd)
493{
494 pce_puts (
495 "emu.config.save\n <filename>\n"
496 "emu.exit\n"
497 "emu.reset\n"
498 "emu.stop\n"
499 "\n"
500 "emu.cas.commit\n"
501 "emu.cas.create <filename>\n"
502 "emu.cas.play\n"
503 "emu.cas.load [<pos>]\n"
504 "emu.cas.read <filename>\n"
505 "emu.cas.record\n"
506 "emu.cas.space\n"
507 "emu.cas.state\n"
508 "emu.cas.stop\n"
509 "emu.cas.truncate\n"
510 "emu.cas.write <filename>\n"
511 "\n"
512 "emu.cpu.speed <factor>\n"
513 "emu.cpu.speed.step <adjustment>\n"
514 "\n"
515 "emu.term.fullscreen \"0\" | \"1\"\n"
516 "emu.term.fullscreen.toggle\n"
517 "emu.term.grab\n"
518 "emu.term.release\n"
519 "emu.term.screenshot [<filename>]\n"
520 "emu.term.title <title>\n"
521 "\n"
522 "emu.video.brightness <brightness>\n"
523 "emu.video.framedrop <count>\n"
524 "emu.video.hue <hue>\n"
525 "emu.video.saturation <saturation>\n"
526 );
527}
528
529static
530void v20_cmd_n (cmd_t *cmd, vic20_t *sim)
531{
532 unsigned pc;
533 e6502_disasm_t dis;
534
535 if (!cmd_match_end (cmd)) {
536 return;
537 }
538
539 e6502_disasm_cur (sim->cpu, &dis);
540
541 pc = (e6502_get_pc (sim->cpu) + dis.dat_n) & 0xffff;
542
543 pce_start (&sim->brk);
544
545 v20_clock_resync (sim);
546
547 while (e6502_get_pc (sim->cpu) != pc) {
548 if (sim->trace) {
549 v20_print_trace (sim->cpu);
550 }
551
552 v20_exec (sim);
553
554 if (v20_check_break (sim)) {
555 break;
556 }
557 }
558
559 pce_stop();
560
561 v20_print_state_cpu (sim->cpu);
562}
563
564static
565void v20_cmd_p (cmd_t *cmd, vic20_t *sim)
566{
567 unsigned short cnt;
568 e6502_disasm_t dis;
569
570 cnt = 1;
571
572 cmd_match_uint16 (cmd, &cnt);
573
574 if (!cmd_match_end (cmd)) {
575 return;
576 }
577
578 pce_start (&sim->brk);
579
580 v20_clock_resync (sim);
581
582 while (cnt > 0) {
583 e6502_disasm_cur (sim->cpu, &dis);
584
585 if (sim->trace) {
586 v20_print_trace (sim->cpu);
587 }
588
589 if (dis.flags & E6502_OPF_JSR) {
590 if (v20_exec_to (sim, dis.pc + dis.dat_n)) {
591 break;
592 }
593 }
594 else {
595 if (v20_exec_off (sim, dis.pc)) {
596 break;
597 }
598 }
599
600 cnt -= 1;
601 }
602
603 pce_stop();
604
605 v20_print_state_cpu (sim->cpu);
606}
607
608static
609void v20_cmd_r (cmd_t *cmd, vic20_t *sim)
610{
611 unsigned long val;
612 char sym[256];
613
614 if (cmd_match_eol (cmd)) {
615 v20_print_state_cpu (sim->cpu);
616 return;
617 }
618
619 if (!cmd_match_ident (cmd, sym, 256)) {
620 cmd_error (cmd, "missing register\n");
621 return;
622 }
623
624 if (e6502_get_reg (sim->cpu, sym, &val)) {
625 pce_printf ("bad register\n");
626 return;
627 }
628
629 if (cmd_match_eol (cmd)) {
630 pce_printf ("%02lX\n", val);
631 return;
632 }
633
634 if (!cmd_match_uint32 (cmd, &val)) {
635 cmd_error (cmd, "missing value\n");
636 return;
637 }
638
639 if (!cmd_match_end (cmd)) {
640 return;
641 }
642
643 e6502_set_reg (sim->cpu, sym, val);
644
645 v20_print_state_cpu (sim->cpu);
646}
647
648static
649void v20_cmd_s (cmd_t *cmd, vic20_t *sim)
650{
651 if (cmd_match_eol (cmd)) {
652 v20_print_state_cpu (sim->cpu);
653 return;
654 }
655
656 v20_print_state (sim, cmd_get_str (cmd));
657}
658
659static
660void v20_cmd_trace (cmd_t *cmd, vic20_t *sim)
661{
662 unsigned short v;
663
664 if (cmd_match_eol (cmd)) {
665 pce_printf ("trace is %s\n", sim->trace ? "on" : "off");
666 return;
667 }
668
669 if (cmd_match (cmd, "on")) {
670 sim->trace = 1;
671 }
672 else if (cmd_match (cmd, "off")) {
673 sim->trace = 0;
674 }
675 else if (cmd_match_uint16 (cmd, &v)) {
676 sim->trace = (v != 0);
677 }
678 else {
679 cmd_error (cmd, "on or off expected\n");
680 }
681}
682
683static
684void v20_cmd_t (cmd_t *cmd, vic20_t *sim)
685{
686 unsigned short i, n;
687
688 n = 1;
689
690 cmd_match_uint16 (cmd, &n);
691
692 if (!cmd_match_end (cmd)) {
693 return;
694 }
695
696 pce_start (&sim->brk);
697
698 v20_clock_resync (sim);
699
700 for (i = 0; i < n; i++) {
701 if (sim->trace) {
702 v20_print_trace (sim->cpu);
703 }
704
705 v20_exec (sim);
706
707 if (v20_check_break (sim)) {
708 break;
709 }
710 }
711
712 pce_stop();
713
714 v20_print_state_cpu (sim->cpu);
715}
716
717static
718void v20_cmd_u (cmd_t *cmd, vic20_t *sim)
719{
720 unsigned i;
721 unsigned short addr, cnt;
722 static unsigned int first = 1;
723 static unsigned short saddr = 0;
724 e6502_disasm_t op;
725 char str[256];
726
727 if (first) {
728 first = 0;
729 saddr = e6502_get_pc (sim->cpu);
730 }
731
732 addr = saddr;
733 cnt = 16;
734
735 if (cmd_match_uint16 (cmd, &addr)) {
736 cmd_match_uint16 (cmd, &cnt);
737 }
738
739 if (!cmd_match_end (cmd)) {
740 return;
741 }
742
743 for (i = 0; i < cnt; i++) {
744 e6502_disasm_mem (sim->cpu, &op, addr);
745 v20_disasm_str (str, &op);
746
747 pce_printf ("%s\n", str);
748
749 addr += op.dat_n;
750 }
751
752 saddr = addr;
753}
754
755int v20_cmd (vic20_t *sim, cmd_t *cmd)
756{
757 if (sim->trm != NULL) {
758 trm_check (sim->trm);
759 }
760
761 if (cmd_match (cmd, "bsave")) {
762 v20_cmd_bsave (cmd, sim);
763 }
764 else if (cmd_match (cmd, "b")) {
765 cmd_do_b (cmd, &sim->bps);
766 }
767 else if (cmd_match (cmd, "c")) {
768 v20_cmd_c (cmd, sim);
769 }
770 else if (cmd_match (cmd, "g")) {
771 v20_cmd_g (cmd, sim);
772 }
773 else if (cmd_match (cmd, "hm")) {
774 v20_cmd_hm (cmd);
775 }
776 else if (cmd_match (cmd, "n")) {
777 v20_cmd_n (cmd, sim);
778 }
779 else if (cmd_match (cmd, "p")) {
780 v20_cmd_p (cmd, sim);
781 }
782 else if (cmd_match (cmd, "r")) {
783 v20_cmd_r (cmd, sim);
784 }
785 else if (cmd_match (cmd, "s")) {
786 v20_cmd_s (cmd, sim);
787 }
788 else if (cmd_match (cmd, "trace")) {
789 v20_cmd_trace (cmd, sim);
790 }
791 else if (cmd_match (cmd, "t")) {
792 v20_cmd_t (cmd, sim);
793 }
794 else if (cmd_match (cmd, "u")) {
795 v20_cmd_u (cmd, sim);
796 }
797 else if (cmd_match (cmd, "vsync")) {
798 v20_cmd_vsync (cmd, sim);
799 }
800 else {
801 return (1);
802 }
803
804 return (0);
805}
806
807void v20_cmd_init (vic20_t *sim, monitor_t *mon)
808{
809 mon_cmd_add (mon, par_cmd, sizeof (par_cmd) / sizeof (par_cmd[0]));
810 mon_cmd_add_bp (mon);
811
812 sim->cpu->hook_ext = sim;
813 sim->cpu->hook_all = NULL;
814 sim->cpu->hook_undef = v20_op_undef;
815 sim->cpu->hook_brk = v20_op_brk;
816}