fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/ibmpc/cmd.c *
7 * Created: 2010-09-21 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2010-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 "ibmpc.h"
25
26#include <stdio.h>
27#include <string.h>
28
29#include <lib/brkpt.h>
30#include <lib/cmd.h>
31#include <lib/console.h>
32#include <lib/log.h>
33#include <lib/monitor.h>
34#include <lib/msgdsk.h>
35#include <lib/sysdep.h>
36
37
38static mon_cmd_t par_cmd[] = {
39 { "boot", "[drive]", "set the boot drive" },
40 { "c", "[cnt]", "clock [1]" },
41 { "gb", "[addr...]", "run with breakpoints" },
42 { "g", "far", "run until CS changes" },
43 { "g", "", "run" },
44 { "hm", "", "print help on messages" },
45 { "i", "[b|w] port", "input a byte or word from a port" },
46 { "key", "[[+|-]key...]", "simulate pressing or releasing keys" },
47 { "log", "int l", "list interrupt log expressions" },
48 { "log", "int n [expr]", "set interrupt n log expression to expr" },
49 { "o", "[b|w] port val", "output a byte or word to a port" },
50 { "pq", "[c|f|s]", "prefetch queue clear/fill/status" },
51 { "p", "[cnt]", "execute cnt instructions, without trace in calls [1]" },
52 { "r", "[reg val]", "set a register" },
53 { "s", "[what]", "print status (pc|cpu|disks|ems|mem|pic|pit|ports|ppi|time|uart|video|xms)" },
54 { "trace", "on|off|expr", "turn trace on or off" },
55 { "t", "[cnt]", "execute cnt instructions [1]" },
56 { "u", "[addr [cnt [mode]]]", "disassemble" }
57};
58
59
60static
61void disasm_str (char *dst, e86_disasm_t *op)
62{
63 unsigned i;
64 unsigned dst_i;
65
66 dst_i = 2;
67 sprintf (dst, "%02X", op->dat[0]);
68
69 for (i = 1; i < op->dat_n; i++) {
70 sprintf (dst + dst_i, " %02X", op->dat[i]);
71 dst_i += 3;
72 }
73
74 dst[dst_i++] = ' ';
75 while (dst_i < 20) {
76 dst[dst_i++] = ' ';
77 }
78
79 if ((op->flags & ~(E86_DFLAGS_CALL | E86_DFLAGS_LOOP)) != 0) {
80 unsigned flg;
81
82 flg = op->flags;
83
84 dst[dst_i++] = '[';
85
86 if (flg & E86_DFLAGS_186) {
87 dst_i += sprintf (dst + dst_i, "186");
88 flg &= ~E86_DFLAGS_186;
89 }
90
91 if (flg != 0) {
92 if (flg != op->flags) {
93 dst[dst_i++] = ' ';
94 }
95 dst_i += sprintf (dst + dst_i, " %04X", flg);
96 }
97 dst[dst_i++] = ']';
98 dst[dst_i++] = ' ';
99 }
100
101 strcpy (dst + dst_i, op->op);
102 while (dst[dst_i] != 0) {
103 dst_i += 1;
104 }
105
106 if (op->arg_n > 0) {
107 dst[dst_i++] = ' ';
108 while (dst_i < 26) {
109 dst[dst_i++] = ' ';
110 }
111 }
112
113 if (op->arg_n == 1) {
114 dst_i += sprintf (dst + dst_i, "%s", op->arg1);
115 }
116 else if (op->arg_n == 2) {
117 dst_i += sprintf (dst + dst_i, "%s, %s", op->arg1, op->arg2);
118 }
119
120 dst[dst_i] = 0;
121}
122
123static
124void prt_uint8_bin (unsigned char val)
125{
126 unsigned i;
127 unsigned char m;
128 char str[16];
129
130 m = 0x80;
131
132 for (i = 0; i < 8; i++) {
133 str[i] = (val & m) ? '1' : '0';
134 m = m >> 1;
135 }
136
137 str[8] = 0;
138
139 pce_puts (str);
140}
141
142static
143void prt_state_video (video_t *vid)
144{
145 FILE *fp;
146
147 pce_prt_sep ("video");
148
149 pce_video_print_info (vid, pce_get_fp_out());
150
151 fp = pce_get_redir_out();
152 if (fp != NULL) {
153 pce_video_print_info (vid, fp);
154 }
155}
156
157static
158void prt_state_ems (ems_t *ems)
159{
160 pce_prt_sep ("EMS");
161 ems_prt_state (ems);
162}
163
164static
165void prt_state_xms (xms_t *xms)
166{
167 pce_prt_sep ("XMS");
168 xms_prt_state (xms);
169}
170
171static
172void prt_state_pit (e8253_t *pit)
173{
174 unsigned i;
175 e8253_counter_t *cnt;
176
177 pce_prt_sep ("8253-PIT");
178
179 for (i = 0; i < 3; i++) {
180 cnt = &pit->counter[i];
181
182 pce_printf (
183 "C%d: SR=%02X M=%u RW=%d CE=%04X %s=%02X %s=%02X %s=%02X %s=%02X "
184 "G=%u O=%u R=%d\n",
185 i,
186 cnt->sr, cnt->mode, cnt->rw,
187 cnt->ce,
188 (cnt->cr_wr & 2) ? "cr1" : "CR1", cnt->cr[1],
189 (cnt->cr_wr & 1) ? "cr0" : "CR0", cnt->cr[0],
190 (cnt->ol_rd & 2) ? "ol1" : "OL1", cnt->ol[1],
191 (cnt->ol_rd & 1) ? "ol0" : "OL0", cnt->ol[0],
192 (unsigned) cnt->gate_val,
193 (unsigned) cnt->out_val,
194 cnt->counting
195 );
196 }
197}
198
199static
200void prt_state_ppi (e8255_t *ppi)
201{
202 pce_prt_sep ("8255-PPI");
203
204 pce_printf (
205 "MOD=%02X MODA=%u MODB=%u",
206 ppi->mode, ppi->group_a_mode, ppi->group_b_mode
207 );
208
209 if (ppi->port[0].inp != 0) {
210 pce_printf (" A=I[%02X]", e8255_get_inp (ppi, 0));
211 }
212 else {
213 pce_printf (" A=O[%02X]", e8255_get_out (ppi, 0));
214 }
215
216 if (ppi->port[1].inp != 0) {
217 pce_printf (" B=I[%02X]", e8255_get_inp (ppi, 1));
218 }
219 else {
220 pce_printf (" B=O[%02X]", e8255_get_out (ppi, 1));
221 }
222
223 switch (ppi->port[2].inp) {
224 case 0xff:
225 pce_printf (" C=I[%02X]", e8255_get_inp (ppi, 2));
226 break;
227
228 case 0x00:
229 pce_printf (" C=O[%02X]", e8255_get_out (ppi, 2));
230 break;
231
232 case 0x0f:
233 pce_printf (" CH=O[%X] CL=I[%X]",
234 (e8255_get_out (ppi, 2) >> 4) & 0x0f,
235 e8255_get_inp (ppi, 2) & 0x0f
236 );
237 break;
238
239 case 0xf0:
240 pce_printf (" CH=I[%X] CL=O[%X]",
241 (e8255_get_inp (ppi, 2) >> 4) & 0x0f,
242 e8255_get_out (ppi, 2) & 0x0f
243 );
244 break;
245 }
246
247 pce_puts ("\n");
248}
249
250static
251void prt_state_dma (e8237_t *dma)
252{
253 unsigned i;
254
255 pce_prt_sep ("8237-DMAC");
256
257 pce_printf ("CMD=%02X PRI=%02X CHK=%d\n",
258 e8237_get_command (dma),
259 e8237_get_priority (dma),
260 dma->check != 0
261 );
262
263 for (i = 0; i < 4; i++) {
264 unsigned short state;
265
266 state = e8237_get_state (dma, i);
267
268 pce_printf (
269 "CHN %u: MODE=%02X ADDR=%04X[%04X] CNT=%04X[%04X] DREQ=%d SREQ=%d MASK=%d\n",
270 i,
271 e8237_get_mode (dma, i) & 0xfcU,
272 e8237_get_addr (dma, i),
273 e8237_get_addr_base (dma, i),
274 e8237_get_cnt (dma, i),
275 e8237_get_cnt_base (dma, i),
276 (state & E8237_STATE_DREQ) != 0,
277 (state & E8237_STATE_SREQ) != 0,
278 (state & E8237_STATE_MASK) != 0
279 );
280 }
281}
282
283static
284void prt_state_pic (e8259_t *pic)
285{
286 unsigned i;
287
288 pce_prt_sep ("8259A-PIC");
289
290 pce_puts ("INP=");
291 prt_uint8_bin (pic->irq_inp);
292 pce_puts ("\n");
293
294 pce_puts ("IRR=");
295 prt_uint8_bin (e8259_get_irr (pic));
296 pce_printf (" PRIO=%u\n", pic->priority);
297
298 pce_puts ("IMR=");
299 prt_uint8_bin (e8259_get_imr (pic));
300 pce_printf (" INTR=%d\n", pic->intr_val != 0);
301
302 pce_puts ("ISR=");
303 prt_uint8_bin (e8259_get_isr (pic));
304 pce_puts ("\n");
305
306 pce_printf ("ICW=[%02X %02X %02X %02X] OCW=[%02X %02X %02X]\n",
307 e8259_get_icw (pic, 0), e8259_get_icw (pic, 1), e8259_get_icw (pic, 2),
308 e8259_get_icw (pic, 3),
309 e8259_get_ocw (pic, 0), e8259_get_ocw (pic, 1), e8259_get_ocw (pic, 2)
310 );
311
312 pce_printf ("N0=%04lX", pic->irq_cnt[0]);
313 for (i = 1; i < 8; i++) {
314 pce_printf (" N%u=%04lX", i, pic->irq_cnt[i]);
315 }
316
317 pce_puts ("\n");
318}
319
320static
321void prt_state_uart (e8250_t *uart, unsigned base)
322{
323 char p;
324 unsigned char lsr, msr;
325
326 lsr = e8250_get_lsr (uart);
327 msr = e8250_get_msr (uart);
328
329 switch (e8250_get_parity (uart)) {
330 case E8250_PARITY_N:
331 p = 'N';
332 break;
333
334 case E8250_PARITY_E:
335 p = 'E';
336 break;
337
338 case E8250_PARITY_O:
339 p = 'O';
340 break;
341
342 case E8250_PARITY_M:
343 p = 'M';
344 break;
345
346 case E8250_PARITY_S:
347 p = 'S';
348 break;
349
350 default:
351 p = '?';
352 break;
353 }
354
355 pce_prt_sep ("8250-UART");
356
357 pce_printf (
358 "IO=%04X %lu %u%c%u DTR=%d RTS=%d DSR=%d CTS=%d DCD=%d RI=%d\n"
359 "TxD=%02X%c RxD=%02X%c SCR=%02X DIV=%04X\n"
360 "IER=%02X IIR=%02X LCR=%02X LSR=%02X MCR=%02X MSR=%02X\n",
361 base,
362 e8250_get_bps (uart), e8250_get_databits (uart), p,
363 e8250_get_stopbits (uart),
364 e8250_get_dtr (uart), e8250_get_rts (uart),
365 (msr & E8250_MSR_DSR) != 0,
366 (msr & E8250_MSR_CTS) != 0,
367 (msr & E8250_MSR_DCD) != 0,
368 (msr & E8250_MSR_RI) != 0,
369 uart->txd, (lsr & E8250_LSR_TBE) ? ' ' : '*',
370 uart->rxd, (lsr & E8250_LSR_RRD) ? '*' : ' ',
371 uart->scratch, uart->divisor,
372 uart->ier, uart->iir, uart->lcr, lsr, uart->mcr, msr
373 );
374}
375
376void prt_state_cpu (e8086_t *c)
377{
378 pce_prt_sep ("8086");
379
380 pce_printf (
381 "AX=%04X BX=%04X CX=%04X DX=%04X "
382 "SP=%04X BP=%04X SI=%04X DI=%04X INT=%02X%c\n",
383 e86_get_ax (c), e86_get_bx (c), e86_get_cx (c), e86_get_dx (c),
384 e86_get_sp (c), e86_get_bp (c), e86_get_si (c), e86_get_di (c),
385 par_pc->current_int & 0xff,
386 (par_pc->current_int & 0x100) ? '*' : ' '
387 );
388
389 pce_printf ("DS=%04X ES=%04X SS=%04X CS=%04X IP=%04X F =%04X",
390 e86_get_ds (c), e86_get_es (c), e86_get_ss (c), e86_get_cs (c),
391 e86_get_ip (c), e86_get_flags (c)
392 );
393
394 pce_printf (" [%c%c%c%c%c%c%c%c%c]\n",
395 e86_get_df (c) ? 'D' : '-',
396 e86_get_if (c) ? 'I' : '-',
397 e86_get_tf (c) ? 'T' : '-',
398 e86_get_of (c) ? 'O' : '-',
399 e86_get_sf (c) ? 'S' : '-',
400 e86_get_zf (c) ? 'Z' : '-',
401 e86_get_af (c) ? 'A' : '-',
402 e86_get_pf (c) ? 'P' : '-',
403 e86_get_cf (c) ? 'C' : '-'
404 );
405
406 if (e86_get_halt (c)) {
407 pce_printf ("HALT=1\n");
408 }
409}
410
411void pc_print_trace (e8086_t *c)
412{
413 e86_disasm_t op;
414 char str[256];
415
416 e86_disasm_cur (c, &op);
417
418 switch (op.arg_n) {
419 case 0:
420 strcpy (str, op.op);
421 break;
422
423 case 1:
424 sprintf (str, "%-5s %s", op.op, op.arg1);
425 break;
426
427 case 2:
428 sprintf (str, "%-5s %s,%s", op.op, op.arg1, op.arg2);
429 break;
430
431 default:
432 strcpy (str, "****");
433 break;
434 }
435
436 pce_printf (
437 "AX=%04X BX=%04X CX=%04X DX=%04X "
438 "SP=%04X BP=%04X SI=%04X DI=%04X "
439 "DS=%04X ES=%04X SS=%04X F=%04X %04X:%04X %s\n",
440 e86_get_ax (c), e86_get_bx (c), e86_get_cx (c), e86_get_dx (c),
441 e86_get_sp (c), e86_get_bp (c), e86_get_si (c), e86_get_di (c),
442 e86_get_ds (c), e86_get_es (c), e86_get_ss (c), e86_get_flags (c),
443 e86_get_cs (c), e86_get_ip (c), str
444 );
445}
446
447static
448void prt_state_mem (ibmpc_t *pc)
449{
450 pce_prt_sep ("PC MEM");
451 mem_prt_state (pc->mem, stdout);
452}
453
454static
455void prt_state_ports (ibmpc_t *pc)
456{
457 pce_prt_sep ("PC PORTS");
458 mem_prt_state (pc->prt, stdout);
459}
460
461static
462void prt_state_pc (ibmpc_t *pc)
463{
464 prt_state_video (pc->video);
465 prt_state_ppi (&pc->ppi);
466 prt_state_pit (&pc->pit);
467 prt_state_pic (&pc->pic);
468 prt_state_dma (&pc->dma);
469 prt_state_cpu (pc->cpu);
470}
471
472static
473void prt_state (ibmpc_t *pc)
474{
475 e86_disasm_t op;
476 char str[256];
477
478 e86_disasm_cur (pc->cpu, &op);
479 disasm_str (str, &op);
480
481 prt_state_cpu (pc->cpu);
482
483 pce_printf ("%04X:%04X %s\n",
484 (unsigned) e86_get_cs (pc->cpu),
485 (unsigned) e86_get_ip (pc->cpu),
486 str
487 );
488}
489
490static
491int pc_check_break (ibmpc_t *pc)
492{
493 unsigned short seg, ofs;
494
495 seg = e86_get_cs (pc->cpu);
496 ofs = e86_get_ip (pc->cpu);
497
498 if (bps_check (&pc->bps, seg, ofs, stdout)) {
499 return (1);
500 }
501
502 if (pc->brk) {
503 return (1);
504 }
505
506 return (0);
507}
508
509static
510void pc_exec (ibmpc_t *pc)
511{
512 unsigned old;
513
514 pc->current_int &= 0xff;
515
516 old = e86_get_opcnt (pc->cpu);
517
518 while (e86_get_opcnt (pc->cpu) == old) {
519 pc_clock (pc, 1);
520
521 if (pc->brk) {
522 break;
523 }
524 }
525}
526
527void pc_run (ibmpc_t *pc)
528{
529 pce_start (&pc->brk);
530
531 pc_clock_discontinuity (pc);
532
533 if (pc->pause == 0) {
534 while (pc->brk == 0) {
535 pc_clock (pc, 4 * pc->speed_current);
536 }
537 }
538 else {
539 while (pc->brk == 0) {
540 pce_usleep (100000);
541 trm_check (pc->trm);
542 }
543 }
544
545 pc->current_int &= 0xff;
546
547 pce_stop();
548}
549
550#if 0
551static
552void pce_op_stat (void *ext, unsigned char op1, unsigned char op2)
553{
554 ibmpc_t *pc;
555
556 pc = (ibmpc_t *) ext;
557
558}
559#endif
560
561/*
562 * Force floppy disk drive types to 40 tracks in the BIOS data area of
563 * newer PC/XT BIOSes.
564 */
565static
566void pc_bios_set_40_track (ibmpc_t *pc, unsigned mask)
567{
568 unsigned i, v;
569
570 for (i = 0; i < 2; i++) {
571 if (mask & (1 << i)) {
572 v = e86_get_mem8 (pc->cpu, 0x40, 0x90 + i);
573 e86_set_mem8 (pc->cpu, 0x40, 0x90 + i, v & 0xfe);
574 }
575 }
576}
577
578static
579void pce_op_int (void *ext, unsigned char n)
580{
581 unsigned seg;
582 ibmpc_t *pc;
583
584 pc = ext;
585
586 pc->current_int = n | 0x100;
587
588 if (pc_intlog_check (pc, n)) {
589 pce_printf ("%04X:%04X: int %02X"
590 " [AX=%04X BX=%04X CX=%04X DX=%04X DS=%04X ES=%04X]\n",
591 e86_get_cs (pc->cpu), e86_get_cur_ip (pc->cpu),
592 n,
593 e86_get_ax (pc->cpu), e86_get_bx (pc->cpu),
594 e86_get_cx (pc->cpu), e86_get_dx (pc->cpu),
595 e86_get_ds (pc->cpu), e86_get_es (pc->cpu)
596 );
597 }
598
599 if (n == 0x13) {
600 if (pc->dsk0 == NULL) {
601 return;
602 }
603
604 if ((e86_get_ah (pc->cpu) != 0x02) || (e86_get_dl (pc->cpu) == 0)) {
605 return;
606 }
607
608 dsks_add_disk (pc->dsk, pc->dsk0);
609
610 pc->dsk0 = NULL;
611 }
612 else if (n == 0x19) {
613 if ((pc->bootdrive != 0) && (pc->dsk0 == NULL)) {
614 /* If we are not booting from drive 0 then
615 * temporarily remove it. */
616 pc->dsk0 = dsks_get_disk (pc->dsk, 0);
617 dsks_rmv_disk (pc->dsk, pc->dsk0);
618 }
619
620 if (pc->fdd40) {
621 pc_bios_set_40_track (pc, pc->fdd40);
622 }
623
624 if (pc->patch_bios_int19 == 0) {
625 return;
626 }
627
628 seg = pc_get_pcex_seg (pc);
629
630 if (seg == 0) {
631 return;
632 }
633
634 pc_log_deb ("patching int 19 (0x%04x)\n", seg);
635
636 e86_set_mem16 (pc->cpu, 0, 4 * 0x19 + 0, 0x0010);
637 e86_set_mem16 (pc->cpu, 0, 4 * 0x19 + 2, seg);
638 }
639}
640
641static
642void pce_op_undef (void *ext, unsigned char op1, unsigned char op2)
643{
644 ibmpc_t *pc;
645
646 pc = (ibmpc_t *) ext;
647
648 pce_log (MSG_DEB, "%04X:%04X: undefined operation [%02X %02x]\n",
649 e86_get_cs (pc->cpu), e86_get_ip (pc->cpu), op1, op2
650 );
651
652 if (pc->brk == 0) {
653 pce_usleep (100000UL);
654 }
655
656 trm_check (pc->trm);
657}
658
659
660static
661void pc_cmd_boot (cmd_t *cmd, ibmpc_t *pc)
662{
663 unsigned short val;
664
665 if (cmd_match_eol (cmd)) {
666 pce_printf ("boot drive is 0x%02x\n", pc_get_bootdrive (pc));
667 return;
668 }
669
670 if (!cmd_match_uint16 (cmd, &val)) {
671 cmd_error (cmd, "expecting boot drive");
672 return;
673 }
674
675 if (!cmd_match_end (cmd)) {
676 return;
677 }
678
679 pc_set_bootdrive (pc, val);
680}
681
682static
683void pc_cmd_c (cmd_t *cmd, ibmpc_t *pc)
684{
685 unsigned long cnt;
686
687 cnt = 1;
688
689 cmd_match_uint32 (cmd, &cnt);
690
691 if (!cmd_match_end (cmd)) {
692 return;
693 }
694
695 pc_clock_discontinuity (pc);
696
697 while (cnt > 0) {
698 pc_clock (pc, 1);
699 cnt -= 1;
700 }
701
702 prt_state (pc);
703}
704
705static
706void pc_cmd_g_b (cmd_t *cmd, ibmpc_t *pc)
707{
708 unsigned long seg, ofs;
709 breakpoint_t *bp;
710
711 while (cmd_match_uint32 (cmd, &seg)) {
712 if (cmd_match (cmd, ":")) {
713 if (!cmd_match_uint32 (cmd, &ofs)) {
714 cmd_error (cmd, "expecting offset");
715 return;
716 }
717
718 bp = bp_segofs_new (seg, ofs);
719 }
720 else {
721 bp = bp_addr_new (seg);
722 }
723
724 bps_bp_add (&pc->bps, bp);
725 }
726
727 if (!cmd_match_end (cmd)) {
728 return;
729 }
730
731 pce_start (&pc->brk);
732
733 pc_clock_discontinuity (pc);
734
735 while (1) {
736 if (pc->trace) {
737 pc_print_trace (pc->cpu);
738 }
739
740 pc_exec (pc);
741
742 if (pc_check_break (pc)) {
743 break;
744 }
745 }
746
747 pce_stop();
748}
749
750static
751void pc_cmd_g_far (cmd_t *cmd, ibmpc_t *pc)
752{
753 unsigned short seg;
754
755 if (!cmd_match_end (cmd)) {
756 return;
757 }
758
759 seg = e86_get_cs (pc->cpu);
760
761 pce_start (&pc->brk);
762
763 pc_clock_discontinuity (pc);
764
765 while (1) {
766 if (pc->trace) {
767 pc_print_trace (pc->cpu);
768 }
769
770 pc_exec (pc);
771
772 if (e86_get_cs (pc->cpu) != seg) {
773 prt_state (pc);
774 break;
775 }
776
777 if (pc_check_break (pc)) {
778 break;
779 }
780 }
781
782 pce_stop();
783}
784
785static
786void pc_cmd_g (cmd_t *cmd, ibmpc_t *pc)
787{
788 if (cmd_match (cmd, "b")) {
789 pc_cmd_g_b (cmd, pc);
790 }
791 else if (cmd_match (cmd, "far")) {
792 pc_cmd_g_far (cmd, pc);
793 }
794 else {
795 if (!cmd_match_end (cmd)) {
796 return;
797 }
798
799 pc_run (pc);
800 }
801}
802
803static
804void pc_cmd_hm (cmd_t *cmd)
805{
806 pce_puts (
807 "emu.config.save <filename>\n"
808 "emu.exit\n"
809 "emu.stop\n"
810 "emu.pause \"0\" | \"1\"\n"
811 "emu.pause.toggle\n"
812 "emu.reset\n"
813 "\n"
814 "emu.cas.commit\n"
815 "emu.cas.create <filename>\n"
816 "emu.cas.play\n"
817 "emu.cas.load [<pos>]\n"
818 "emu.cas.read <filename>\n"
819 "emu.cas.record\n"
820 "emu.cas.space\n"
821 "emu.cas.state\n"
822 "emu.cas.stop\n"
823 "emu.cas.truncate\n"
824 "emu.cas.write <filename>\n"
825 "\n"
826 "emu.cpu.model \"8086\" | \"8088\" | \"80186\" | \"80188\"\n"
827 "emu.cpu.speed <factor>\n"
828 "emu.cpu.speed.step <adjustment>\n"
829 "\n"
830 "emu.disk.boot <bootdrive>\n"
831 "emu.fdc.accurate \"0\" | \"1\"\n"
832 "emu.fdc.verbose <level>\n"
833 "\n"
834 "emu.parport.driver <driver>\n"
835 "emu.parport.file <filename>\n"
836 "\n"
837 "emu.serport.driver <driver>\n"
838 "emu.serport.file <filename>\n"
839 "\n"
840 "emu.term.fullscreen \"0\" | \"1\"\n"
841 "emu.term.fullscreen.toggle\n"
842 "emu.term.grab\n"
843 "emu.term.release\n"
844 "emu.term.screenshot [<filename>]\n"
845 "emu.term.title <title>\n"
846 "\n"
847 "emu.video.blink <blink-rate>\n"
848 "emu.video.redraw [\"now\"]\n"
849 "\n"
850 );
851
852 msg_dsk_print_help();
853}
854
855static
856void pc_cmd_i (cmd_t *cmd, ibmpc_t *pc)
857{
858 int word;
859 unsigned short port;
860
861 if (cmd_match (cmd, "w")) {
862 word = 1;
863 }
864 else if (cmd_match (cmd, "b")) {
865 word = 0;
866 }
867 else {
868 word = 0;
869 }
870
871 if (!cmd_match_uint16 (cmd, &port)) {
872 cmd_error (cmd, "need a port address");
873 return;
874 }
875
876 if (!cmd_match_end (cmd)) {
877 return;
878 }
879
880 if (word) {
881 pce_printf ("%04X: %04X\n", port, e86_get_prt16 (pc->cpu, port));
882 }
883 else {
884 pce_printf ("%04X: %02X\n", port, e86_get_prt8 (pc->cpu, port));
885 }
886}
887
888static
889void pc_cmd_key (cmd_t *cmd, ibmpc_t *pc)
890{
891 unsigned i;
892 unsigned mask;
893 pce_key_t key;
894 char str[256];
895
896 while (cmd_match_str (cmd, str, 256)) {
897 i = 0;
898
899 if (str[0] == '+') {
900 mask = 1;
901 i += 1;
902 }
903 else if (str[0] == '-') {
904 mask = 2;
905 i += 1;
906 }
907 else {
908 mask = 3;
909 }
910
911 key = pce_key_from_string (str + i);
912
913 if (key == PCE_KEY_NONE) {
914 pce_printf ("unknown key: %s\n", str);
915 }
916 else {
917 if (mask & 1) {
918 pc_kbd_set_key (&pc->kbd, PCE_KEY_EVENT_DOWN, key);
919 }
920
921 if (mask & 2) {
922 pc_kbd_set_key (&pc->kbd, PCE_KEY_EVENT_UP, key);
923 }
924 }
925 }
926
927 if (!cmd_match_end (cmd)) {
928 return;
929 }
930}
931
932static
933void pc_cmd_log_int_l (cmd_t *cmd, ibmpc_t *pc)
934{
935 unsigned i;
936 const char *str;
937
938 for (i = 0; i < 256; i++) {
939 str = pc_intlog_get (pc, i);
940
941 if (str != NULL) {
942 pce_printf ("%02X: %s\n", i, str);
943 }
944 }
945}
946
947static
948void pc_cmd_log_int (cmd_t *cmd, ibmpc_t *pc)
949{
950 unsigned short n;
951 char buf[256];
952
953 if (cmd_match_eol (cmd)) {
954 pc_cmd_log_int_l (cmd, pc);
955 return;
956 }
957
958 if (cmd_match (cmd, "l")) {
959 pc_cmd_log_int_l (cmd, pc);
960 return;
961 }
962
963 if (!cmd_match_uint16 (cmd, &n)) {
964 cmd_error (cmd, "need an interrupt number");
965 return;
966 }
967
968 if (cmd_match_eol (cmd)) {
969 pc_intlog_set (pc, n, NULL);
970 pce_printf ("%02X: <deleted>\n", n);
971 return;
972 }
973
974 if (!cmd_match_str (cmd, buf, 256)) {
975 cmd_error (cmd, "need an expression");
976 return;
977 }
978
979 pce_printf ("%02X: %s\n", n, buf);
980
981 pc_intlog_set (pc, n, buf);
982}
983
984static
985void pc_cmd_log (cmd_t *cmd, ibmpc_t *pc)
986{
987 if (cmd_match (cmd, "int")) {
988 pc_cmd_log_int (cmd, pc);
989 }
990 else {
991 cmd_error (cmd, "log what?");
992 }
993}
994
995static
996void pc_cmd_o (cmd_t *cmd, ibmpc_t *pc)
997{
998 int word;
999 unsigned short port, val;
1000
1001 if (cmd_match (cmd, "w")) {
1002 word = 1;
1003 }
1004 else if (cmd_match (cmd, "b")) {
1005 word = 0;
1006 }
1007 else {
1008 word = 0;
1009 }
1010
1011 if (!cmd_match_uint16 (cmd, &port)) {
1012 cmd_error (cmd, "need a port address");
1013 return;
1014 }
1015
1016 if (!cmd_match_uint16 (cmd, &val)) {
1017 cmd_error (cmd, "need a value");
1018 return;
1019 }
1020
1021 if (!cmd_match_end (cmd)) {
1022 return;
1023 }
1024
1025 if (word) {
1026 e86_set_prt16 (pc->cpu, port, val);
1027 }
1028 else {
1029 e86_set_prt8 (pc->cpu, port, val);
1030 }
1031}
1032
1033static
1034void pc_cmd_pqc (cmd_t *cmd, ibmpc_t *pc)
1035{
1036 if (!cmd_match_end (cmd)) {
1037 return;
1038 }
1039
1040 e86_pq_init (pc->cpu);
1041}
1042
1043static
1044void pc_cmd_pqs (cmd_t *cmd, ibmpc_t *pc)
1045{
1046 unsigned i;
1047
1048 if (!cmd_match_end (cmd)) {
1049 return;
1050 }
1051
1052 pce_puts ("PQ:");
1053
1054 for (i = 0; i < pc->cpu->pq_cnt; i++) {
1055 pce_printf (" %02X", pc->cpu->pq[i]);
1056 }
1057
1058 pce_puts ("\n");
1059}
1060
1061static
1062void pc_cmd_pqf (cmd_t *cmd, ibmpc_t *pc)
1063{
1064 if (!cmd_match_end (cmd)) {
1065 return;
1066 }
1067
1068 e86_pq_fill (pc->cpu);
1069}
1070
1071static
1072void pc_cmd_pq (cmd_t *cmd, ibmpc_t *pc)
1073{
1074 if (cmd_match (cmd, "c")) {
1075 pc_cmd_pqc (cmd, pc);
1076 }
1077 else if (cmd_match (cmd, "f")) {
1078 pc_cmd_pqf (cmd, pc);
1079 }
1080 else if (cmd_match (cmd, "s")) {
1081 pc_cmd_pqs (cmd, pc);
1082 }
1083 else if (cmd_match_eol (cmd)) {
1084 pc_cmd_pqs (cmd, pc);
1085 }
1086 else {
1087 cmd_error (cmd, "pq: unknown command (%s)\n");
1088 }
1089}
1090
1091static
1092void pc_cmd_p (cmd_t *cmd, ibmpc_t *pc)
1093{
1094 unsigned cnt, opcnt1, opcnt2;
1095 unsigned short seg, ofs, seg2, ofs2;
1096 unsigned long i, n;
1097 int brk, skip;
1098 e86_disasm_t op;
1099
1100 n = 1;
1101
1102 cmd_match_uint32 (cmd, &n);
1103
1104 if (!cmd_match_end (cmd)) {
1105 return;
1106 }
1107
1108 brk = 0;
1109
1110 pce_start (&pc->brk);
1111
1112 pc->current_int &= 0xff;
1113
1114 pc_clock_discontinuity (pc);
1115
1116 for (i = 0; i < n; i++) {
1117 e86_disasm_cur (pc->cpu, &op);
1118
1119 seg = e86_get_cs (pc->cpu);
1120 ofs = e86_get_ip (pc->cpu);
1121
1122 cnt = pc->cpu->int_cnt;
1123
1124 if (pc->trace) {
1125 pc_print_trace (pc->cpu);
1126 }
1127
1128 while ((e86_get_cs (pc->cpu) == seg) && (e86_get_ip (pc->cpu) == ofs)) {
1129 pc_clock (pc, 1);
1130
1131 if (pc_check_break (pc)) {
1132 brk = 1;
1133 break;
1134 }
1135 }
1136
1137 if (brk) {
1138 break;
1139 }
1140
1141 skip = 0;
1142
1143 if (op.flags & (E86_DFLAGS_CALL | E86_DFLAGS_LOOP)) {
1144 seg2 = seg;
1145 ofs2 = ofs + op.dat_n;
1146 skip = 1;
1147 }
1148 else if (pc->cpu->int_cnt != cnt) {
1149 seg2 = pc->cpu->int_cs;
1150 ofs2 = pc->cpu->int_ip;
1151 skip = 1;
1152 }
1153
1154 if (skip) {
1155 opcnt1 = -e86_get_opcnt (pc->cpu);
1156
1157 while ((e86_get_cs (pc->cpu) != seg2) || (e86_get_ip (pc->cpu) != ofs2)) {
1158 if (pc->trace) {
1159 opcnt2 = e86_get_opcnt (pc->cpu);
1160
1161 if (opcnt1 != opcnt2) {
1162 opcnt1 = opcnt2;
1163 pc_print_trace (pc->cpu);
1164 }
1165 }
1166
1167 pc_clock (pc, 1);
1168
1169 if (pc_check_break (pc)) {
1170 brk = 1;
1171 break;
1172 }
1173 }
1174 }
1175
1176 if (brk) {
1177 break;
1178 }
1179
1180 if (pc_check_break (pc)) {
1181 break;
1182 }
1183 }
1184
1185 pce_stop();
1186
1187 prt_state (pc);
1188}
1189
1190static
1191void pc_cmd_r (cmd_t *cmd, ibmpc_t *pc)
1192{
1193 unsigned long val;
1194 char sym[256];
1195
1196 if (cmd_match_eol (cmd)) {
1197 prt_state_cpu (pc->cpu);
1198 return;
1199 }
1200
1201 if (!cmd_match_ident (cmd, sym, 256)) {
1202 pce_printf ("missing register\n");
1203 return;
1204 }
1205
1206 if (e86_get_reg (pc->cpu, sym, &val)) {
1207 pce_printf ("bad register (%s)\n", sym);
1208 return;
1209 }
1210
1211 if (cmd_match_eol (cmd)) {
1212 pce_printf ("%04lX\n", val);
1213 return;
1214 }
1215
1216 if (!cmd_match_uint32 (cmd, &val)) {
1217 pce_printf ("missing value\n");
1218 return;
1219 }
1220
1221 if (!cmd_match_end (cmd)) {
1222 return;
1223 }
1224
1225 e86_set_reg (pc->cpu, sym, val);
1226
1227 prt_state (pc);
1228}
1229
1230static
1231void pc_cmd_s (cmd_t *cmd, ibmpc_t *pc)
1232{
1233 if (cmd_match_eol (cmd)) {
1234 prt_state (pc);
1235 return;
1236 }
1237
1238 while (!cmd_match_eol (cmd)) {
1239 if (cmd_match (cmd, "pc")) {
1240 prt_state_pc (pc);
1241 }
1242 else if (cmd_match (cmd, "cpu")) {
1243 prt_state_cpu (pc->cpu);
1244 }
1245 else if (cmd_match (cmd, "dma")) {
1246 prt_state_dma (&pc->dma);
1247 }
1248 else if (cmd_match (cmd, "disks")) {
1249 dsks_print_info (pc->dsk);
1250 }
1251 else if (cmd_match (cmd, "ems")) {
1252 prt_state_ems (pc->ems);
1253 }
1254 else if (cmd_match (cmd, "mem")) {
1255 prt_state_mem (pc);
1256 }
1257 else if (cmd_match (cmd, "pic")) {
1258 prt_state_pic (&pc->pic);
1259 }
1260 else if (cmd_match (cmd, "pit")) {
1261 prt_state_pit (&pc->pit);
1262 }
1263 else if (cmd_match (cmd, "ppi")) {
1264 prt_state_ppi (&pc->ppi);
1265 }
1266 else if (cmd_match (cmd, "ports")) {
1267 prt_state_ports (pc);
1268 }
1269 else if (cmd_match (cmd, "uart")) {
1270 unsigned short i;
1271 if (!cmd_match_uint16 (cmd, &i)) {
1272 i = 0;
1273 }
1274 if ((i < 4) && (pc->serport[i] != NULL)) {
1275 prt_state_uart (
1276 &pc->serport[i]->uart,
1277 pc->serport[i]->io
1278 );
1279 }
1280 }
1281 else if (cmd_match (cmd, "video")) {
1282 prt_state_video (pc->video);
1283 }
1284 else if (cmd_match (cmd, "xms")) {
1285 prt_state_xms (pc->xms);
1286 }
1287 else {
1288 cmd_error (cmd, "unknown component (%s)\n");
1289 return;
1290 }
1291 }
1292}
1293
1294static
1295void pc_cmd_trace (cmd_t *cmd, ibmpc_t *pc)
1296{
1297 unsigned short v;
1298
1299 if (cmd_match_eol (cmd)) {
1300 pce_printf ("trace is %s\n", pc->trace ? "on" : "off");
1301 return;
1302 }
1303
1304 if (cmd_match (cmd, "on")) {
1305 pc->trace = 1;
1306 }
1307 else if (cmd_match (cmd, "off")) {
1308 pc->trace = 0;
1309 }
1310 else if (cmd_match_uint16 (cmd, &v)) {
1311 pc->trace = (v != 0);
1312 }
1313 else {
1314 cmd_error (cmd, "on or off expected\n");
1315 }
1316}
1317
1318static
1319void pc_cmd_t (cmd_t *cmd, ibmpc_t *pc)
1320{
1321 unsigned long i, n;
1322
1323 n = 1;
1324
1325 cmd_match_uint32 (cmd, &n);
1326
1327 if (!cmd_match_end (cmd)) {
1328 return;
1329 }
1330
1331 pce_start (&pc->brk);
1332
1333 pc_clock_discontinuity (pc);
1334
1335 for (i = 0; i < n; i++) {
1336 if (pc->trace) {
1337 pc_print_trace (pc->cpu);
1338 }
1339
1340 pc_exec (pc);
1341
1342 if (pc_check_break (pc)) {
1343 break;
1344 }
1345 }
1346
1347 pce_stop();
1348
1349 prt_state (pc);
1350}
1351
1352static
1353void pc_cmd_u (cmd_t *cmd, ibmpc_t *pc)
1354{
1355 unsigned short seg, ofs, cnt, mode;
1356 static unsigned int first = 1;
1357 static unsigned short sseg = 0;
1358 static unsigned short sofs = 0;
1359 e86_disasm_t op;
1360 char str[256];
1361
1362 if (first) {
1363 first = 0;
1364 sseg = e86_get_cs (pc->cpu);
1365 sofs = e86_get_ip (pc->cpu);
1366 }
1367
1368 seg = sseg;
1369 ofs = sofs;
1370 cnt = 16;
1371 mode = 0;
1372
1373 if (cmd_match_uint16_16 (cmd, &seg, &ofs)) {
1374 cmd_match_uint16 (cmd, &cnt);
1375 }
1376
1377 cmd_match_uint16 (cmd, &mode);
1378
1379 if (!cmd_match_end (cmd)) {
1380 return;
1381 }
1382
1383 while (cnt > 0) {
1384 e86_disasm_mem (pc->cpu, &op, seg, ofs);
1385 disasm_str (str, &op);
1386
1387 pce_printf ("%04X:%04X %s\n", seg, ofs, str);
1388
1389 ofs = (ofs + op.dat_n) & 0xffff;
1390
1391 if (mode == 0) {
1392 cnt -= 1;
1393 }
1394 else {
1395 cnt = (cnt < op.dat_n) ? 0 : (cnt - op.dat_n);
1396 }
1397 }
1398
1399 sseg = seg;
1400 sofs = ofs;
1401}
1402
1403int pc_cmd (ibmpc_t *pc, cmd_t *cmd)
1404{
1405 if (pc->trm != NULL) {
1406 trm_check (pc->trm);
1407 }
1408
1409 if (cmd_match (cmd, "boot")) {
1410 pc_cmd_boot (cmd, pc);
1411 }
1412 else if (cmd_match (cmd, "b")) {
1413 cmd_do_b (cmd, &pc->bps);
1414 }
1415 else if (cmd_match (cmd, "c")) {
1416 pc_cmd_c (cmd, pc);
1417 }
1418 else if (cmd_match (cmd, "g")) {
1419 pc_cmd_g (cmd, pc);
1420 }
1421 else if (cmd_match (cmd, "hm")) {
1422 pc_cmd_hm (cmd);
1423 }
1424 else if (cmd_match (cmd, "i")) {
1425 pc_cmd_i (cmd, pc);
1426 }
1427 else if (cmd_match (cmd, "key")) {
1428 pc_cmd_key (cmd, pc);
1429 }
1430 else if (cmd_match (cmd, "log")) {
1431 pc_cmd_log (cmd, pc);
1432 }
1433 else if (cmd_match (cmd, "o")) {
1434 pc_cmd_o (cmd, pc);
1435 }
1436 else if (cmd_match (cmd, "pq")) {
1437 pc_cmd_pq (cmd, pc);
1438 }
1439 else if (cmd_match (cmd, "p")) {
1440 pc_cmd_p (cmd, pc);
1441 }
1442 else if (cmd_match (cmd, "r")) {
1443 pc_cmd_r (cmd, pc);
1444 }
1445 else if (cmd_match (cmd, "s")) {
1446 pc_cmd_s (cmd, pc);
1447 }
1448 else if (cmd_match (cmd, "trace")) {
1449 pc_cmd_trace (cmd, pc);
1450 }
1451 else if (cmd_match (cmd, "t")) {
1452 pc_cmd_t (cmd, pc);
1453 }
1454 else if (cmd_match (cmd, "u")) {
1455 pc_cmd_u (cmd, pc);
1456 }
1457 else {
1458 return (1);
1459 }
1460
1461 return (0);
1462}
1463
1464void pc_cmd_init (ibmpc_t *pc, monitor_t *mon)
1465{
1466 mon_cmd_add (mon, par_cmd, sizeof (par_cmd) / sizeof (par_cmd[0]));
1467 mon_cmd_add_bp (mon);
1468
1469 pc->cpu->op_int = &pce_op_int;
1470 pc->cpu->op_undef = &pce_op_undef;
1471#if 0
1472 pc->cpu->op_stat = pce_op_stat;
1473#endif
1474
1475}