Browse Source

cpm80: Add a CP/M-80 emulator

master
Hampa Hug 2 years ago
parent
commit
0ca85efeed

+ 93
- 0
Makefile.dep View File

@@ -258,6 +258,99 @@ src/arch/atarist/viking.o: src/arch/atarist/viking.c \
258 258
 	src/drivers/video/terminal.h \
259 259
 	src/libini/libini.h
260 260
 
261
+src/arch/cpm80/bios.o: src/arch/cpm80/bios.c \
262
+	src/arch/cpm80/bios.h \
263
+	src/arch/cpm80/cpm80.h \
264
+	src/arch/cpm80/main.h \
265
+	src/config.h \
266
+	src/cpu/e8080/e8080.h \
267
+	src/devices/memory.h \
268
+	src/drivers/block/blkpsi.h \
269
+	src/drivers/block/block.h \
270
+	src/drivers/char/char.h \
271
+	src/drivers/psi/psi-img.h \
272
+	src/drivers/psi/psi.h \
273
+	src/lib/brkpt.h \
274
+	src/lib/cmd.h \
275
+	src/lib/log.h \
276
+	src/libini/libini.h
277
+
278
+src/arch/cpm80/cmd.o: src/arch/cpm80/cmd.c \
279
+	src/arch/cpm80/bios.h \
280
+	src/arch/cpm80/cpm80.h \
281
+	src/arch/cpm80/main.h \
282
+	src/config.h \
283
+	src/cpu/e8080/e8080.h \
284
+	src/devices/memory.h \
285
+	src/drivers/block/block.h \
286
+	src/drivers/char/char.h \
287
+	src/lib/brkpt.h \
288
+	src/lib/cmd.h \
289
+	src/lib/console.h \
290
+	src/lib/log.h \
291
+	src/lib/monitor.h \
292
+	src/lib/sysdep.h \
293
+	src/libini/libini.h
294
+
295
+src/arch/cpm80/cpm80.o: src/arch/cpm80/cpm80.c \
296
+	src/arch/cpm80/bios.h \
297
+	src/arch/cpm80/cpm80.h \
298
+	src/arch/cpm80/main.h \
299
+	src/arch/cpm80/msg.h \
300
+	src/config.h \
301
+	src/cpu/e8080/e8080.h \
302
+	src/devices/memory.h \
303
+	src/drivers/block/block.h \
304
+	src/drivers/char/char.h \
305
+	src/lib/brkpt.h \
306
+	src/lib/cmd.h \
307
+	src/lib/inidsk.h \
308
+	src/lib/iniram.h \
309
+	src/lib/load.h \
310
+	src/lib/log.h \
311
+	src/lib/msg.h \
312
+	src/lib/path.h \
313
+	src/lib/sysdep.h \
314
+	src/libini/libini.h
315
+
316
+src/arch/cpm80/main.o: src/arch/cpm80/main.c \
317
+	src/arch/cpm80/cmd.h \
318
+	src/arch/cpm80/cpm80.h \
319
+	src/arch/cpm80/main.h \
320
+	src/arch/cpm80/msg.h \
321
+	src/config.h \
322
+	src/cpu/e8080/e8080.h \
323
+	src/devices/memory.h \
324
+	src/drivers/block/block.h \
325
+	src/drivers/char/char.h \
326
+	src/lib/brkpt.h \
327
+	src/lib/cmd.h \
328
+	src/lib/console.h \
329
+	src/lib/getopt.h \
330
+	src/lib/log.h \
331
+	src/lib/monitor.h \
332
+	src/lib/path.h \
333
+	src/lib/sysdep.h \
334
+	src/libini/libini.h
335
+
336
+src/arch/cpm80/msg.o: src/arch/cpm80/msg.c \
337
+	src/arch/cpm80/cpm80.h \
338
+	src/arch/cpm80/main.h \
339
+	src/arch/cpm80/msg.h \
340
+	src/config.h \
341
+	src/cpu/e8080/e8080.h \
342
+	src/devices/memory.h \
343
+	src/drivers/block/block.h \
344
+	src/drivers/char/char.h \
345
+	src/lib/brkpt.h \
346
+	src/lib/cmd.h \
347
+	src/lib/console.h \
348
+	src/lib/inidsk.h \
349
+	src/lib/log.h \
350
+	src/lib/monitor.h \
351
+	src/lib/msg.h \
352
+	src/libini/libini.h
353
+
261 354
 src/arch/dos/dos.o: src/arch/dos/dos.c \
262 355
 	src/arch/dos/dos.h \
263 356
 	src/arch/dos/dosmem.h \

+ 2
- 0
Makefile.inc.in View File

@@ -75,6 +75,7 @@ CFLAGS_DEFAULT += -DPCE_HOST_SPARC
75 75
 endif
76 76
 
77 77
 PCE_BUILD_ATARIST := @PCE_BUILD_ATARIST@
78
+PCE_BUILD_CPM80   := @PCE_BUILD_CPM80@
78 79
 PCE_BUILD_IBMPC   := @PCE_BUILD_IBMPC@
79 80
 PCE_BUILD_MACPLUS := @PCE_BUILD_MACPLUS@
80 81
 PCE_BUILD_RC759   := @PCE_BUILD_RC759@
@@ -149,6 +150,7 @@ include $(srcdir)/src/drivers/sound/Makefile.inc
149 150
 include $(srcdir)/src/drivers/video/Makefile.inc
150 151
 include $(srcdir)/src/arch/Makefile.inc
151 152
 include $(srcdir)/src/arch/atarist/Makefile.inc
153
+include $(srcdir)/src/arch/cpm80/Makefile.inc
152 154
 include $(srcdir)/src/arch/dos/Makefile.inc
153 155
 include $(srcdir)/src/arch/ibmpc/Makefile.inc
154 156
 include $(srcdir)/src/arch/ibmpc/bios/Makefile.inc

+ 40
- 0
configure View File

@@ -644,6 +644,7 @@ PCE_BUILD_MACPLUS_ROM
644 644
 PCE_BUILD_MACPLUS
645 645
 PCE_BUILD_IBMPC_ROM
646 646
 PCE_BUILD_IBMPC
647
+PCE_BUILD_CPM80
647 648
 PCE_BUILD_ATARIST
648 649
 PCE_LARGE_FILE
649 650
 PCE_SDL_LIBS
@@ -741,6 +742,7 @@ with_sdl
741 742
 enable_static_sdl
742 743
 enable_largefile
743 744
 enable_atari_st
745
+enable_cpm80
744 746
 enable_ibmpc
745 747
 enable_ibmpc_rom
746 748
 enable_macplus
@@ -1389,6 +1391,7 @@ Optional Features:
1389 1391
   --enable-static-sdl     Link to static SDL [no]
1390 1392
   --disable-largefile     Disable large file support [no]
1391 1393
   --enable-atari-st       Enable the Atari ST emulator [yes]
1394
+  --enable-cpm80          Enable the CPM-80 emulator [yes]
1392 1395
   --enable-ibmpc          Enable the IBM PC emulator [yes]
1393 1396
   --enable-ibmpc-rom      Build the IBM PC ROM from source [no]
1394 1397
   --enable-macplus        Enable the Mac Plus emulator [yes]
@@ -4753,6 +4756,37 @@ if test $PCE_BUILD_ATARIST -eq 1 ; then
4753 4756
 fi
4754 4757
 
4755 4758
 
4759
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build the CPM-80 emulator" >&5
4760
+$as_echo_n "checking whether to build the CPM-80 emulator... " >&6; }
4761
+# Check whether --enable-cpm80 was given.
4762
+if test "${enable_cpm80+set}" = set; then :
4763
+  enableval=$enable_cpm80;
4764
+	if test "x$enableval" = "xyes" ; then
4765
+		PCE_BUILD_CPM80=1
4766
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (forced)" >&5
4767
+$as_echo "yes (forced)" >&6; }
4768
+	else
4769
+		PCE_BUILD_CPM80=0
4770
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no (forced)" >&5
4771
+$as_echo "no (forced)" >&6; }
4772
+	fi
4773
+
4774
+else
4775
+
4776
+	PCE_BUILD_CPM80=1
4777
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5
4778
+$as_echo "yes (default)" >&6; }
4779
+
4780
+
4781
+fi
4782
+
4783
+
4784
+if test "x$PCE_BUILD_CPM80" = "x1" ; then
4785
+	$as_echo "#define PCE_BUILD_CPM80 1" >>confdefs.h
4786
+
4787
+fi
4788
+
4789
+
4756 4790
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build the IBM PC emulator" >&5
4757 4791
 $as_echo_n "checking whether to build the IBM PC emulator... " >&6; }
4758 4792
 if test "x$have_ibmpc" != "x1" ; then
@@ -5627,6 +5661,12 @@ else
5627 5661
 	emu2="$emu2 atarist"
5628 5662
 fi
5629 5663
 
5664
+if test "x$PCE_BUILD_CPM80" = "x1" ; then
5665
+	emu1="$emu1 cpm80"
5666
+else
5667
+	emu2="$emu2 cpm80"
5668
+fi
5669
+
5630 5670
 if test "x$PCE_BUILD_IBMPC" = "x1" ; then
5631 5671
 	emu1="$emu1 ibmpc"
5632 5672
 else

+ 29
- 0
configure.in View File

@@ -369,6 +369,29 @@ if test $PCE_BUILD_ATARIST -eq 1 ; then
369 369
 fi
370 370
 
371 371
 
372
+AC_MSG_CHECKING([whether to build the CPM-80 emulator])
373
+AC_ARG_ENABLE(cpm80,
374
+  [AS_HELP_STRING([--enable-cpm80], [Enable the CPM-80 emulator [yes]])],
375
+  [
376
+	if test "x$enableval" = "xyes" ; then
377
+		PCE_BUILD_CPM80=1
378
+		AC_MSG_RESULT([yes (forced)])
379
+	else
380
+		PCE_BUILD_CPM80=0
381
+		AC_MSG_RESULT([no (forced)])
382
+	fi
383
+  ],
384
+  [
385
+	PCE_BUILD_CPM80=1
386
+	AC_MSG_RESULT([yes (default)])
387
+  ]
388
+)
389
+AC_SUBST(PCE_BUILD_CPM80)
390
+if test "x$PCE_BUILD_CPM80" = "x1" ; then
391
+	AC_DEFINE(PCE_BUILD_CPM80)
392
+fi
393
+
394
+
372 395
 AC_MSG_CHECKING([whether to build the IBM PC emulator])
373 396
 if test "x$have_ibmpc" != "x1" ; then
374 397
 	PCE_BUILD_IBMPC=0
@@ -938,6 +961,12 @@ else
938 961
 	emu2="$emu2 atarist"
939 962
 fi
940 963
 
964
+if test "x$PCE_BUILD_CPM80" = "x1" ; then
965
+	emu1="$emu1 cpm80"
966
+else
967
+	emu2="$emu2 cpm80"
968
+fi
969
+
941 970
 if test "x$PCE_BUILD_IBMPC" = "x1" ; then
942 971
 	emu1="$emu1 ibmpc"
943 972
 else

+ 87
- 0
src/arch/cpm80/Makefile.inc View File

@@ -0,0 +1,87 @@
1
+# src/arch/cpm80/Makefile.inc
2
+
3
+rel := src/arch/cpm80
4
+
5
+DIRS += $(rel)
6
+DIST += $(rel)/Makefile.inc
7
+
8
+# ----------------------------------------------------------------------
9
+
10
+PCE_CPM80_CFLAGS  := $(CFLAGS_DEFAULT)
11
+PCE_CPM80_LDFLAGS := $(LDFLAGS_DEFAULT)
12
+PCE_CPM80_LIBS    := $(LIBS)
13
+
14
+ifeq "$(PCE_HOST_WINDOWS)" "1"
15
+	PCE_CPM80_LIBS += -mconsole
16
+endif
17
+
18
+ifeq "$(PCE_ENABLE_READLINE)" "1"
19
+	PCE_CPM80_LIBS += $(PCE_READLINE_LIBS)
20
+endif
21
+
22
+$(rel)/%.o: $(rel)/%.c
23
+	$(QP)echo "  CC     $@"
24
+	$(QR)$(CC) -c $(PCE_CPM80_CFLAGS) -o $@ $<
25
+
26
+# ----------------------------------------------------------------------
27
+
28
+PCE_CPM80_BAS := bios cmd cpm80 main msg
29
+PCE_CPM80_SRC := $(foreach f,$(PCE_CPM80_BAS),$(rel)/$(f).c)
30
+PCE_CPM80_OBJ := $(foreach f,$(PCE_CPM80_BAS),$(rel)/$(f).o)
31
+PCE_CPM80_HDR := $(foreach f,$(PCE_CPM80_BAS),$(rel)/$(f).h)
32
+#PCE_CPM80_MAN1 := $(rel)/pce-cpm80.1
33
+PCE_CPM80_ETC := $(rel)/pce-cpm80.cfg
34
+PCE_CPM80_BIN := $(rel)/pce-cpm80$(EXEEXT)
35
+
36
+PCE_CPM80_OBJ_EXT := \
37
+	src/cpu/e8080/e8080.a \
38
+	src/devices/memory.o \
39
+	src/drivers/char/char.a \
40
+	src/drivers/options.o \
41
+	src/lib/brkpt.o \
42
+	src/lib/cmd.o \
43
+	src/lib/console.o \
44
+	src/lib/getopt.o \
45
+	src/lib/ihex.o \
46
+	src/lib/inidsk.o \
47
+	src/lib/iniram.o \
48
+	src/lib/load.o \
49
+	src/lib/log.o \
50
+	src/lib/monitor.o \
51
+	src/lib/msg.o \
52
+	src/lib/path.o \
53
+	src/lib/srec.o \
54
+	src/lib/string.o \
55
+	src/lib/sysdep.o \
56
+	src/libini/libini.a \
57
+	src/drivers/block/block.a \
58
+	src/drivers/psi/psi.a \
59
+	src/drivers/char/char.a
60
+
61
+ifeq "$(PCE_ENABLE_TUN)" "1"
62
+PCE_CPM80_OBJ_EXT += src/lib/tun.o
63
+endif
64
+
65
+ifeq "$(PCE_BUILD_CPM80)" "1"
66
+BIN  += $(PCE_CPM80_BIN)
67
+ETC  += $(PCE_CPM80_ETC)
68
+MAN1 += $(PCE_CPM80_MAN1)
69
+endif
70
+
71
+CLN  += $(PCE_CPM80_BIN) $(PCE_CPM80_OBJ) $(PCE_CPM80_ETC)
72
+DIST += $(PCE_CPM80_SRC) $(PCE_CPM80_HDR) $(PCE_CPM80_MAN1)
73
+DIST += $(rel)/pce-cpm80.cfg.in
74
+
75
+$(rel)/bios.o:  $(rel)/bios.c
76
+$(rel)/cmd.o:   $(rel)/cmd.c
77
+$(rel)/cpm80.o: $(rel)/cpm80.c
78
+$(rel)/main.o:  $(rel)/main.c
79
+$(rel)/msg.o:   $(rel)/msg.c
80
+
81
+$(rel)/pce-cpm80$(EXEEXT): $(PCE_CPM80_OBJ_EXT) $(PCE_CPM80_OBJ)
82
+	$(QP)echo "  LD     $@"
83
+	$(QR)$(LD) $(PCE_CPM80_LDFLAGS) -o $@ $(PCE_CPM80_OBJ) $(PCE_CPM80_OBJ_EXT) $(PCE_CPM80_LIBS) -lm
84
+
85
+$(rel)/pce-cpm80.cfg: $(rel)/pce-cpm80.cfg.in
86
+	$(QP)echo "  SED    $@"
87
+	$(QR)sed -e "s]PCE_DIR_DATA]$(datadir)]g" < $< > $@

+ 1025
- 0
src/arch/cpm80/bios.c
File diff suppressed because it is too large
View File


+ 42
- 0
src/arch/cpm80/bios.h View File

@@ -0,0 +1,42 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/bios.h                                        *
7
+ * Created:     2012-11-29 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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
+#ifndef PCE_CPM80_BIOS_H
24
+#define PCE_CPM80_BIOS_H 1
25
+
26
+
27
+#include "cpm80.h"
28
+
29
+
30
+int con_ready (cpm80_t *sim);
31
+int con_getc (cpm80_t *sim, unsigned char *c);
32
+int con_putc (cpm80_t *sim, unsigned char c);
33
+int con_puts (cpm80_t *sim, const char *str);
34
+int aux_getc (cpm80_t *sim, unsigned char *c);
35
+int aux_putc (cpm80_t *sim, unsigned char c);
36
+int lst_putc (cpm80_t *sim, unsigned char c);
37
+
38
+void c80_bios (cpm80_t *sim, unsigned fct);
39
+void c80_bios_init (cpm80_t *sim);
40
+
41
+
42
+#endif

+ 789
- 0
src/arch/cpm80/cmd.c View File

@@ -0,0 +1,789 @@
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-2016 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
+
38
+static 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
+	{ "t", "[cnt]", "execute cnt instructions [1]" },
48
+	{ "u", "[addr [cnt]]", "disassemble" }
49
+};
50
+
51
+
52
+static
53
+void c80_disasm_str (char *dst, e8080_disasm_t *op, int with_pc, int with_comment)
54
+{
55
+	unsigned i, k, n;
56
+	char     comment[256];
57
+
58
+	comment[0] = 0;
59
+
60
+	if (with_pc) {
61
+		n = sprintf (dst, "%04X  ", (unsigned) op->pc);
62
+	}
63
+	else {
64
+		n = 0;
65
+	}
66
+
67
+	for (i = 0; i < op->data_cnt; i++) {
68
+		n += sprintf (dst + n, "%02X ", (unsigned) op->data[i]);
69
+	}
70
+
71
+	for (i = op->data_cnt; i < 4; i++) {
72
+		dst[n++] = ' ';
73
+		dst[n++] = ' ';
74
+		dst[n++] = ' ';
75
+	}
76
+
77
+	k = n + 8;
78
+	n += sprintf (dst + n, "%s", op->op);
79
+
80
+	if (op->arg_cnt > 0) {
81
+		while (n < k) {
82
+			dst[n++] = ' ';
83
+		}
84
+
85
+		n += sprintf (dst + n, "%s", op->arg[0]);
86
+
87
+		for (i = 1; i < op->arg_cnt; i++) {
88
+			n += sprintf (dst + n, ", %s", op->arg[i]);
89
+		}
90
+	}
91
+
92
+	if (with_comment && (comment[0] != 0)) {
93
+		while (n < 40) {
94
+			dst[n++] = ' ';
95
+		}
96
+
97
+		dst[n++] = ';';
98
+	}
99
+
100
+	dst[n] = 0;
101
+}
102
+
103
+static
104
+void c80_disasm_cur (e8080_t *c, e8080_disasm_t *op)
105
+{
106
+	if (e8080_get_flags (c) & E8080_FLAG_Z80) {
107
+		z80_disasm_cur (c, op);
108
+	}
109
+	else {
110
+		e8080_disasm_cur (c, op);
111
+	}
112
+}
113
+
114
+static
115
+void c80_disasm_mem (e8080_t *c, e8080_disasm_t *op, unsigned short addr)
116
+{
117
+	if (e8080_get_flags (c) & E8080_FLAG_Z80) {
118
+		z80_disasm_mem (c, op, addr);
119
+	}
120
+	else {
121
+		e8080_disasm_mem (c, op, addr);
122
+	}
123
+}
124
+
125
+static
126
+void c80_print_cpu_z80_1 (e8080_t *c)
127
+{
128
+	e8080_disasm_t op;
129
+	char           str[256];
130
+
131
+	c80_disasm_cur (c, &op);
132
+	c80_disasm_str (str, &op, 0, 0);
133
+
134
+	if (c->halt) {
135
+		pce_printf ("HALT=1  ");
136
+	}
137
+
138
+	pce_printf (
139
+		"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",
140
+		(unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
141
+		(unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
142
+		(unsigned) e8080_get_ix (c), (unsigned) e8080_get_iy (c),
143
+		(unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
144
+		(unsigned) e8080_get_psw (c),
145
+		(e8080_get_sf (c)) ? 'S' : '-',
146
+		(e8080_get_zf (c)) ? 'Z' : '-',
147
+		(e8080_get_af (c)) ? 'A' : '-',
148
+		(e8080_get_pf (c)) ? 'P' : '-',
149
+		(e8080_get_cf (c)) ? 'C' : '-',
150
+		str
151
+	);
152
+}
153
+
154
+static
155
+void c80_print_cpu_8080_1 (e8080_t *c)
156
+{
157
+	e8080_disasm_t op;
158
+	char           str[256];
159
+
160
+	c80_disasm_cur (c, &op);
161
+	c80_disasm_str (str, &op, 0, 0);
162
+
163
+	if (c->halt) {
164
+		pce_printf ("HALT=1  ");
165
+	}
166
+
167
+	pce_printf (
168
+		"A=%02X BC=%04X DE=%04X HL=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c]  %s\n",
169
+		(unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
170
+		(unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
171
+		(unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
172
+		(unsigned) e8080_get_psw (c),
173
+		(e8080_get_sf (c)) ? 'S' : '-',
174
+		(e8080_get_zf (c)) ? 'Z' : '-',
175
+		(e8080_get_af (c)) ? 'A' : '-',
176
+		(e8080_get_pf (c)) ? 'P' : '-',
177
+		(e8080_get_cf (c)) ? 'C' : '-',
178
+		str
179
+	);
180
+}
181
+
182
+static
183
+void c80_print_cpu_z80_2 (e8080_t *c)
184
+{
185
+	e8080_disasm_t op;
186
+	char           str[256];
187
+
188
+	c80_disasm_cur (c, &op);
189
+	c80_disasm_str (str, &op, 1, 1);
190
+
191
+	pce_printf (
192
+		"A=%02X BC=%04X DE=%04X HL=%04X IX=%04X IY=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c]\n"
193
+		"%s\n",
194
+		(unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
195
+		(unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
196
+		(unsigned) e8080_get_ix (c), (unsigned) e8080_get_iy (c),
197
+		(unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
198
+		(unsigned) e8080_get_psw (c),
199
+		(e8080_get_sf (c)) ? 'S' : '-',
200
+		(e8080_get_zf (c)) ? 'Z' : '-',
201
+		(e8080_get_af (c)) ? 'A' : '-',
202
+		(e8080_get_pf (c)) ? 'P' : '-',
203
+		(e8080_get_cf (c)) ? 'C' : '-',
204
+		str
205
+	);
206
+
207
+	if (c->halt) {
208
+		pce_printf ("HALT=1\n");
209
+	}
210
+}
211
+
212
+static
213
+void c80_print_cpu_8080_2 (e8080_t *c)
214
+{
215
+	e8080_disasm_t op;
216
+	char           str[256];
217
+
218
+	c80_disasm_cur (c, &op);
219
+	c80_disasm_str (str, &op, 1, 1);
220
+
221
+	pce_printf (
222
+		"A=%02X BC=%04X DE=%04X HL=%04X SP=%04X PC=%04X PSW=%02X[%c%c%c%c%c]\n"
223
+		"%s\n",
224
+		(unsigned) e8080_get_a (c), (unsigned) e8080_get_bc (c),
225
+		(unsigned) e8080_get_de (c), (unsigned) e8080_get_hl (c),
226
+		(unsigned) e8080_get_sp (c), (unsigned) e8080_get_pc (c),
227
+		(unsigned) e8080_get_psw (c),
228
+		(e8080_get_sf (c)) ? 'S' : '-',
229
+		(e8080_get_zf (c)) ? 'Z' : '-',
230
+		(e8080_get_af (c)) ? 'A' : '-',
231
+		(e8080_get_pf (c)) ? 'P' : '-',
232
+		(e8080_get_cf (c)) ? 'C' : '-',
233
+		str
234
+	);
235
+
236
+	if (c->halt) {
237
+		pce_printf ("HALT=1\n");
238
+	}
239
+}
240
+
241
+void c80_print_cpu (e8080_t *c, int oneline)
242
+{
243
+	if (oneline) {
244
+		if (e8080_get_flags (c) & E8080_FLAG_Z80) {
245
+			c80_print_cpu_z80_1 (c);
246
+		}
247
+		else {
248
+			c80_print_cpu_8080_1 (c);
249
+		}
250
+	}
251
+	else {
252
+		if (e8080_get_flags (c) & E8080_FLAG_Z80) {
253
+			c80_print_cpu_z80_2 (c);
254
+		}
255
+		else {
256
+			c80_print_cpu_8080_2 (c);
257
+		}
258
+	}
259
+}
260
+
261
+void print_state_cpu (e8080_t *c)
262
+{
263
+	if (e8080_get_flags (c) & E8080_FLAG_Z80) {
264
+		pce_prt_sep ("Z80");
265
+	}
266
+	else {
267
+		pce_prt_sep ("8080");
268
+	}
269
+
270
+	c80_print_cpu (c, 0);
271
+}
272
+
273
+static
274
+void print_state_mem (cpm80_t *sim)
275
+{
276
+	pce_prt_sep ("MEMORY");
277
+	mem_prt_state (sim->mem, stdout);
278
+}
279
+
280
+static
281
+void print_state (cpm80_t *sim, const char *str)
282
+{
283
+	cmd_t cmd;
284
+
285
+	cmd_set_str (&cmd, str);
286
+
287
+	if (cmd_match_eol (&cmd)) {
288
+		return;
289
+	}
290
+
291
+	while (!cmd_match_eol (&cmd)) {
292
+		if (cmd_match (&cmd, "cpu")) {
293
+			print_state_cpu (sim->cpu);
294
+		}
295
+		else if (cmd_match (&cmd, "mem")) {
296
+			print_state_mem (sim);
297
+		}
298
+		else {
299
+			printf ("unknown component (%s)\n", cmd_get_str (&cmd));
300
+			return;
301
+		}
302
+	}
303
+}
304
+
305
+static
306
+int c80_check_break (cpm80_t *sim)
307
+{
308
+	if (bps_check (&sim->bps, 0, e8080_get_pc (sim->cpu), stdout)) {
309
+		return (1);
310
+	}
311
+
312
+	if (sim->brk) {
313
+		return (1);
314
+	}
315
+
316
+	return (0);
317
+}
318
+
319
+static
320
+void c80_exec (cpm80_t *sim)
321
+{
322
+	unsigned long old;
323
+
324
+	old = e8080_get_opcnt (sim->cpu);
325
+
326
+	while (e8080_get_opcnt (sim->cpu) == old) {
327
+		c80_clock (sim, 4);
328
+
329
+		if (sim->brk) {
330
+			break;
331
+		}
332
+	}
333
+}
334
+
335
+static
336
+int c80_exec_to (cpm80_t *sim, unsigned short addr)
337
+{
338
+	while (e8080_get_pc (sim->cpu) != addr) {
339
+		c80_clock (sim, 4);
340
+
341
+		if (sim->brk) {
342
+			return (1);
343
+		}
344
+	}
345
+
346
+	return (0);
347
+}
348
+
349
+static
350
+int c80_exec_off (cpm80_t *sim, unsigned short addr)
351
+{
352
+	while (e8080_get_pc (sim->cpu) == addr) {
353
+		c80_clock (sim, 4);
354
+
355
+		if (sim->brk) {
356
+			return (1);
357
+		}
358
+	}
359
+
360
+	return (0);
361
+}
362
+
363
+void c80_run (cpm80_t *sim)
364
+{
365
+	pce_start (&sim->brk);
366
+
367
+	c80_clock_discontinuity (sim);
368
+
369
+	while (1) {
370
+		c80_clock (sim, 64);
371
+
372
+		if (sim->brk) {
373
+			break;
374
+		}
375
+	}
376
+
377
+	pce_stop();
378
+}
379
+
380
+
381
+static
382
+int c80_hook_undef (void *ext, unsigned char op)
383
+{
384
+	cpm80_t *sim;
385
+
386
+	sim = ext;
387
+
388
+	pce_log (MSG_DEB,
389
+		"%04X: undefined operation [%02X %02X %02X %02X]\n",
390
+		(unsigned) e8080_get_pc (sim->cpu),
391
+		(unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu)),
392
+		(unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 1),
393
+		(unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 2),
394
+		(unsigned) e8080_get_mem8 (sim->cpu, e8080_get_pc (sim->cpu) + 3)
395
+	);
396
+
397
+	pce_usleep (5000);
398
+
399
+	return (0);
400
+}
401
+
402
+static
403
+int c80_hook_rst (void *ext, unsigned char op)
404
+{
405
+	unsigned  fct, ex;
406
+	cpm80_t *sim;
407
+
408
+	sim = ext;
409
+
410
+	ex = (op >> 3) & 7;
411
+
412
+	if (ex == 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 (ex == 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
+
436
+static
437
+void 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
+
457
+static
458
+void 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
+		c80_exec (sim);
478
+
479
+		if (c80_check_break (sim)) {
480
+			break;
481
+		}
482
+	}
483
+
484
+	pce_stop();
485
+}
486
+
487
+static
488
+void c80_cmd_g (cpm80_t *sim, cmd_t *cmd)
489
+{
490
+	if (cmd_match (cmd, "b")) {
491
+		c80_cmd_g_b (sim, cmd);
492
+		return;
493
+	}
494
+
495
+	if (!cmd_match_end (cmd)) {
496
+		return;
497
+	}
498
+
499
+	c80_run (sim);
500
+}
501
+
502
+static
503
+void c80_cmd_i (cpm80_t *sim, cmd_t *cmd)
504
+{
505
+	unsigned short port;
506
+
507
+	if (!cmd_match_uint16 (cmd, &port)) {
508
+		cmd_error (cmd, "need a port address");
509
+		return;
510
+	}
511
+
512
+	if (!cmd_match_end (cmd)) {
513
+		return;
514
+	}
515
+
516
+	pce_printf ("%04X: %02X\n", port, e8080_get_port8 (sim->cpu, port));
517
+}
518
+
519
+static
520
+void c80_cmd_o (cpm80_t *sim, cmd_t *cmd)
521
+{
522
+	unsigned short port, val;
523
+
524
+	if (!cmd_match_uint16 (cmd, &port)) {
525
+		cmd_error (cmd, "need a port address");
526
+		return;
527
+	}
528
+
529
+	if (!cmd_match_uint16 (cmd, &val)) {
530
+		cmd_error (cmd, "need a value");
531
+		return;
532
+	}
533
+
534
+	if (!cmd_match_end (cmd)) {
535
+		return;
536
+	}
537
+
538
+	e8080_set_port8 (sim->cpu, port, val);
539
+}
540
+
541
+static
542
+void c80_cmd_p (cpm80_t *sim, cmd_t *cmd)
543
+{
544
+	int            s;
545
+	unsigned short i, n;
546
+	e8080_disasm_t dis;
547
+
548
+	n = 1;
549
+	s = 0;
550
+
551
+	if (cmd_match_uint16 (cmd, &n)) {
552
+		s = 1;
553
+	}
554
+
555
+	if (!cmd_match_end (cmd)) {
556
+		return;
557
+	}
558
+
559
+	pce_start (&sim->brk);
560
+
561
+	c80_clock_discontinuity (sim);
562
+
563
+	for (i = 0; i < n; i++) {
564
+		c80_disasm_cur (sim->cpu, &dis);
565
+
566
+		if (s) {
567
+			c80_print_cpu (sim->cpu, 1);
568
+		}
569
+
570
+		if (dis.flags & E8080_OPF_CALL) {
571
+			if (c80_exec_to (sim, dis.pc + dis.data_cnt)) {
572
+				break;
573
+			}
574
+		}
575
+		else {
576
+			if (c80_exec_off (sim, dis.pc)) {
577
+				break;
578
+			}
579
+		}
580
+	}
581
+
582
+	if (s) {
583
+		c80_print_cpu (sim->cpu, 1);
584
+	}
585
+
586
+	pce_stop();
587
+
588
+	print_state_cpu (sim->cpu);
589
+}
590
+
591
+static
592
+void c80_cmd_r (cpm80_t *sim, cmd_t *cmd)
593
+{
594
+	unsigned long val;
595
+	char          sym[256];
596
+
597
+	if (cmd_match_eol (cmd)) {
598
+		print_state_cpu (sim->cpu);
599
+		return;
600
+	}
601
+
602
+	if (!cmd_match_ident (cmd, sym, 256)) {
603
+		cmd_error (cmd, "missing register");
604
+		return;
605
+	}
606
+
607
+	if (e8080_get_reg (sim->cpu, sym, &val)) {
608
+		cmd_error (cmd, "bad register\n");
609
+		return;
610
+	}
611
+
612
+	if (cmd_match_eol (cmd)) {
613
+		pce_printf ("%02lX\n", val);
614
+		return;
615
+	}
616
+
617
+	if (!cmd_match_uint32 (cmd, &val)) {
618
+		cmd_error (cmd, "missing value\n");
619
+		return;
620
+	}
621
+
622
+	if (!cmd_match_end (cmd)) {
623
+		return;
624
+	}
625
+
626
+	e8080_set_reg (sim->cpu, sym, val);
627
+
628
+	print_state_cpu (sim->cpu);
629
+}
630
+
631
+static
632
+void c80_cmd_s (cpm80_t *sim, cmd_t *cmd)
633
+{
634
+	if (cmd_match_eol (cmd)) {
635
+		print_state_cpu (sim->cpu);
636
+		return;
637
+	}
638
+
639
+	print_state (sim, cmd_get_str (cmd));
640
+}
641
+
642
+static
643
+void c80_cmd_t (cpm80_t *sim, cmd_t *cmd)
644
+{
645
+	int            s;
646
+	unsigned short i, n;
647
+
648
+	n = 1;
649
+	s = 0;
650
+
651
+	if (cmd_match_uint16 (cmd, &n)) {
652
+		s = 1;
653
+	}
654
+
655
+	if (!cmd_match_end (cmd)) {
656
+		return;
657
+	}
658
+
659
+	pce_start (&sim->brk);
660
+
661
+	c80_clock_discontinuity (sim);
662
+
663
+	for (i = 0; i < n; i++) {
664
+		if (s) {
665
+			c80_print_cpu (sim->cpu, 1);
666
+		}
667
+
668
+		c80_exec (sim);
669
+	}
670
+
671
+	if (s) {
672
+		c80_print_cpu (sim->cpu, 1);
673
+	}
674
+
675
+	pce_stop();
676
+
677
+	print_state_cpu (sim->cpu);
678
+}
679
+
680
+static
681
+void c80_cmd_u (cpm80_t *sim, cmd_t *cmd)
682
+{
683
+	int                   to;
684
+	unsigned              i;
685
+	unsigned short        addr, cnt, taddr;
686
+	static unsigned int   first = 1;
687
+	static unsigned short saddr = 0;
688
+	e8080_disasm_t        op;
689
+	char                  str[256];
690
+
691
+	if (first) {
692
+		first = 0;
693
+		saddr = e8080_get_pc (sim->cpu);
694
+	}
695
+
696
+	to = 0;
697
+	addr = saddr;
698
+	cnt = 16;
699
+
700
+	if (cmd_match (cmd, "t")) {
701
+		to = 1;
702
+	}
703
+
704
+	if (cmd_match_uint16 (cmd, &addr)) {
705
+		cmd_match_uint16 (cmd, &cnt);
706
+	}
707
+
708
+	if (!cmd_match_end (cmd)) {
709
+		return;
710
+	}
711
+
712
+	if (to) {
713
+		if (addr < (2 * cnt)) {
714
+			taddr = 0;
715
+		}
716
+		else {
717
+			taddr = addr - 2 * cnt;
718
+		}
719
+
720
+		while (taddr <= addr) {
721
+			c80_disasm_mem (sim->cpu, &op, taddr);
722
+			c80_disasm_str (str, &op, 1, 1);
723
+
724
+			pce_printf ("%s\n", str);
725
+
726
+			taddr += op.data_cnt;
727
+		}
728
+	}
729
+	else {
730
+		for (i = 0; i < cnt; i++) {
731
+			c80_disasm_mem (sim->cpu, &op, addr);
732
+			c80_disasm_str (str, &op, 1, 1);
733
+
734
+			pce_printf ("%s\n", str);
735
+
736
+			addr += op.data_cnt;
737
+		}
738
+	}
739
+
740
+	saddr = addr;
741
+}
742
+
743
+int c80_cmd (cpm80_t *sim, cmd_t *cmd)
744
+{
745
+	if (cmd_match (cmd, "b")) {
746
+		cmd_do_b (cmd, &sim->bps);
747
+	}
748
+	else if (cmd_match (cmd, "c")) {
749
+		c80_cmd_c (sim, cmd);
750
+	}
751
+	else if (cmd_match (cmd, "g")) {
752
+		c80_cmd_g (sim, cmd);
753
+	}
754
+	else if (cmd_match (cmd, "i")) {
755
+		c80_cmd_i (sim, cmd);
756
+	}
757
+	else if (cmd_match (cmd, "o")) {
758
+		c80_cmd_o (sim, cmd);
759
+	}
760
+	else if (cmd_match (cmd, "p")) {
761
+		c80_cmd_p (sim, cmd);
762
+	}
763
+	else if (cmd_match (cmd, "r")) {
764
+		c80_cmd_r (sim, cmd);
765
+	}
766
+	else if (cmd_match (cmd, "s")) {
767
+		c80_cmd_s (sim, cmd);
768
+	}
769
+	else if (cmd_match (cmd, "t")) {
770
+		c80_cmd_t (sim, cmd);
771
+	}
772
+	else if (cmd_match (cmd, "u")) {
773
+		c80_cmd_u (sim, cmd);
774
+	}
775
+	else {
776
+		return (1);
777
+	}
778
+
779
+	return (0);
780
+}
781
+
782
+void c80_cmd_init (cpm80_t *sim, monitor_t *mon)
783
+{
784
+	mon_cmd_add (mon, par_cmd, sizeof (par_cmd) / sizeof (par_cmd[0]));
785
+	mon_cmd_add_bp (mon);
786
+
787
+	e8080_set_hook_undef_fct (sim->cpu, sim, c80_hook_undef);
788
+	e8080_set_hook_rst_fct (sim->cpu, sim, c80_hook_rst);
789
+}

+ 43
- 0
src/arch/cpm80/cmd.h View File

@@ -0,0 +1,43 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/cmd.h                                         *
7
+ * Created:     2012-11-28 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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
+#ifndef PCE_CPM80_CMD_H
24
+#define PCE_CPM80_CMD_H 1
25
+
26
+
27
+#include "cpm80.h"
28
+
29
+#include <cpu/e8080/e8080.h>
30
+#include <lib/cmd.h>
31
+#include <lib/monitor.h>
32
+
33
+
34
+void print_state_cpu (e8080_t *c);
35
+
36
+void c80_run (cpm80_t *sim);
37
+
38
+int c80_cmd (cpm80_t *sim, cmd_t *cmd);
39
+
40
+void c80_cmd_init (cpm80_t *sim, monitor_t *mon);
41
+
42
+
43
+#endif

+ 445
- 0
src/arch/cpm80/cpm80.c View File

@@ -0,0 +1,445 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/sim8080/sim8080.c                                   *
7
+ * Created:     2012-11-28 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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
+#include "msg.h"
27
+
28
+#include <ctype.h>
29
+#include <stdlib.h>
30
+#include <string.h>
31
+#include <unistd.h>
32
+#include <fcntl.h>
33
+#include <sys/types.h>
34
+
35
+#include <cpu/e8080/e8080.h>
36
+#include <devices/memory.h>
37
+#include <drivers/block/block.h>
38
+#include <drivers/char/char.h>
39
+#include <libini/libini.h>
40
+#include <lib/brkpt.h>
41
+#include <lib/inidsk.h>
42
+#include <lib/iniram.h>
43
+#include <lib/load.h>
44
+#include <lib/log.h>
45
+#include <lib/msg.h>
46
+#include <lib/path.h>
47
+#include <lib/sysdep.h>
48
+
49
+
50
+static
51
+void c80_set_port8 (cpm80_t *sim, unsigned long addr, unsigned char val)
52
+{
53
+	switch (addr) {
54
+	case 0x01:
55
+	case 0x11:
56
+		if (val == 0x5f) {
57
+			val = 0x08;
58
+		}
59
+		con_putc (sim, val);
60
+		break;
61
+
62
+	case 0x00:
63
+	case 0x02:
64
+		break;
65
+
66
+	case 0xfe:
67
+		c80_stop (sim);
68
+		break;
69
+
70
+	default:
71
+		sim_log_deb ("OUT %04lX, %02X\n", addr, val);
72
+		break;
73
+	}
74
+}
75
+
76
+static
77
+unsigned char c80_get_port8 (cpm80_t *sim, unsigned long addr)
78
+{
79
+	unsigned char val;
80
+
81
+	val = 0x00;
82
+
83
+	switch (addr) {
84
+	case 0x00:
85
+	case 0x10:
86
+		val = 0x02;
87
+		if (con_ready (sim)) {
88
+			val |= (addr == 0) ? 0x20 : 0x21;
89
+		}
90
+		break;
91
+
92
+	case 0x01:
93
+	case 0x11:
94
+		if (con_getc (sim, &val)) {
95
+			val = 0;
96
+		}
97
+		else {
98
+			if ((val == 0x7f) || (val == 0x08)) {
99
+				val = 0x5f;
100
+			}
101
+		}
102
+		break;
103
+
104
+	case 0x13:
105
+	case 0x20:
106
+		val = 0;
107
+		break;
108
+
109
+	case 0xff:
110
+		val = 0xff;
111
+		break;
112
+
113
+	default:
114
+		sim_log_deb ("IN %04lX (%02X)\n", addr, val);
115
+		break;
116
+	}
117
+
118
+	return (val);
119
+}
120
+
121
+static
122
+void c80_setup_system (cpm80_t *sim, ini_sct_t *ini)
123
+{
124
+	const char *model;
125
+	ini_sct_t  *sct;
126
+
127
+	sim->brk = 0;
128
+	sim->clk_cnt = 0;
129
+	sim->clk_div = 0;
130
+
131
+	sim->model = CPM80_MODEL_PLAIN;
132
+
133
+	sct = ini_next_sct (ini, NULL, "system");
134
+
135
+	ini_get_string (sct, "model", &model, "cpm");
136
+
137
+	pce_log_tag (MSG_INF,
138
+		"SYSTEM:",
139
+		"model=%s\n", model
140
+	);
141
+
142
+	if (strcmp (model, "plain") == 0) {
143
+		sim->model = CPM80_MODEL_PLAIN;
144
+	}
145
+	else if (strcmp (model, "cpm") == 0) {
146
+		sim->model = CPM80_MODEL_CPM;
147
+	}
148
+	else {
149
+		pce_log (MSG_ERR, "*** unknown machine model (%s)\n", model);
150
+	}
151
+}
152
+
153
+static
154
+void c80_setup_mem (cpm80_t *sim, ini_sct_t *ini)
155
+{
156
+	sim->mem = mem_new();
157
+
158
+	ini_get_ram (sim->mem, ini, &sim->ram);
159
+	ini_get_rom (sim->mem, ini);
160
+}
161
+
162
+static
163
+void c80_setup_cpu (cpm80_t *sim, ini_sct_t *ini)
164
+{
165
+	const char    *cpu;
166
+	unsigned      speed;
167
+	unsigned long clock;
168
+	ini_sct_t     *sct;
169
+
170
+	sct = ini_next_sct (ini, NULL, "system");
171
+
172
+	if (ini_get_uint32 (sct, "clock", &clock, 0)) {
173
+		ini_get_uint16 (sct, "speed", &speed, 0);
174
+		clock = 1000000UL * speed;
175
+	}
176
+
177
+	ini_get_string (sct, "cpu", &cpu, "8080");
178
+
179
+	pce_log_tag (MSG_INF, "CPU:", "model=%s clock=%lu\n", cpu, clock);
180
+
181
+	sim->cpu = e8080_new();
182
+
183
+	if (sim->cpu == NULL) {
184
+		pce_log (MSG_ERR, "*** failed to create the CPU\n");
185
+		return;
186
+	}
187
+
188
+	e8080_set_mem_fct (sim->cpu, sim->mem, &mem_get_uint8, &mem_set_uint8);
189
+	e8080_set_port_fct (sim->cpu, sim, c80_get_port8, c80_set_port8);
190
+
191
+	if (sim->ram != NULL) {
192
+		unsigned char *data;
193
+		unsigned long size;
194
+
195
+		size = mem_blk_get_size (sim->ram);
196
+		data = mem_blk_get_data (sim->ram);
197
+
198
+		e8080_set_mem_map_rd (sim->cpu, 0, size - 1, data);
199
+		e8080_set_mem_map_wr (sim->cpu, 0, size - 1, data);
200
+	}
201
+
202
+	sim->clock = clock;
203
+
204
+	if (c80_set_cpu_model (sim, cpu)) {
205
+		pce_log (MSG_ERR, "*** failed to set CPU model (%s)\n", cpu);
206
+	}
207
+}
208
+
209
+static
210
+void c80_setup_char (cpm80_t *sim, ini_sct_t *ini)
211
+{
212
+	const char *con, *aux, *lst;
213
+	ini_sct_t  *sct;
214
+
215
+	sim->con = NULL;
216
+	sim->aux = NULL;
217
+	sim->lst = NULL;
218
+
219
+	sim->con_buf = 0;
220
+	sim->con_buf_cnt = 0;
221
+
222
+	sct = ini_next_sct (ini, NULL, "system");
223
+
224
+	ini_get_string (sct, "con", &con, NULL);
225
+	ini_get_string (sct, "aux", &aux, NULL);
226
+	ini_get_string (sct, "lst", &lst, NULL);
227
+
228
+	if (con != NULL) {
229
+		pce_log_tag (MSG_INF, "CON:", "driver=%s\n", con);
230
+
231
+		if ((sim->con = chr_open (con)) == NULL) {
232
+			pce_log (MSG_ERR, "*** opening con failed\n");
233
+		}
234
+	}
235
+
236
+	if (aux != NULL) {
237
+		pce_log_tag (MSG_INF, "AUX:", "driver=%s\n", aux);
238
+
239
+		if ((sim->aux = chr_open (aux)) == NULL) {
240
+			pce_log (MSG_ERR, "*** opening aux failed\n");
241
+		}
242
+	}
243
+
244
+	if (lst != NULL) {
245
+		pce_log_tag (MSG_INF, "LST:", "driver=%s\n", lst);
246
+
247
+		if ((sim->lst = chr_open (lst)) == NULL) {
248
+			pce_log (MSG_ERR, "*** opening lst failed\n");
249
+		}
250
+	}
251
+}
252
+
253
+static
254
+void c80_setup_disks (cpm80_t *sim, ini_sct_t *ini)
255
+{
256
+	ini_sct_t *sct;
257
+	disk_t    *dsk;
258
+
259
+	sim->dsks = dsks_new();
260
+
261
+	sct = NULL;
262
+	while ((sct = ini_next_sct (ini, sct, "disk")) != NULL) {
263
+		if (ini_get_disk (sct, &dsk)) {
264
+			pce_log (MSG_ERR, "*** loading drive failed\n");
265
+			continue;
266
+		}
267
+
268
+		if (dsk == NULL) {
269
+			continue;
270
+		}
271
+
272
+		dsks_add_disk (sim->dsks, dsk);
273
+	}
274
+}
275
+
276
+cpm80_t *c80_new (ini_sct_t *ini)
277
+{
278
+	cpm80_t *sim;
279
+
280
+	if ((sim = malloc (sizeof (cpm80_t))) == NULL) {
281
+		return (NULL);
282
+	}
283
+
284
+	memset (sim, 0, sizeof (cpm80_t));
285
+
286
+	bps_init (&sim->bps);
287
+
288
+	c80_setup_system (sim, ini);
289
+	c80_setup_mem (sim, ini);
290
+	c80_setup_cpu (sim, ini);
291
+	c80_setup_char (sim, ini);
292
+	c80_setup_disks (sim, ini);
293
+	pce_load_mem_ini (sim->mem, ini);
294
+
295
+	if (sim->model == CPM80_MODEL_CPM) {
296
+		c80_bios_init (sim);
297
+	}
298
+
299
+	return (sim);
300
+}
301
+
302
+static
303
+void c80_del_char (cpm80_t *sim)
304
+{
305
+	if (sim->lst != NULL) {
306
+		chr_close (sim->lst);
307
+	}
308
+
309
+	if (sim->aux != NULL) {
310
+		chr_close (sim->aux);
311
+	}
312
+
313
+	if (sim->con != NULL) {
314
+		chr_close (sim->con);
315
+	}
316
+}
317
+
318
+void c80_del (cpm80_t *sim)
319
+{
320
+	if (sim == NULL) {
321
+		return;
322
+	}
323
+
324
+	dsks_del (sim->dsks);
325
+	c80_del_char (sim);
326
+	e8080_del (sim->cpu);
327
+	mem_del (sim->mem);
328
+	bps_free (&sim->bps);
329
+
330
+	free (sim);
331
+}
332
+
333
+void c80_stop (cpm80_t *sim)
334
+{
335
+	c80_set_msg (sim, "emu.stop", NULL);
336
+}
337
+
338
+void c80_reset (cpm80_t *sim)
339
+{
340
+	e8080_reset (sim->cpu);
341
+
342
+	if (sim->model == CPM80_MODEL_CPM) {
343
+		c80_bios_init (sim);
344
+	}
345
+}
346
+
347
+int c80_set_cpu_model (cpm80_t *sim, const char *str)
348
+{
349
+	if (strcmp (str, "8080") == 0) {
350
+		e8080_set_8080 (sim->cpu);
351
+	}
352
+	else if (strcmp (str, "Z80") == 0) {
353
+		e8080_set_z80 (sim->cpu);
354
+	}
355
+	else {
356
+		return (1);
357
+	}
358
+
359
+	return (0);
360
+}
361
+
362
+void c80_idle (cpm80_t *sim)
363
+{
364
+	pce_usleep (10000);
365
+
366
+	c80_clock_discontinuity (sim);
367
+}
368
+
369
+void c80_clock_discontinuity (cpm80_t *sim)
370
+{
371
+	sim->sync_clk = 0;
372
+	sim->sync_us = 0;
373
+	sim->sync_sleep = 0;
374
+
375
+	pce_get_interval_us (&sim->sync_us);
376
+}
377
+
378
+void c80_set_clock (cpm80_t *sim, unsigned long clock)
379
+{
380
+	sim->clock = clock;
381
+
382
+	sim_log_deb ("set clock to %lu\n", clock);
383
+
384
+	c80_clock_discontinuity (sim);
385
+}
386
+
387
+void c80_set_speed (cpm80_t *sim, unsigned speed)
388
+{
389
+	c80_set_clock (sim, 1000000UL * speed);
390
+}
391
+
392
+static
393
+void c80_realtime_sync (cpm80_t *sim, unsigned long n)
394
+{
395
+	unsigned long fct;
396
+	unsigned long us1, us2, sl;
397
+
398
+	if (sim->clock == 0) {
399
+		return;
400
+	}
401
+
402
+	sim->sync_clk += n;
403
+
404
+	fct = sim->clock / CPM80_CPU_SYNC;
405
+
406
+	if (sim->sync_clk < fct) {
407
+		return;
408
+	}
409
+
410
+	sim->sync_clk -= fct;
411
+
412
+	us1 = pce_get_interval_us (&sim->sync_us);
413
+	us2 = (1000000 / CPM80_CPU_SYNC);
414
+
415
+	if (us1 < us2) {
416
+		sim->sync_sleep += us2 - us1;
417
+	}
418
+	else {
419
+		sim->sync_sleep -= us1 - us2;
420
+	}
421
+
422
+	if (sim->sync_sleep >= (1000000 / CPM80_CPU_SYNC)) {
423
+		pce_usleep (1000000 / CPM80_CPU_SYNC);
424
+		sl = pce_get_interval_us (&sim->sync_us);
425
+		sim->sync_sleep -= sl;
426
+	}
427
+
428
+	if (sim->sync_sleep < -1000000) {
429
+		sim_log_deb ("system too slow, skipping 1 second\n");
430
+		sim->sync_sleep += 1000000;
431
+	}
432
+}
433
+
434
+void c80_clock (cpm80_t *sim, unsigned n)
435
+{
436
+	sim->clk_div += n;
437
+
438
+	if (sim->clk_div >= 16384) {
439
+		sim->clk_div -= 16384;
440
+
441
+		c80_realtime_sync (sim, 16384);
442
+	}
443
+
444
+	e8080_clock (sim->cpu, n);
445
+}

+ 112
- 0
src/arch/cpm80/cpm80.h View File

@@ -0,0 +1,112 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/cpm80.h                                       *
7
+ * Created:     2012-11-28 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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
+#ifndef PCE_CPM80_CPM80_H
24
+#define PCE_CPM80_CPM80_H 1
25
+
26
+
27
+#include <cpu/e8080/e8080.h>
28
+#include <devices/memory.h>
29
+#include <drivers/block/block.h>
30
+#include <drivers/char/char.h>
31
+#include <libini/libini.h>
32
+#include <lib/brkpt.h>
33
+
34
+
35
+#define PCE_BRK_STOP  1
36
+#define PCE_BRK_ABORT 2
37
+#define PCE_BRK_SNAP  3
38
+
39
+#define CPM80_CPU_SYNC  100
40
+#define CPM80_DRIVE_MAX 16
41
+
42
+#define CPM80_MODEL_PLAIN 0
43
+#define CPM80_MODEL_CPM   1
44
+
45
+
46
+/*****************************************************************************
47
+ * @short The cpm80 context struct
48
+ *****************************************************************************/
49
+typedef struct cpm80_s {
50
+	unsigned       model;
51
+
52
+	e8080_t        *cpu;
53
+
54
+	memory_t       *mem;
55
+	mem_blk_t      *ram;
56
+
57
+	bp_set_t       bps;
58
+
59
+	unsigned long  clk_cnt;
60
+	unsigned long  clk_div;
61
+
62
+	unsigned long  clock;
63
+	unsigned long  sync_clk;
64
+	unsigned long  sync_us;
65
+	long           sync_sleep;
66
+
67
+	unsigned       brk;
68
+
69
+	char_drv_t     *con;
70
+	char_drv_t     *aux;
71
+	char_drv_t     *lst;
72
+
73
+	unsigned char  con_buf;
74
+	unsigned char  con_buf_cnt;
75
+
76
+	disks_t        *dsks;
77
+
78
+	unsigned       addr_ccp;
79
+	unsigned       addr_bdos;
80
+	unsigned       addr_bios;
81
+
82
+	unsigned       bios_disk_cnt;
83
+	unsigned char  bios_disk_type[CPM80_DRIVE_MAX];
84
+
85
+	unsigned short bios_dma;
86
+	unsigned char  bios_dsk;
87
+	unsigned char  bios_trk;
88
+	unsigned char  bios_sec;
89
+} cpm80_t;
90
+
91
+
92
+cpm80_t *c80_new (ini_sct_t *ini);
93
+
94
+void c80_del (cpm80_t *sim);
95
+
96
+void c80_stop (cpm80_t *sim);
97
+
98
+void c80_reset (cpm80_t *sim);
99
+
100
+int c80_set_cpu_model (cpm80_t *sim, const char *str);
101
+
102
+void c80_idle (cpm80_t *sim);
103
+
104
+void c80_clock_discontinuity (cpm80_t *sim);
105
+
106
+void c80_set_clock (cpm80_t *sim, unsigned long clock);
107
+void c80_set_speed (cpm80_t *sim, unsigned speed);
108
+
109
+void c80_clock (cpm80_t *sim, unsigned n);
110
+
111
+
112
+#endif

+ 378
- 0
src/arch/cpm80/main.c View File

@@ -0,0 +1,378 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/main.c                                        *
7
+ * Created:     2012-11-28 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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 "cpm80.h"
26
+#include "msg.h"
27
+
28
+#include <stdarg.h>
29
+#include <stdlib.h>
30
+#include <string.h>
31
+
32
+#include <signal.h>
33
+
34
+#include <drivers/char/char.h>
35
+
36
+#include <lib/console.h>
37
+#include <lib/getopt.h>
38
+#include <lib/log.h>
39
+#include <lib/monitor.h>
40
+#include <lib/path.h>
41
+#include <lib/sysdep.h>
42
+
43
+
44
+monitor_t  par_mon;
45
+
46
+cpm80_t    *par_sim = NULL;
47
+ini_sct_t  *par_cfg = NULL;
48
+
49
+static ini_strings_t par_ini_str;
50
+
51
+
52
+static pce_option_t opts[] = {
53
+	{ '?', 0, "help", NULL, "Print usage information" },
54
+	{ 'c', 1, "config", "string", "Set the config file name [none]" },
55
+	{ 'd', 1, "path", "string", "Add a directory to the search path" },
56
+	{ 'i', 1, "ini-prefix", "string", "Add an ini string before the config file" },
57
+	{ 'I', 1, "ini-append", "string", "Add an ini string after the config file" },
58
+	{ 'l', 1, "log", "string", "Set the log file name [none]" },
59
+	{ 'q', 0, "quiet", NULL, "Set the log level to error [no]" },
60
+	{ 'r', 0, "run", NULL, "Start running immediately [no]" },
61
+	{ 'R', 0, "no-monitor", NULL, "Never stop running [no]" },
62
+	{ 's', 1, "speed", "int", "Set the CPU speed" },
63
+	{ 'v', 0, "verbose", NULL, "Set the log level to debug [no]" },
64
+	{ 'V', 0, "version", NULL, "Print version information" },
65
+	{  -1, 0, NULL, NULL, NULL }
66
+};
67
+
68
+static
69
+void print_help (void)
70
+{
71
+	pce_getopt_help (
72
+		"pce-cpm80: CP/M-80 emulator",
73
+		"usage: pce-cpm80 [options]",
74
+		opts
75
+	);
76
+
77
+	fflush (stdout);
78
+}
79
+
80
+static
81
+void print_version (void)
82
+{
83
+	fputs (
84
+		"pce-cpm80 version " PCE_VERSION_STR
85
+		"\n\n"
86
+		"Copyright (C) 2012-2016 Hampa Hug <hampa@hampa.ch>\n",
87
+		stdout
88
+	);
89
+
90
+	fflush (stdout);
91
+}
92
+
93
+static
94
+void sim_log_banner (void)
95
+{
96
+	pce_log (MSG_MSG, "pce-cpm80 version " PCE_VERSION_STR "\n");
97
+}
98
+
99
+static
100
+void sig_int (int s)
101
+{
102
+	fprintf (stderr, "pce-cpm80: sigint\n");
103
+	fflush (stderr);
104
+
105
+	if (par_sim->brk == 0) {
106
+		par_sim->brk = PCE_BRK_STOP;
107
+	}
108
+	else {
109
+		par_sim->brk = PCE_BRK_ABORT;
110
+	}
111
+}
112
+
113
+static
114
+void sig_term (int s)
115
+{
116
+	fprintf (stderr, "pce-cpm80: sigterm\n");
117
+	fflush (stderr);
118
+
119
+	par_sim->brk = PCE_BRK_ABORT;
120
+}
121
+
122
+void sig_segv (int s)
123
+{
124
+	fprintf (stderr, "pce-cpm80: segmentation fault\n");
125
+
126
+	if ((par_sim != NULL) && (par_sim->cpu != NULL)) {
127
+		print_state_cpu (par_sim->cpu);
128
+	}
129
+
130
+	fflush (stderr);
131
+
132
+	exit (1);
133
+}
134
+
135
+static
136
+void sim_atexit (void)
137
+{
138
+	pce_set_fd_interactive (0, 1);
139
+}
140
+
141
+static
142
+int cmd_get_sym (cpm80_t *sim, const char *sym, unsigned long *val)
143
+{
144
+	if (e8080_get_reg (sim->cpu, sym, val) == 0) {
145
+		return (0);
146
+	}
147
+
148
+	if (strcmp (sym, "bios") == 0) {
149
+		*val = sim->addr_bios;
150
+		return (0);
151
+	}
152
+
153
+	if (strcmp (sym, "bdos") == 0) {
154
+		*val = sim->addr_bdos;
155
+		return (0);
156
+	}
157
+
158
+	if (strcmp (sym, "ccp") == 0) {
159
+		*val = sim->addr_ccp;
160
+		return (0);
161
+	}
162
+
163
+	return (1);
164
+}
165
+
166
+static
167
+int cmd_set_sym (cpm80_t *sim, const char *sym, unsigned long val)
168
+{
169
+	if (e8080_set_reg (sim->cpu, sym, val) == 0) {
170
+		return (0);
171
+	}
172
+
173
+	return (1);
174
+}
175
+
176
+void sim_log_deb (const char *msg, ...)
177
+{
178
+	va_list  va;
179
+	unsigned pc;
180
+
181
+	if (par_sim == NULL) {
182
+		pc = 0;
183
+	}
184
+	else {
185
+		pc = e8080_get_pc (par_sim->cpu);
186
+	}
187
+
188
+	pce_log (MSG_DEB, "[%04X] ", pc);
189
+
190
+	va_start (va, msg);
191
+	pce_log_va (MSG_DEB, msg, va);
192
+	va_end (va);
193
+}
194
+
195
+static
196
+int pce_load_config (ini_sct_t *ini, const char *fname)
197
+{
198
+	if (fname == NULL) {
199
+		return (0);
200
+	}
201
+
202
+	pce_log_tag (MSG_INF, "CONFIG:", "file=\"%s\"\n", fname);
203
+
204
+	if (ini_read (par_cfg, fname)) {
205
+		pce_log (MSG_ERR, "*** loading config file failed\n");
206
+		return (1);
207
+	}
208
+
209
+	return (0);
210
+}
211
+
212
+int main (int argc, char *argv[])
213
+{
214
+	int       r;
215
+	char      **optarg;
216
+	int       run, nomon;
217
+	char      *cfg;
218
+	ini_sct_t *sct;
219
+
220
+	cfg = NULL;
221
+	run = 0;
222
+	nomon = 0;
223
+
224
+	pce_log_init();
225
+	pce_log_add_fp (stderr, 0, MSG_INF);
226
+
227
+	par_cfg = ini_sct_new (NULL);
228
+
229
+	if (par_cfg == NULL) {
230
+		return (1);
231
+	}
232
+
233
+	ini_str_init (&par_ini_str);
234
+
235
+	while (1) {
236
+		r = pce_getopt (argc, argv, &optarg, opts);
237
+
238
+		if (r == GETOPT_DONE) {
239
+			break;
240
+		}
241
+
242
+		if (r < 0) {
243
+			return (1);
244
+		}
245
+
246
+		switch (r) {
247
+		case '?':
248
+			print_help();
249
+			return (0);
250
+
251
+		case 'V':
252
+			print_version();
253
+			return (0);
254
+
255
+		case 'c':
256
+			cfg = optarg[0];
257
+			break;
258
+
259
+		case 'd':
260
+			pce_path_set (optarg[0]);
261
+			break;
262
+
263
+		case 'i':
264
+			if (ini_read_str (par_cfg, optarg[0])) {
265
+				fprintf (stderr,
266
+					"%s: error parsing ini string (%s)\n",
267
+					argv[0], optarg[0]
268
+				);
269
+				return (1);
270
+			}
271
+			break;
272
+
273
+		case 'I':
274
+			ini_str_add (&par_ini_str, optarg[0], "\n", NULL);
275
+			break;
276
+
277
+		case 'l':
278
+			pce_log_add_fname (optarg[0], MSG_DEB);
279
+			break;
280
+
281
+		case 'q':
282
+			pce_log_set_level (stderr, MSG_ERR);
283
+			break;
284
+
285
+		case 'r':
286
+			run = 1;
287
+			break;
288
+
289
+		case 'R':
290
+			nomon = 1;
291
+			break;
292
+
293
+		case 's':
294
+			ini_str_add (&par_ini_str, "cpu.speed = ",
295
+				optarg[0], "\n"
296
+			);
297
+			break;
298
+
299
+		case 'v':
300
+			pce_log_set_level (stderr, MSG_DEB);
301
+			break;
302
+
303
+		case 0:
304
+			fprintf (stderr, "%s: unknown option (%s)\n",
305
+				argv[0], optarg[0]
306
+			);
307
+			return (1);
308
+
309
+		default:
310
+			return (1);
311
+		}
312
+	}
313
+
314
+	sim_log_banner();
315
+
316
+	if (pce_load_config (par_cfg, cfg)) {
317
+		return (1);
318
+	}
319
+
320
+	sct = par_cfg;
321
+
322
+	if (ini_str_eval (&par_ini_str, sct, 1)) {
323
+		return (1);
324
+	}
325
+
326
+	atexit (sim_atexit);
327
+
328
+	pce_path_ini (sct);
329
+
330
+	par_sim = c80_new (sct);
331
+
332
+	signal (SIGINT, sig_int);
333
+	signal (SIGTERM, sig_term);
334
+	signal (SIGSEGV, sig_segv);
335
+
336
+	pce_console_init (stdin, stdout);
337
+
338
+	mon_init (&par_mon);
339
+	mon_set_cmd_fct (&par_mon, c80_cmd, par_sim);
340
+	mon_set_msg_fct (&par_mon, c80_set_msg, par_sim);
341
+	mon_set_get_mem_fct (&par_mon, par_sim->mem, mem_get_uint8);
342
+	mon_set_set_mem_fct (&par_mon, par_sim->mem, mem_set_uint8);
343
+	mon_set_memory_mode (&par_mon, 0);
344
+	mon_set_prompt (&par_mon, "\033[0m-");
345
+
346
+	cmd_init (par_sim, cmd_get_sym, cmd_set_sym);
347
+	c80_cmd_init (par_sim, &par_mon);
348
+
349
+	c80_reset (par_sim);
350
+
351
+	if (nomon) {
352
+		while (par_sim->brk != PCE_BRK_ABORT) {
353
+			c80_run (par_sim);
354
+		}
355
+	}
356
+	else if (run) {
357
+		c80_run (par_sim);
358
+
359
+		if (par_sim->brk != PCE_BRK_ABORT) {
360
+			pce_puts ("\n");
361
+		}
362
+	}
363
+	else {
364
+		pce_puts ("type 'h' for help\n");
365
+	}
366
+
367
+	if (par_sim->brk != PCE_BRK_ABORT) {
368
+		mon_run (&par_mon);
369
+	}
370
+
371
+	c80_del (par_sim);
372
+
373
+	mon_free (&par_mon);
374
+	pce_console_done();
375
+	pce_log_done();
376
+
377
+	return (0);
378
+}

+ 33
- 0
src/arch/cpm80/main.h View File

@@ -0,0 +1,33 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/main.h                                        *
7
+ * Created:     2012-11-28 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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
+#ifndef PCE_CPM80_MAIN_H
24
+#define PCE_CPM80_MAIN_H 1
25
+
26
+
27
+#include <config.h>
28
+
29
+
30
+void sim_log_deb (const char *msg, ...);
31
+
32
+
33
+#endif

+ 224
- 0
src/arch/cpm80/msg.c View File

@@ -0,0 +1,224 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/msg.c                                         *
7
+ * Created:     2012-11-30 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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 "cpm80.h"
25
+#include "msg.h"
26
+
27
+#include <string.h>
28
+
29
+#include <drivers/block/block.h>
30
+
31
+#include <lib/console.h>
32
+#include <lib/inidsk.h>
33
+#include <lib/log.h>
34
+#include <lib/monitor.h>
35
+#include <lib/msg.h>
36
+
37
+
38
+typedef struct {
39
+	const char *msg;
40
+
41
+	int (*set_msg) (cpm80_t *sim, const char *msg, const char *val);
42
+} c80_msg_list_t;
43
+
44
+
45
+extern monitor_t par_mon;
46
+extern cpm80_t   *par_sim;
47
+
48
+
49
+static
50
+int c80_set_msg_emu_cpu_speed (cpm80_t *sim, const char *msg, const char *val)
51
+{
52
+	unsigned v;
53
+
54
+	if (msg_get_uint (val, &v)) {
55
+		return (1);
56
+	}
57
+
58
+	c80_set_speed (sim, v);
59
+
60
+	return (0);
61
+}
62
+
63
+static
64
+int c80_set_msg_emu_disk_commit (cpm80_t *sim, const char *msg, const char *val)
65
+{
66
+	int      r;
67
+	unsigned drv;
68
+
69
+	if (strcmp (val, "all") == 0) {
70
+		pce_log (MSG_INF, "commiting all drives\n");
71
+
72
+		if (dsks_commit (sim->dsks)) {
73
+			pce_log (MSG_ERR,
74
+				"*** commit failed for at least one disk\n"
75
+			);
76
+			return (1);
77
+		}
78
+
79
+		return (0);
80
+	}
81
+
82
+	r = 0;
83
+
84
+	while (*val != 0) {
85
+		if (msg_get_prefix_uint (&val, &drv, ":", " \t")) {
86
+			pce_log (MSG_ERR, "*** commit error: bad drive (%s)\n",
87
+				val
88
+			);
89
+
90
+			return (1);
91
+		}
92
+
93
+		pce_log (MSG_INF, "commiting drive %u\n", drv);
94
+
95
+		if (dsks_set_msg (sim->dsks, drv, "commit", NULL)) {
96
+			pce_log (MSG_ERR, "*** commit error for drive %u\n",
97
+				drv
98
+			);
99
+
100
+			r = 1;
101
+		}
102
+	}
103
+
104
+	return (r);
105
+}
106
+
107
+static
108
+int c80_set_msg_emu_disk_eject (cpm80_t *sim, const char *msg, const char *val)
109
+{
110
+	unsigned drv;
111
+	disk_t   *dsk;
112
+
113
+	while (*val != 0) {
114
+		if (msg_get_prefix_uint (&val, &drv, ":", " \t")) {
115
+			pce_log (MSG_ERR,
116
+				"*** disk eject error: bad drive (%s)\n",
117
+				val
118
+			);
119
+
120
+			return (1);
121
+		}
122
+
123
+		dsk = dsks_get_disk (sim->dsks, drv);
124
+
125
+		if (dsk == NULL) {
126
+			pce_log (MSG_ERR,
127
+				"*** disk eject error: no such disk (%lu)\n", drv
128
+			);
129
+		}
130
+		else {
131
+			pce_log (MSG_INF, "ejecting drive %lu\n", drv);
132
+
133
+			dsks_rmv_disk (sim->dsks, dsk);
134
+
135
+			dsk_del (dsk);
136
+		}
137
+	}
138
+
139
+	return (0);
140
+}
141
+
142
+static
143
+int c80_set_msg_emu_disk_insert (cpm80_t *sim, const char *msg, const char *val)
144
+{
145
+	if (dsk_insert (sim->dsks, val, 1)) {
146
+		return (1);
147
+	}
148
+
149
+	return (0);
150
+}
151
+
152
+static
153
+int c80_set_msg_emu_exit (cpm80_t *sim, const char *msg, const char *val)
154
+{
155
+	sim->brk = PCE_BRK_ABORT;
156
+
157
+	mon_set_terminate (&par_mon, 1);
158
+
159
+	return (0);
160
+}
161
+
162
+static
163
+int c80_set_msg_emu_reset (cpm80_t *sim, const char *msg, const char *val)
164
+{
165
+	c80_reset (sim);
166
+
167
+	return (0);
168
+}
169
+
170
+static
171
+int c80_set_msg_emu_stop (cpm80_t *sim, const char *msg, const char *val)
172
+{
173
+	sim->brk = PCE_BRK_STOP;
174
+
175
+	return (0);
176
+}
177
+
178
+static c80_msg_list_t set_msg_list[] = {
179
+	{ "emu.cpu.speed", c80_set_msg_emu_cpu_speed },
180
+	{ "emu.disk.commit", c80_set_msg_emu_disk_commit },
181
+	{ "emu.disk.eject", c80_set_msg_emu_disk_eject },
182
+	{ "emu.disk.insert", c80_set_msg_emu_disk_insert },
183
+	{ "emu.exit", c80_set_msg_emu_exit },
184
+	{ "emu.reset", c80_set_msg_emu_reset },
185
+	{ "emu.stop", c80_set_msg_emu_stop },
186
+	{ NULL, NULL }
187
+};
188
+
189
+
190
+int c80_set_msg (cpm80_t *sim, const char *msg, const char *val)
191
+{
192
+	c80_msg_list_t *lst;
193
+
194
+	/* a hack, for debugging only */
195
+	if (sim == NULL) {
196
+		sim = par_sim;
197
+	}
198
+
199
+	if (msg == NULL) {
200
+		return (1);
201
+	}
202
+
203
+	if (val == NULL) {
204
+		val = "";
205
+	}
206
+
207
+	lst = set_msg_list;
208
+
209
+	while (lst->msg != NULL) {
210
+		if (msg_is_message (lst->msg, msg)) {
211
+			return (lst->set_msg (sim, msg, val));
212
+		}
213
+
214
+		lst += 1;
215
+	}
216
+
217
+	if (msg_is_prefix ("term", msg)) {
218
+		return (1);
219
+	}
220
+
221
+	pce_log (MSG_INF, "unhandled message (\"%s\", \"%s\")\n", msg, val);
222
+
223
+	return (1);
224
+}

+ 33
- 0
src/arch/cpm80/msg.h View File

@@ -0,0 +1,33 @@
1
+/*****************************************************************************
2
+ * pce                                                                       *
3
+ *****************************************************************************/
4
+
5
+/*****************************************************************************
6
+ * File name:   src/arch/cpm80/msg.h                                         *
7
+ * Created:     2012-11-30 by Hampa Hug <hampa@hampa.ch>                     *
8
+ * Copyright:   (C) 2012-2016 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
+#ifndef PCE_CPM80_MSG_H
24
+#define PCE_CPM80_MSG_H 1
25
+
26
+
27
+#include "cpm80.h"
28
+
29
+
30
+int c80_set_msg (cpm80_t *sim, const char *msg, const char *val);
31
+
32
+
33
+#endif

+ 57
- 0
src/arch/cpm80/pce-cpm80.cfg.in View File

@@ -0,0 +1,57 @@
1
+# pce-cpm80.cfg
2
+#
3
+# Example config file
4
+
5
+system {
6
+	# The machine model. Valid values are "cpm" and "plain".
7
+	model = "cpm"
8
+
9
+	# The CPU model. Valid values are "8080" and "Z80".
10
+	cpu = "8080"
11
+
12
+	# The CPU clock speed in Hz. Zero means all out.
13
+	#clock = 0
14
+
15
+	# The CPU clock speed in MHz. Zero means all out.
16
+	speed = 0
17
+
18
+	con = "sercon"
19
+	aux = "stdio:file=aux.out:flush=1"
20
+	lst = "stdio:file=lst.out:flush=1"
21
+}
22
+
23
+# Multiple "ram" sections may be present
24
+ram {
25
+	# The base address
26
+	address = 0
27
+
28
+	# The size in bytes
29
+	size = 65536
30
+
31
+	# The RAM image that is used to initialize the RAM
32
+	#file = "cpm80.ram"
33
+}
34
+
35
+# load sections are processed after the emulator is set up.
36
+#load {
37
+#	format = "ihex"
38
+#	file = "cpm80.ihex"
39
+#}
40
+
41
+disk {
42
+	drive    = 0x00
43
+	type     = "auto"
44
+	file     = "fda.img"
45
+	file     = "fda.psi"
46
+	optional = 1
47
+	readonly = 0
48
+}
49
+
50
+disk {
51
+	drive    = 0x01
52
+	type     = "auto"
53
+	file     = "fdb.img"
54
+	file     = "fdb.psi"
55
+	optional = 1
56
+	readonly = 0
57
+}

Loading…
Cancel
Save