summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2015-07-29 00:05:21 -0700
committerMichael Pavone <pavone@retrodev.com>2015-07-29 00:05:21 -0700
commitee2438c01d298a90d61f2fcde4e0394d51c89088 (patch)
treede4356c634df9a146b7f3486d1000e2ef84208a7
parent7f3358e31c30e519a45258917fc419e57b4ca422 (diff)
Implement a tiny bit of CPM BDOS and add a corresponding Z80 core driver so that simple CPM programs like ZEXDOC/ZEXALL can be run against my Z80 core
-rw-r--r--Makefile3
-rw-r--r--blastcpm.c112
-rw-r--r--fake_cpm.sz8105
3 files changed, 220 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 873ea0c..6c4e1a7 100644
--- a/Makefile
+++ b/Makefile
@@ -164,6 +164,9 @@ stateview$(EXE) : stateview.o vdp.o render_sdl.o $(CONFIGOBJS) gst.o
vgmplay$(EXE) : vgmplay.o render_sdl.o $(CONFIGOBJS) $(AUDIOOBJS)
$(CC) -o $@ $^ $(LDFLAGS)
$(FIXUP) ./$@
+
+blastcpm : blastcpm.o util.o $(Z80OBJS) $(TRANSOBJS)
+ $(CC) -o $@ $^
test : test.o vdp.o
$(CC) -o test test.o vdp.o
diff --git a/blastcpm.c b/blastcpm.c
new file mode 100644
index 0000000..d964d70
--- /dev/null
+++ b/blastcpm.c
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/select.h>
+
+#include "z80_to_x86.h"
+#include "util.h"
+
+uint8_t ram[64 * 1024];
+
+#define START_OFF 0x100
+#define OS_START 0xE400
+#define OS_RESET 0xE403
+int headless = 1;
+
+void z80_next_int_pulse(z80_context * context)
+{
+ context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER;
+}
+
+void render_errorbox(char *title, char *message)
+{
+}
+
+void render_infobox(char *title, char *message)
+{
+}
+
+void *console_write(uint32_t address, void *context, uint8_t value)
+{
+ putchar(value);
+ return context;
+}
+
+uint8_t console_read(uint32_t address, void *context)
+{
+ return getchar();
+}
+
+void *console_flush_write(uint32_t address, void *context, uint8_t value)
+{
+ fflush(stdout);
+ return context;
+}
+
+uint8_t console_status_read(uint32_t address, void *context)
+{
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ FD_SET(fileno(stdin), &read_fds);
+ return select(fileno(stdin)+1, &read_fds, NULL, NULL, &timeout) > 0;
+}
+
+void *exit_write(uint32_t address, void *context, uint8_t value)
+{
+ exit(0);
+ return context;
+}
+
+const memmap_chunk z80_map[] = {
+ { 0x0000, 0x10000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL},
+};
+
+const memmap_chunk io_map[] = {
+ { 0x0, 0x1, 0xFFFF, 0, 0, NULL, NULL, NULL, console_read, console_write},
+ { 0x1, 0x2, 0xFFFF, 0, 0, NULL, NULL, NULL, console_status_read, console_flush_write},
+ { 0x2, 0x3, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, exit_write},
+};
+
+int main(int argc, char **argv)
+{
+ FILE *f = fopen("fake_cpm.bin", "rb");
+ long fsize = file_size(f);
+ if (fsize > sizeof(ram) - OS_START) {
+ fsize = sizeof(ram) - OS_START;
+ }
+ if (fread(ram + OS_START, 1, fsize, f) != fsize) {
+ fprintf(stderr, "Error reading from fake_cpm.bin\n");
+ exit(1);
+ }
+ f = fopen(argv[1], "rb");
+ fsize = file_size(f);
+ if (fsize > OS_START - START_OFF) {
+ fsize = OS_START - START_OFF;
+ }
+ if (fread(ram + START_OFF, 1, fsize, f) != fsize) {
+ fprintf(stderr, "Error reading from file %s\n", argv[1]);
+ exit(1);
+ }
+ fclose(f);
+ ram[0] = 0xC3;
+ ram[1] = OS_RESET & 0xFF;
+ ram[2] = OS_RESET >> 8;
+ ram[5] = 0xC3;
+ ram[6] = OS_START & 0xFF;
+ ram[7] = OS_START >> 8;
+
+ z80_options opts;
+ z80_context context;
+ init_z80_opts(&opts, z80_map, 1, io_map, 3, 1);
+ init_z80_context(&context, &opts);
+ for(;;)
+ {
+ z80_run(&context, 1000000);
+ context.current_cycle = 0;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/fake_cpm.sz8 b/fake_cpm.sz8
new file mode 100644
index 0000000..24e32ae
--- /dev/null
+++ b/fake_cpm.sz8
@@ -0,0 +1,105 @@
+CONSOLE_PORT equ 0
+STATUS_PORT equ 1
+EXIT_PORT equ 2
+ org $E400
+ jp handle_call
+ ld a, (should_exit)
+ dec a
+ jr z, do_exit
+ ld a, 1
+ ld (should_exit), a
+ jp $100
+do_exit:
+no_impl
+ out (EXIT_PORT), a
+should_exit:
+ dc.b 0
+
+console_in:
+ in a, (CONSOLE_PORT)
+ ld l, a
+ ret
+console_out:
+ ld a, e
+ out (CONSOLE_PORT), a
+ ret
+get_iobyte:
+ ld a, (3)
+ ld l, a
+ ret
+set_iobyte:
+ ld a, e
+ ld (3), a
+ ret
+write_string:
+ ld c, '$'
+ jp .start
+.continue
+ out (CONSOLE_PORT), a
+ inc de
+.start
+ ld a, (de)
+ cp c
+ jr nz, .continue
+ ;flush output
+ out (STATUS_PORT),a
+ ret
+read_string:
+ ld a, (de)
+ ld c, a
+ ld b, $A ;newline
+ inc c
+ inc de
+ push de
+ inc de
+ jp .start
+.continue
+ in a, (CONSOLE_PORT)
+ cp b
+ jr z, .end
+ ld (de), a
+ inc de
+.start
+ dec c
+ jr nz, .continue
+ ;todo: consume excess characters
+.end
+ pop hl
+ ex de, hl
+ sbc hl, de
+ ld a, l
+ ld (de), a
+ ret
+
+console_status:
+ in a, (STATUS_PORT)
+ ld l, a
+ ret
+
+handle_call:
+ ld a, c
+ or a
+ jr z, do_exit
+ dec a
+ jr z, console_in
+ dec a
+ jr z, console_out
+ dec a
+ jr z, no_impl ;aux reader input
+ dec a
+ jr z, no_impl ;aux punch output
+ dec a
+ jr z, no_impl ;printer output
+ dec a
+ jr z, no_impl ;direct console IO
+ dec a
+ jr z, get_iobyte
+ dec a
+ jr z, set_iobyte
+ dec a
+ jr z, write_string
+ dec a
+ jr z, read_string
+ dec a
+ jr z, console_status
+ jp no_impl \ No newline at end of file