diff src/main.c @ 25:fb14515266f4

Implemented timer and timer interrupts. Added get/setvbr instructions. Fixed assembler bug. Moved mnemonics into a separate source file
author Michael Pavone <pavone@retrodev.com>
date Thu, 31 Mar 2016 23:25:52 -0700
parents 4c9dbfa30a66
children 083347ccd508
line wrap: on
line diff
--- a/src/main.c	Thu Mar 31 00:07:37 2016 -0700
+++ b/src/main.c	Thu Mar 31 23:25:52 2016 -0700
@@ -5,6 +5,7 @@
 #include "cpu.h"
 #include "vdp.h"
 #include "audio.h"
+#include "timer.h"
 #include "system.h"
 
 #define CYCLES_PER_FRAME (832*262)
@@ -34,8 +35,9 @@
 
 typedef struct {
 	cpu   *proc;
+	audio *audio;
+	timer timer;
 	vdp   video;
-	audio *audio;
 } console;
 
 void debug_port_write(cpu *context, uint8_t port, uint16_t value)
@@ -111,6 +113,55 @@
 	audio_write_vol(system->audio, port - PORT_VOLUME_AB, value);
 }
 
+void timer_port_write(cpu *context, uint8_t port, uint16_t value)
+{
+	console *system = context->system;
+	timer_run(&system->timer, context->cycles);
+	timer_write(&system->timer, value);
+	uint32_t next_int = next_interrupt_cycle(context, (~context->pending_interrupts) & 3);
+	if (next_int < context->current_target) {
+		context->current_target = next_int;
+	}
+}
+
+uint32_t next_interrupt_cycle(cpu *context, uint8_t mask)
+{
+	console *system = context->system;
+	uint32_t next = 0xFFFFFFFF;
+	if (mask & 1) {
+		timer_run(&system->timer, context->cycles);
+		next = timer_next_interrupt(&system->timer);
+	}
+	if (mask & 2) {
+		vdp_run(&system->video, context->cycles);
+		//TODO: VBlank interrupt
+	}
+	return next;
+}
+
+uint8_t get_current_interrupts(cpu *context)
+{
+	console *system = context->system;
+	timer_run(&system->timer, context->cycles);
+	uint8_t bits = 0;
+	if (system->timer.pending) {
+		bits |= 1;
+	}
+	vdp_run(&system->video, context->cycles);
+	//TODO: VBlank interrupt
+	return bits;
+}
+
+void ack_interrupt(cpu *context, int which)
+{
+	console *system = context->system;
+	if (which == 0) {
+		timer_run(&system->timer, context->cycles);
+		system->timer.pending = 0;
+	}
+	//TODO: VBlank interrupt
+}
+
 memory_region regions[] = {
 	{rom, 0, sizeof(rom)-1, MEM_READ},
 	{ram, sizeof(rom), sizeof(rom)-1+sizeof(ram), MEM_READ},
@@ -123,9 +174,11 @@
 		run_cpu(context->proc, CYCLES_PER_FRAME);
 		audio_run(context->audio, CYCLES_PER_FRAME);
 		vdp_run(&context->video, CYCLES_PER_FRAME);
+		timer_run(&context->timer, CYCLES_PER_FRAME);
 		context->proc->cycles -= CYCLES_PER_FRAME;
 		context->video.cycles -= CYCLES_PER_FRAME;
 		context->audio->cycles -= CYCLES_PER_FRAME;
+		context->timer.cycles -= CYCLES_PER_FRAME;
 		system_poll_events();
 	}
 }
@@ -150,12 +203,14 @@
 	context.proc = alloc_cpu(10, sizeof(regions)/sizeof(memory_region), regions);
 	context.proc->system = &context;
 	vdp_init(&context.video, 2);
+	timer_init(&context.timer, 16);
 	context.proc->port_handlers[PORT_FREQUENCY_A].write = frequency_port_write;
 	context.proc->port_handlers[PORT_FREQUENCY_B].write = frequency_port_write;
 	context.proc->port_handlers[PORT_FREQUENCY_C].write = frequency_port_write;
 	context.proc->port_handlers[PORT_FREQUENCY_D].write = frequency_port_write;
 	context.proc->port_handlers[PORT_VOLUME_AB].write = volume_port_write;
 	context.proc->port_handlers[PORT_VOLUME_CD].write = volume_port_write;
+	context.proc->port_handlers[PORT_TIMER].write = timer_port_write;
 	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;