Mercurial > repos > simple16
diff src/vdp.c @ 43:6e7bfe83d2b0
Changed the design to vastly simplify the video hardware and support a 23-bit address space on the CPU
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 27 Aug 2016 22:38:31 -0700 |
parents | 083347ccd508 |
children |
line wrap: on
line diff
--- a/src/vdp.c Mon Apr 11 23:35:51 2016 -0700 +++ b/src/vdp.c Sat Aug 27 22:38:31 2016 -0700 @@ -4,225 +4,105 @@ #include "vdp.h" #include "system.h" +#define MAX_ACTIVE_LINES 240 +#define TOTAL_LINES 262 +#define ACTIVE_WIDTH 320 +#define TOTAL_WIDTH 416 + +#define VDP_STATUS_FB_SELECT 1 +#define VDP_STATUS_PENDING_VINT 2 +#define VDP_STATUS_VBLANK 4 +#define VDP_STATUS_CRAM_PENDING 8 +#define VDP_STATUS_VINT_ENABLED 0x2000 +#define VDP_STATUS_DEPTH 0x4000 +#define VDP_STATUS_ENABLED 0x8000 + 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) { + uint8_t *current_fb = context->status & VDP_STATUS_FB_SELECT ? context->vram + 64*1024 : context->vram; + while (context->cycles < target) { context->hcounter+=2; - if (context->hcounter == 416) { + if (context->hcounter == TOTAL_WIDTH) { context->hcounter = 0; context->vcounter++; - if (context->vcounter == 262) { + if (context->vcounter == TOTAL_LINES) { context->vcounter = 0; } } - context->status &= ~(VDP_STATUS_VRAM|VDP_STATUS_SRAM); - //Render to linebuffer - if ((context->status & VDP_STATUS_ENABLED) && context->vcounter > 15 && context->vcounter < 240 && context->hcounter < 406) { - if (context->hcounter < 246) { - context->status |= VDP_STATUS_VRAM; - if (!context->hcounter) { - //flip linebuffers - if (context->drawbuffer == context->linebuffers) { - context->drawbuffer = context->linebuffers + 328; - context->readbuffer = context->linebuffers; - } else { - context->drawbuffer = context->linebuffers; - context->readbuffer = context->linebuffers + 328; - } - context->draw_dest = 0; - //enable sprite scanning - context->status |= VDP_STATUS_SPRITE_SCAN; - context->current_draw = 0; - } - if (context->draw_counter) { - context->draw_counter--; - uint16_t pixels = context->vram[context->draw_source++]; - for (int i = context->hflip ? 0 : 12; i >= 0 && i < 16; i+= context->hflip ? 4 : -4) - { - uint8_t pixel = ((pixels >> i) & 0xF) | context->palpriority; - context->drawbuffer[context->draw_dest ^ (context->hflip << 2)] = pixel; - context->draw_dest++; - } - } else { - //00VV VVVV VVHH HHHH - uint16_t vpos = (context->vscroll & 0x7FF) + context->vcounter - 16; - uint16_t vmask = (context->vscroll >> 2) & 0x3E00; - uint16_t vcoarse = (vpos << 3) & 0x3FC0; - uint16_t vfine = vpos & 7; - uint16_t hcoarse = ((context->hscroll >> 3) + context->hcounter/6) & 0x3F; - uint16_t tableaddress = hcoarse | (vcoarse & ~vmask) | ((context->vscroll << 3) & vmask); - //printf("VCounter: %X, VScroll: %X, HCounter: %X, Table: %X\n", context->vcounter, context->vscroll, context->hcounter, tableaddress); - uint16_t entry = context->vram[tableaddress]; - context->draw_source = (entry & 0x3FF) * 16; - if (entry & 0x1000) { - context->draw_source += 14 - vfine * 2; - } else { - context->draw_source += vfine * 2; - } - context->palpriority = entry >> 9 & 0x70; - context->draw_counter = 2; - context->hflip = (entry & 0x800) != 0; - } - if (context->status & VDP_STATUS_SPRITE_SCAN) { - context->status |= VDP_STATUS_SRAM; - uint16_t pos = context->sram[context->hcounter]; - uint16_t y = pos & 0xFF; - uint16_t x = pos >> 8; - uint16_t atts = context->sram[context->hcounter+1]; - x |= atts << 2 & 0x100; - if (x | y) { - uint16_t size = atts & 0x400 ? 16 : 8; - if (context->vcounter >= y && context->vcounter < y + size) { - uint16_t address = (atts & 0x3F) * 16; - if (atts & 0x1000) { - address += (size-1) * 2 - (context->vcounter - y) * 2; - } else { - address += (context->vcounter - y) * 2; - } - context->sprite_draws[context->current_draw].source = address; - context->sprite_draws[context->current_draw].x = x; - context->sprite_draws[context->current_draw].hflip = (atts & 0x800) != 0; - context->sprite_draws[context->current_draw].palpriority = 0x80 | (atts >> 9 & 0x50); - context->current_draw++; - if (size == 16) { - context->sprite_draws[context->current_draw].source = address + 32; - context->sprite_draws[context->current_draw].x = x + 8; - context->sprite_draws[context->current_draw].hflip = (atts & 0x800) != 0; - context->sprite_draws[context->current_draw].palpriority = 0x80 | (atts >> 9 & 0x50); - if (context->sprite_draws[context->current_draw].hflip) { - context->sprite_draws[context->current_draw].x -= 8; - context->sprite_draws[context->current_draw-1].x += 8; - } - } - context->current_draw++; - if (context->current_draw == 40) { - //no more rendering capacity - context->status &= ~VDP_STATUS_SPRITE_SCAN; - context->current_draw = 0; - } - } - } else { - //hit sprite list terminator - context->status &= ~VDP_STATUS_SPRITE_SCAN; - context->current_draw = 0; - } - } - } else { - sprite_draw *draw = context->sprite_draws + (context->current_draw >> 1); - if (draw->palpriority) { - context->status |= VDP_STATUS_VRAM; - uint16_t pixels = context->vram[draw->source + (context->current_draw & 1)]; - uint16_t x = draw->x - 16 + (context->hscroll & 7); - for (int i = draw->hflip ? 0 : 12; i >= 0 && i < 16; i+= draw->hflip ? 4 : -4, x++) - { - uint8_t pixel = (pixels >> i) & 0xF; - if (pixel && x < 328 && ((draw->palpriority & 0x40) || !(context->drawbuffer[x] & 0x40))) { - context->drawbuffer[x ^ (draw->hflip << 2)] = pixel | draw->palpriority; - } - } - if (context->current_draw & 1) { - draw->palpriority = 0; - } else { - draw->x += 4; - } - } - context->current_draw++; - } - } //Draw to framebuffer - if (context->vcounter > 8 && context->vcounter < 249 && context->hcounter < 320) { - if (!context->hcounter && context->vcounter == 9) { + if (context->vcounter < MAX_ACTIVE_LINES && context->hcounter < ACTIVE_WIDTH) { + if (!context->framebuffer) { 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); - //clear pending interrupt flag since VBlank is over - context->status &= ~VDP_STATUS_PENDING_VINT; } - 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]]; + uint16_t *dest = context->framebuffer + context->vcounter * context->pitch + context->hcounter; + if ( + context->status & VDP_STATUS_ENABLED + && context->vcounter >= context->top_skip + && context->vcounter < MAX_ACTIVE_LINES - context->bottom_skip + ) { + if (context->status & VDP_STATUS_DEPTH) { + uint16_t offset = context->start_offset + (context->vcounter - context->top_skip) * ACTIVE_WIDTH + context->hcounter; + //8bpp + *(dest++) = context->cram[current_fb[offset++]]; + *dest = context->cram[current_fb[offset]]; + } else { + //4bpp + uint8_t pixels = current_fb[context->start_offset + (context->vcounter - context->top_skip) * ACTIVE_WIDTH + context->hcounter >> 1]; + *(dest++) = context->cram[context->pal_select | pixels >> 4]; + *dest = context->cram[context->pal_select | (pixels & 0xF)]; + } } else { - //Display is disabled or we're in the border area, draw the background color - *dest = *context->cram; - dest++; - *dest = *context->cram; + *(dest++) = context->cram[0]; + *dest = context->cram[0]; } - } else if(!context->hcounter && context->vcounter == 249) { - if (context->status & VDP_STATUS_ENABLED) { - context->status |= VDP_STATUS_PENDING_VINT; - } + } else if (context->framebuffer && context->hcounter < ACTIVE_WIDTH) { 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; + if (!context->hcounter) { + if (context->vcounter == (context->vcounter - context->bottom_skip)) { + context->status |= VDP_STATUS_PENDING_VINT | VDP_STATUS_VBLANK; + } else if (context->vcounter == context->top_skip) { + //clear pending interrupt flag since VBlank is over + context->status &= ~(VDP_STATUS_PENDING_VINT | VDP_STATUS_VBLANK); } } context->cycles += context->clock_inc; } } -void vdp_write_address(vdp *context, uint16_t value) +void vdp_write_mode(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; - } + uint16_t status_bits = VDP_STATUS_ENABLED | VDP_STATUS_DEPTH | VDP_STATUS_VINT_ENABLED | VDP_STATUS_FB_SELECT; + context->status &= ~status_bits; + context->status |= value & status_bits; + context->pal_select = value >> 7 & 0x30; + context->top_skip = value >> 6 & 0x1F; + context->bottom_skip = value >> 1 & 0x1F; } -void vdp_write_data(vdp *context, uint16_t value) +void vdp_write_cram(vdp *context, uint16_t value) { - context->fifo = value; - context->status |= VDP_STATUS_FIFO; -} - -void vdp_write_hscroll(vdp *context, uint16_t value) -{ - context->hscroll = value & 0x1FF; - if (value & 0x8000) { - context->status |= VDP_STATUS_ENABLED; + if (context->status & VDP_STATUS_CRAM_PENDING) { + context->cram[context->pal_write_index++] = value; + if (!(--context->pal_write_count)) { + context->status &= ~VDP_STATUS_CRAM_PENDING; + } } else { - context->status &= ~VDP_STATUS_ENABLED; + context->pal_write_count = value; + context->pal_write_index = value >> 8; + context->status |= VDP_STATUS_CRAM_PENDING; } } @@ -232,11 +112,12 @@ return 0; } else if (context->status & VDP_STATUS_ENABLED) { uint32_t next_line = context->vcounter + 1; - uint32_t next_line_cyc = context->cycles + ((416 - context->hcounter) >> 1) * context->clock_inc; - if (context->vcounter < 249) { - return next_line_cyc + (249 - next_line) * 832; + uint32_t next_line_cyc = context->cycles + ((TOTAL_WIDTH - context->hcounter) >> 1) * context->clock_inc; + uint32_t vint_line = (MAX_ACTIVE_LINES - context->bottom_skip); + if (context->vcounter < vint_line) { + return next_line_cyc + (vint_line - next_line) * (TOTAL_WIDTH >> 1) * context->clock_inc; } else { - return next_line_cyc + (249 + 262 - next_line) * 832; + return next_line_cyc + (vint_line + TOTAL_LINES - next_line) * (TOTAL_WIDTH >> 1) * context->clock_inc; } } else { return 0xFFFFFFFF; @@ -252,3 +133,8 @@ { return (context->status & VDP_STATUS_PENDING_VINT) != 0; } + +uint8_t *vdp_get_back_buffer(vdp *context) +{ + return context->status & VDP_STATUS_FB_SELECT ? context->vram : context->vram + 64*1024; +}