# HG changeset patch # User Michael Pavone # Date 1459063471 25200 # Node ID 5176efdda5aebc56f814185b88a77e9d5ce174bc # Parent 8f9a05e2e42541e351169207a929fbbfcb9e3412 Initial work on VDP emulation diff -r 8f9a05e2e425 -r 5176efdda5ae Makefile --- a/Makefile Sat Mar 26 23:36:33 2016 -0700 +++ b/Makefile Sun Mar 27 00:24:31 2016 -0700 @@ -12,7 +12,7 @@ clean : rm -f $(TARGETDIR)/*.o $(TARGETDIR)/s16 $(TARGETDIR)/asm -$(TARGETDIR)/s16 : $(TARGETDIR)/main.o $(TARGETDIR)/cpu.o +$(TARGETDIR)/s16 : $(TARGETDIR)/main.o $(TARGETDIR)/cpu.o $(TARGETDIR)/vdp.o $(CC) -o $@ $^ $(LDFLAGS) $(TARGETDIR)/asm : $(TARGETDIR)/asm.o $(TARGETDIR)/cpu.o diff -r 8f9a05e2e425 -r 5176efdda5ae src/cpu.h --- a/src/cpu.h Sat Mar 26 23:36:33 2016 -0700 +++ b/src/cpu.h Sun Mar 27 00:24:31 2016 -0700 @@ -25,6 +25,7 @@ struct cpu { + void *system; uint32_t cycles; uint32_t clock_inc; uint32_t num_mem_regions; diff -r 8f9a05e2e425 -r 5176efdda5ae src/main.c --- a/src/main.c Sat Mar 26 23:36:33 2016 -0700 +++ b/src/main.c Sun Mar 27 00:24:31 2016 -0700 @@ -3,8 +3,9 @@ #include #include #include "cpu.h" +#include "vdp.h" -#define CYCLES_PER_FRAME ((48000*25)/60) +#define CYCLES_PER_FRAME (832*262) uint8_t rom[48 * 1024]; uint8_t ram[16 * 1024]; @@ -22,8 +23,17 @@ PORT_VOLUME_CD, PORT_TIMER, PORT_SERIAL, + PORT_VERTICAL, + PORT_HORIZONTAL, + PORT_VRAM_ADDRESS, + PORT_VRAM_DATA }; +typedef struct { + cpu *proc; + vdp video; +} console; + void debug_port_write(cpu *context, uint8_t port, uint16_t value) { putchar(value); @@ -34,17 +44,68 @@ return getchar(); } +void vertical_port_write(cpu *context, uint8_t port, uint16_t value) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + system->video.vscroll = value; +} + +uint16_t vertical_port_read(cpu *context, uint8_t port) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + return system->video.vcounter; +} + +void horizontal_port_write(cpu *context, uint8_t port, uint16_t value) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + system->video.hscroll = value; +} + +uint16_t horizontal_port_read(cpu *context, uint8_t port) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + return system->video.hcounter; +} + +void address_port_write(cpu *context, uint8_t port, uint16_t value) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + vdp_write_address(&system->video, value); +} + +uint16_t address_port_read(cpu *context, uint8_t port) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + return system->video.status; +} + +void data_port_write(cpu *context, uint8_t port, uint16_t value) +{ + console *system = context->system; + vdp_run(&system->video, context->cycles); + vdp_write_data(&system->video, value); +} + memory_region regions[] = { {rom, 0, sizeof(rom)-1, MEM_READ}, {ram, sizeof(rom), sizeof(rom)-1+sizeof(ram), MEM_READ}, }; -void run_console(cpu *context) +void run_console(console *context) { for(;;) { - run_cpu(context, CYCLES_PER_FRAME); - context->cycles -= CYCLES_PER_FRAME; + run_cpu(context->proc, CYCLES_PER_FRAME); + vdp_run(&context->video, CYCLES_PER_FRAME); + context->proc->cycles -= CYCLES_PER_FRAME; + context->video.cycles -= CYCLES_PER_FRAME; } } @@ -66,9 +127,19 @@ if ((read = fread(rom, 1, sizeof(rom), f)) < sizeof(rom)) { memset(rom + read, 0xFF, sizeof(rom)-read); } - cpu *context = alloc_cpu(1, sizeof(regions)/sizeof(memory_region), regions); - context->port_handlers[PORT_SERIAL].write = debug_port_write; - context->port_handlers[PORT_SERIAL].read = debug_port_read; - run_console(context); + console context; + context.proc = alloc_cpu(10, sizeof(regions)/sizeof(memory_region), regions); + context.proc->system = &context; + vdp_init(&context.video, 2); + context.proc->port_handlers[PORT_SERIAL].write = debug_port_write; + context.proc->port_handlers[PORT_SERIAL].read = debug_port_read; + context.proc->port_handlers[PORT_VERTICAL].write = vertical_port_write; + context.proc->port_handlers[PORT_VERTICAL].read = vertical_port_read; + context.proc->port_handlers[PORT_HORIZONTAL].write = horizontal_port_write; + context.proc->port_handlers[PORT_HORIZONTAL].read = horizontal_port_read; + context.proc->port_handlers[PORT_VRAM_ADDRESS].write = address_port_write; + context.proc->port_handlers[PORT_VRAM_ADDRESS].read = address_port_read; + context.proc->port_handlers[PORT_VRAM_DATA].write = data_port_write; + run_console(&context); return 0; } diff -r 8f9a05e2e425 -r 5176efdda5ae src/vdp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vdp.c Sun Mar 27 00:24:31 2016 -0700 @@ -0,0 +1,70 @@ +#include +#include +#include "vdp.h" + +void vdp_init(vdp *context, uint32_t clock_div) +{ + memset(context, 0, sizeof(vdp)); + context->clock_inc = clock_div; +} + +void vdp_run(vdp *context, uint32_t target) +{ + while (context->cycles < target) + { + context->hcounter++; + if (context->hcounter == 416) { + context->hcounter = 0; + context->vcounter++; + if (context->vcounter == 262) { + context->vcounter = 0; + } + } + //TODO: do rendering stuff here + if (context->status & VDP_STATUS_FIFO) { + switch (context->fifo_dest) + { + case FIFO_DEST_VRAM: + if (!(context->status & VDP_STATUS_VRAM)) { + context->vram[context->dest_offset++] = context->fifo; + context->dest_offset &= sizeof(context->vram)/2-1; + context->status &= ~VDP_STATUS_FIFO; + } + break; + case FIFO_DEST_SRAM: + if (!(context->status & VDP_STATUS_SRAM)) { + context->sram[context->dest_offset++] = context->fifo; + context->dest_offset &= sizeof(context->sram)/2-1; + context->status &= ~VDP_STATUS_FIFO; + } + break; + case FIFO_DEST_CRAM: + context->cram[context->dest_offset++] = context->fifo; + context->dest_offset &= sizeof(context->cram)/2-1; + context->status &= ~VDP_STATUS_FIFO; + break; + } + } + context->cycles += context->clock_inc; + } +} +void vdp_write_address(vdp *context, uint16_t value) +{ + context->status &= ~VDP_STATUS_FIFO; + if (value & 0x8000) { + context->fifo_dest = FIFO_DEST_VRAM; + context->dest_offset = (value & (sizeof(context->vram) -1))/2; + } else if (value & 0xFF00 == 0xFE00) { + context->fifo_dest = FIFO_DEST_SRAM; + context->dest_offset = (value & (sizeof(context->sram) -1))/2; + } else if (value & 0xFF00 == 0xFF00) { + context->fifo_dest = FIFO_DEST_CRAM; + context->dest_offset = (value & (sizeof(context->cram) -1))/2; + } +} + +void vdp_write_data(vdp *context, uint16_t value) +{ + context->fifo = value; + context->status |= VDP_STATUS_FIFO; +} diff -r 8f9a05e2e425 -r 5176efdda5ae src/vdp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vdp.h Sun Mar 27 00:24:31 2016 -0700 @@ -0,0 +1,41 @@ +#ifndef VDP_H_ +#define VDP_H_ + +typedef struct { + uint32_t cycles; + uint32_t clock_inc; + + uint16_t fifo; + uint16_t dest_offset; + uint16_t status; + + uint16_t vcounter; + uint16_t hcounter; + + uint16_t vscroll; + uint16_t hscroll; + + uint16_t vram[32*512]; + uint16_t sram[64*2]; + uint16_t cram[64]; + + uint8_t fifo_dest; +} vdp; + +enum { + FIFO_DEST_INVALID, + FIFO_DEST_VRAM, + FIFO_DEST_SRAM, + FIFO_DEST_CRAM +}; + +#define VDP_STATUS_FIFO 1 +#define VDP_STATUS_VRAM 2 +#define VDP_STATUS_SRAM 4 + +void vdp_init(vdp *context, uint32_t clock_div); +void vdp_run(vdp *context, uint32_t target); +void vdp_write_address(vdp *context, uint16_t value); +void vdp_write_data(vdp *context, uint16_t value); + +#endif //VDP_H_