changeset 8:5176efdda5ae

Initial work on VDP emulation
author Michael Pavone <pavone@retrodev.com>
date Sun, 27 Mar 2016 00:24:31 -0700
parents 8f9a05e2e425
children a3f14b00aead
files Makefile src/cpu.h src/main.c src/vdp.c src/vdp.h
diffstat 5 files changed, 192 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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;
--- 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 <stdlib.h>
 #include <string.h>
 #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;
 }
--- /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 <stdint.h>
+#include <string.h>
+#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;
+}
--- /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_