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