# HG changeset patch # User Michael Pavone # Date 1438153521 25200 # Node ID cf6149b7c6e51ed7913c7473fe6febab8398d350 # Parent ab017fb09e77b344a4077ce8e32ce103255fe550 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 diff -r ab017fb09e77 -r cf6149b7c6e5 Makefile --- a/Makefile Wed Jul 29 00:03:36 2015 -0700 +++ b/Makefile Wed Jul 29 00:05:21 2015 -0700 @@ -164,6 +164,9 @@ 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 -r ab017fb09e77 -r cf6149b7c6e5 blastcpm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/blastcpm.c Wed Jul 29 00:05:21 2015 -0700 @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include + +#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 -r ab017fb09e77 -r cf6149b7c6e5 fake_cpm.sz8 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fake_cpm.sz8 Wed Jul 29 00:05:21 2015 -0700 @@ -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