view src/vdp.c @ 11:04d8efe7a1f0

Initial stab at video output and background color rendering. Fixed address decoding in address port write handler.
author Michael Pavone <pavone@retrodev.com>
date Sun, 27 Mar 2016 17:36:02 -0700
parents 5176efdda5ae
children 04fc17376999
line wrap: on
line source

#include <stdint.h>
#include <string.h>
#include "vdp.h"
#include "system.h"

void vdp_init(vdp *context, uint32_t clock_div)
{
	memset(context, 0, sizeof(vdp));
	//clock div specifies the pixel clock divider
	//but our emulation step is half that fast
	context->clock_inc = clock_div*2;
	context->drawbuffer = context->linebuffers;
	context->readbuffer = context->linebuffers+320;
}

void vdp_run(vdp *context, uint32_t target)
{
	while (context->cycles < target)
	{
		context->hcounter+=2;
		if (context->hcounter == 416) {
			context->hcounter = 0;
			context->vcounter++;
			if (context->vcounter == 262) {
				context->vcounter = 0;
			}
		}
		//TODO: do rendering stuff here
		//Draw to framebuffer
		if (context->vcounter > 8 && context->vcounter < 249 && context->hcounter < 320) {
			if (!context->hcounter && context->vcounter == 9) {
				context->framebuffer = system_get_framebuffer(&context->pitch);
				//pitch is in terms of bytes, but we want it in terms of pixels
				context->pitch /= sizeof(uint16_t);
			}
			uint16_t *dest = context->framebuffer + (context->vcounter - 9) * context->pitch + context->hcounter;
			if (context->status & VDP_STATUS_ENABLED && context->vcounter > 16 && context->vcounter < 241) {
				*dest = context->cram[0x3F & context->readbuffer[context->hcounter]];
				dest++;
				*dest = context->cram[0x3F & context->readbuffer[context->hcounter+1]];
			} else {
				//Display is disabled or we're in the border area, draw the background color
				*dest = *context->cram;
				dest++;
				*dest = *context->cram;
			}
		} else if(!context->hcounter && context->vcounter == 249) {
			system_framebuffer_updated();
			context->framebuffer = NULL;
		}
		//Handle the FIFO
		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;
}