fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 816 lines 15 kB view raw
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}