comparison vdp.c @ 487:c08a4efeee7f opengl

Update opengl branch from default. Fix build breakage unrelated to merge
author Mike Pavone <pavone@retrodev.com>
date Sat, 26 Oct 2013 22:38:47 -0700
parents 1f3450d1129f
children 32f053ad9b02 8ac0eb05642c
comparison
equal deleted inserted replaced
449:7696d824489d 487:c08a4efeee7f
1 /*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5 */
1 #include "vdp.h" 6 #include "vdp.h"
2 #include "blastem.h" 7 #include "blastem.h"
3 #include <stdlib.h> 8 #include <stdlib.h>
4 #include <string.h> 9 #include <string.h>
5 #include "render.h" 10 #include "render.h"
10 #define MAP_BIT_PRIORITY 0x8000 15 #define MAP_BIT_PRIORITY 0x8000
11 #define MAP_BIT_H_FLIP 0x800 16 #define MAP_BIT_H_FLIP 0x800
12 #define MAP_BIT_V_FLIP 0x1000 17 #define MAP_BIT_V_FLIP 0x1000
13 18
14 #define SCROLL_BUFFER_SIZE 32 19 #define SCROLL_BUFFER_SIZE 32
15 #define SCROLL_BUFFER_DRAW 16 20 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1)
16 21 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2)
17 #define FIFO_SIZE 4
18 22
19 #define MCLKS_SLOT_H40 16 23 #define MCLKS_SLOT_H40 16
20 #define MCLKS_SLOT_H32 20 24 #define MCLKS_SLOT_H32 20
21 #define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after 25 #define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after
22 #define VINT_CYCLE_H32 ((33+20+7)*MCLKS_SLOT_H32) //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number 26 #define VINT_CYCLE_H32 ((33+20+7)*MCLKS_SLOT_H32) //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number
24 #define MCLK_WEIRD_END (HSYNC_SLOT_H40*MCLKS_SLOT_H40 + 332) 28 #define MCLK_WEIRD_END (HSYNC_SLOT_H40*MCLKS_SLOT_H40 + 332)
25 #define SLOT_WEIRD_END (HSYNC_SLOT_H40+17) 29 #define SLOT_WEIRD_END (HSYNC_SLOT_H40+17)
26 #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) 30 #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32)
27 #define HBLANK_CLEAR_H40 (MCLK_WEIRD_END+61*4) 31 #define HBLANK_CLEAR_H40 (MCLK_WEIRD_END+61*4)
28 #define HBLANK_CLEAR_H32 (HSYNC_END_H32 + 46*5) 32 #define HBLANK_CLEAR_H32 (HSYNC_END_H32 + 46*5)
33 #define FIFO_LATENCY 3
29 34
30 int32_t color_map[1 << 12]; 35 int32_t color_map[1 << 12];
31 uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; 36 uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255};
37
38 uint8_t debug_base[][3] = {
39 {127, 127, 127}, //BG
40 {0, 0, 127}, //A
41 {127, 0, 0}, //Window
42 {0, 127, 0}, //B
43 {127, 0, 127} //Sprites
44 };
32 45
33 uint8_t color_map_init_done; 46 uint8_t color_map_init_done;
34 47
35 void init_vdp_context(vdp_context * context) 48 void init_vdp_context(vdp_context * context)
36 { 49 {
44 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); 57 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
45 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); 58 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
46 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; 59 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE;
47 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; 60 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE;
48 context->sprite_draws = MAX_DRAWS; 61 context->sprite_draws = MAX_DRAWS;
49 context->fifo_cur = malloc(sizeof(fifo_entry) * FIFO_SIZE); 62 context->fifo_write = 0;
50 context->fifo_end = context->fifo_cur + FIFO_SIZE; 63 context->fifo_read = -1;
51 context->b32 = render_depth() == 32; 64 context->b32 = render_depth() == 32;
52 if (!color_map_init_done) { 65 if (!color_map_init_done) {
53 uint8_t b,g,r; 66 uint8_t b,g,r;
54 for (uint16_t color = 0; color < (1 << 12); color++) { 67 for (uint16_t color = 0; color < (1 << 12); color++) {
55 if (color & FBUF_SHADOW) { 68 if (color & FBUF_SHADOW) {
67 } 80 }
68 color_map[color] = render_map_color(r, g, b); 81 color_map[color] = render_map_color(r, g, b);
69 } 82 }
70 color_map_init_done = 1; 83 color_map_init_done = 1;
71 } 84 }
85 for (uint8_t color = 0; color < (1 << (3 + 1 + 1 + 1)); color++)
86 {
87 uint8_t src = color & DBG_SRC_MASK;
88 if (src > DBG_SRC_S) {
89 context->debugcolors[color] = 0;
90 } else {
91 uint8_t r,g,b;
92 b = debug_base[src][0];
93 g = debug_base[src][1];
94 r = debug_base[src][2];
95 if (color & DBG_PRIORITY)
96 {
97 if (b) {
98 b += 48;
99 }
100 if (g) {
101 g += 48;
102 }
103 if (r) {
104 r += 48;
105 }
106 }
107 if (color & DBG_SHADOW) {
108 b /= 2;
109 g /= 2;
110 r /=2 ;
111 }
112 if (color & DBG_HILIGHT) {
113 if (b) {
114 b += 72;
115 }
116 if (g) {
117 g += 72;
118 }
119 if (r) {
120 r += 72;
121 }
122 }
123 context->debugcolors[color] = render_map_color(r, g, b);
124 }
125 }
126 }
127
128 int is_refresh(vdp_context * context, uint32_t slot)
129 {
130 if (context->latched_mode & BIT_H40) {
131 return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210);
132 } else {
133 //TODO: Figure out which slots are refresh when display is off in 32-cell mode
134 //These numbers are guesses based on H40 numbers
135 return (slot == 24 || slot == 56 || slot == 88 || slot == 120 || slot == 152);
136 //The numbers below are the refresh slots during active display
137 //return (slot == 66 || slot == 98 || slot == 130 || slot == 162);
138 }
72 } 139 }
73 140
74 void render_sprite_cells(vdp_context * context) 141 void render_sprite_cells(vdp_context * context)
75 { 142 {
76 if (context->cur_slot >= context->sprite_draws) { 143 if (context->cur_slot >= context->sprite_draws) {
77 sprite_draw * d = context->sprite_draw_list + context->cur_slot; 144 sprite_draw * d = context->sprite_draw_list + context->cur_slot;
78 145
79 uint16_t dir; 146 uint16_t dir;
80 int16_t x; 147 int16_t x;
81 if (d->h_flip) { 148 if (d->h_flip) {
82 x = d->x_pos + 7; 149 x = d->x_pos + 7;
83 dir = -1; 150 dir = -1;
112 int16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; 179 int16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF;
113 int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF; 180 int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF;
114 uint16_t link = context->vdpmem[address+3] & 0x7F; 181 uint16_t link = context->vdpmem[address+3] & 0x7F;
115 uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3; 182 uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3;
116 uint8_t pri = context->vdpmem[address + 4] >> 7; 183 uint8_t pri = context->vdpmem[address + 4] >> 7;
117 uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; 184 uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
118 //printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern); 185 //printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
119 current_index = link; 186 current_index = link;
120 count++; 187 count++;
121 } while (current_index != 0 && count < 80); 188 } while (current_index != 0 && count < 80);
122 } 189 }
127 printf("**Mode Group**\n" 194 printf("**Mode Group**\n"
128 "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n" 195 "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n"
129 "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" 196 "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n"
130 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" 197 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n"
131 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", 198 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n",
132 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, 199 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0,
133 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", 200 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled",
134 context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", 201 context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled",
135 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, 202 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4,
136 context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full", 203 context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full",
137 hscroll[context->regs[REG_MODE_3] & 0x3], 204 hscroll[context->regs[REG_MODE_3] & 0x3],
138 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled"); 205 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled");
139 printf("\n**Table Group**\n" 206 printf("\n**Table Group**\n"
151 printf("\n**Misc Group**\n" 218 printf("\n**Misc Group**\n"
152 "07: %.2X | Backdrop Color: $%X\n" 219 "07: %.2X | Backdrop Color: $%X\n"
153 "0A: %.2X | H-Int Counter: %u\n" 220 "0A: %.2X | H-Int Counter: %u\n"
154 "0F: %.2X | Auto-increment: $%X\n" 221 "0F: %.2X | Auto-increment: $%X\n"
155 "10: %.2X | Scroll A/B Size: %sx%s\n", 222 "10: %.2X | Scroll A/B Size: %sx%s\n",
156 context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, 223 context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F,
157 context->regs[REG_HINT], context->regs[REG_HINT], 224 context->regs[REG_HINT], context->regs[REG_HINT],
158 context->regs[REG_AUTOINC], context->regs[REG_AUTOINC], 225 context->regs[REG_AUTOINC], context->regs[REG_AUTOINC],
159 context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]); 226 context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]);
160 227 printf("\n**Internal Group**\n"
161 //TODO: Window Group, DMA Group 228 "Address: %X\n"
229 "CD: %X\n"
230 "Pending: %s\n",
231 context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false");
232
233 //TODO: Window Group, DMA Group
162 } 234 }
163 235
164 void scan_sprite_table(uint32_t line, vdp_context * context) 236 void scan_sprite_table(uint32_t line, vdp_context * context)
165 { 237 {
166 if (context->sprite_index && context->slot_counter) { 238 if (context->sprite_index && context->slot_counter) {
238 line++; 310 line++;
239 } 311 }
240 height *= 2; 312 height *= 2;
241 } 313 }
242 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; 314 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4;
243 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; 315 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1];
244 uint8_t pal_priority = (tileinfo >> 9) & 0x70; 316 uint8_t pal_priority = (tileinfo >> 9) & 0x70;
245 uint8_t row; 317 uint8_t row;
246 if (tileinfo & MAP_BIT_V_FLIP) { 318 if (tileinfo & MAP_BIT_V_FLIP) {
247 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; 319 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line;
248 } else { 320 } else {
258 if (x) { 330 if (x) {
259 context->flags |= FLAG_CAN_MASK; 331 context->flags |= FLAG_CAN_MASK;
260 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { 332 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) {
261 context->flags |= FLAG_MASKED; 333 context->flags |= FLAG_MASKED;
262 } 334 }
263 335
264 context->flags &= ~FLAG_DOT_OFLOW; 336 context->flags &= ~FLAG_DOT_OFLOW;
265 int16_t i; 337 int16_t i;
266 if (context->flags & FLAG_MASKED) { 338 if (context->flags & FLAG_MASKED) {
267 for (i=0; i < width && context->sprite_draws; i++) { 339 for (i=0; i < width && context->sprite_draws; i++) {
268 --context->sprite_draws; 340 --context->sprite_draws;
304 context->colors[addr] = color_map[value & 0xEEE]; 376 context->colors[addr] = color_map[value & 0xEEE];
305 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; 377 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW];
306 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; 378 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT];
307 } 379 }
308 380
309 #define VRAM_READ 0 381 #define VRAM_READ 0 //0000
310 #define VRAM_WRITE 1 382 #define VRAM_WRITE 1 //0001
311 #define CRAM_READ 8 383 //2 would trigger register write 0010
312 #define CRAM_WRITE 3 384 #define CRAM_WRITE 3 //0011
313 #define VSRAM_READ 4 385 #define VSRAM_READ 4 //0100
314 #define VSRAM_WRITE 5 386 #define VSRAM_WRITE 5//0101
387 //6 would trigger regsiter write 0110
388 //7 is a mystery
389 #define CRAM_READ 8 //1000
390 //9 is also a mystery //1001
391 //A would trigger register write 1010
392 //B is a mystery 1011
393 #define VRAM_READ8 0xC //1100
394 //D is a mystery 1101
395 //E would trigger register write 1110
396 //F is a mystery 1111
315 #define DMA_START 0x20 397 #define DMA_START 0x20
316 398
317 void external_slot(vdp_context * context) 399 void external_slot(vdp_context * context)
400 {
401 fifo_entry * start = context->fifo + context->fifo_read;
402 /*if (context->flags2 & FLAG2_READ_PENDING) {
403 context->flags2 &= ~FLAG2_READ_PENDING;
404 context->flags |= FLAG_UNUSED_SLOT;
405 return;
406 }*/
407 if (context->fifo_read >= 0 && start->cycle <= context->cycles) {
408 switch (start->cd & 0xF)
409 {
410 case VRAM_WRITE:
411 if (start->partial) {
412 //printf("VRAM Write: %X to %X at %d (line %d, slot %d)\n", start->value, start->address ^ 1, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16);
413 context->vdpmem[start->address ^ 1] = start->partial == 2 ? start->value >> 8 : start->value;
414 } else {
415 //printf("VRAM Write High: %X to %X at %d (line %d, slot %d)\n", start->value >> 8, start->address, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16);
416 context->vdpmem[start->address] = start->value >> 8;
417 start->partial = 1;
418 //skip auto-increment and removal of entry from fifo
419 return;
420 }
421 break;
422 case CRAM_WRITE: {
423 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
424 write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value);
425 break;
426 }
427 case VSRAM_WRITE:
428 if (((start->address/2) & 63) < VSRAM_SIZE) {
429 //printf("VSRAM Write: %X to %X\n", start->value, context->address);
430 context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value;
431 }
432
433 break;
434 }
435 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
436 if (context->fifo_read == context->fifo_write) {
437 context->fifo_read = -1;
438 }
439 } else {
440 context->flags |= FLAG_UNUSED_SLOT;
441 }
442 }
443
444 void run_dma_src(vdp_context * context, uint32_t slot)
318 { 445 {
319 //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode 446 //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode
320 //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations 447 //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations
321 //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy 448 //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy
322 if(context->flags & FLAG_DMA_RUN) { 449 if (context->fifo_write == context->fifo_read) {
323 uint16_t dma_len; 450 return;
324 switch(context->regs[REG_DMASRC_H] & 0xC0) 451 }
325 { 452 fifo_entry * cur = NULL;
326 //68K -> VDP 453 switch(context->regs[REG_DMASRC_H] & 0xC0)
327 case 0: 454 {
328 case 0x40: 455 //68K -> VDP
329 switch(context->dma_cd & 0xF) 456 case 0:
330 { 457 case 0x40:
331 case VRAM_WRITE: 458 if (!slot || !is_refresh(context, slot-1)) {
332 if (context->flags & FLAG_DMA_PROG) { 459 cur = context->fifo + context->fifo_write;
333 context->vdpmem[context->address ^ 1] = context->dma_val; 460 cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
334 context->flags &= ~FLAG_DMA_PROG; 461 cur->address = context->address;
335 } else { 462 cur->value = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]);
336 context->dma_val = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); 463 cur->cd = context->cd;
337 context->vdpmem[context->address] = context->dma_val >> 8; 464 cur->partial = 0;
338 context->flags |= FLAG_DMA_PROG; 465 if (context->fifo_read < 0) {
339 } 466 context->fifo_read = context->fifo_write;
340 break; 467 }
341 case CRAM_WRITE: { 468 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
342 write_cram(context, context->address, read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L])); 469 }
343 //printf("CRAM DMA | %X set to %X from %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->cycles); 470 break;
344 break; 471 //Copy
345 } 472 case 0xC0:
346 case VSRAM_WRITE: 473 if (context->flags & FLAG_UNUSED_SLOT && context->fifo_read < 0) {
347 if (((context->address/2) & 63) < VSRAM_SIZE) { 474 //TODO: Fix this to not use the FIFO at all once read-caching is properly implemented
348 context->vsram[(context->address/2) & 63] = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); 475 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1);
349 } 476 cur = context->fifo + context->fifo_read;
350 break; 477 cur->cycle = context->cycles;
351 } 478 cur->address = context->address;
352 break; 479 cur->partial = 1;
353 //Fill 480 cur->value = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1] | (cur->value & 0xFF00);
354 case 0x80: 481 cur->cd = VRAM_WRITE;
355 switch(context->dma_cd & 0xF) 482 context->flags &= ~FLAG_UNUSED_SLOT;
356 { 483 }
357 case VRAM_WRITE: 484 break;
358 //Charles MacDonald's VDP doc says that the low byte gets written first 485 case 0x80:
359 context->vdpmem[context->address] = context->dma_val; 486 if (context->fifo_read < 0) {
360 context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF); 487 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1);
361 break; 488 cur = context->fifo + context->fifo_read;
362 case CRAM_WRITE: 489 cur->cycle = context->cycles;
363 write_cram(context, context->address, context->dma_val); 490 cur->address = context->address;
364 //printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles); 491 cur->partial = 2;
365 break; 492 }
366 case VSRAM_WRITE: 493 break;
367 if (((context->address/2) & 63) < VSRAM_SIZE) { 494 }
368 context->vsram[(context->address/2) & 63] = context->dma_val; 495
369 } 496 if (cur) {
370 break; 497 context->regs[REG_DMASRC_L] += 1;
371 } 498 if (!context->regs[REG_DMASRC_L]) {
372 break; 499 context->regs[REG_DMASRC_M] += 1;
373 //Copy 500 }
374 case 0xC0: 501 context->address += context->regs[REG_AUTOINC];
375 if (context->flags & FLAG_DMA_PROG) { 502 uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1;
376 switch(context->dma_cd & 0xF) 503 context->regs[REG_DMALEN_H] = dma_len >> 8;
377 { 504 context->regs[REG_DMALEN_L] = dma_len;
378 case VRAM_WRITE: 505 if (!dma_len) {
379 context->vdpmem[context->address] = context->dma_val; 506 //printf("DMA end at cycle %d\n", context->cycles);
380 break; 507 context->flags &= ~FLAG_DMA_RUN;
381 case CRAM_WRITE: { 508 context->cd &= 0xF;
382 write_cram(context, context->address, context->dma_val);
383 //printf("CRAM DMA Copy | %X set to %X from %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->regs[REG_DMASRC_L] & (CRAM_SIZE-1), context->cycles);
384 break;
385 }
386 case VSRAM_WRITE:
387 if (((context->address/2) & 63) < VSRAM_SIZE) {
388 context->vsram[(context->address/2) & 63] = context->dma_val;
389 }
390 break;
391 }
392 context->flags &= ~FLAG_DMA_PROG;
393 } else {
394 //I assume, that DMA copy copies from the same RAM as the destination
395 //but it's possible I'm mistaken
396 switch(context->dma_cd & 0xF)
397 {
398 case VRAM_WRITE:
399 context->dma_val = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]];
400 break;
401 case CRAM_WRITE:
402 context->dma_val = context->cram[context->regs[REG_DMASRC_L] & (CRAM_SIZE-1)];
403 break;
404 case VSRAM_WRITE:
405 if ((context->regs[REG_DMASRC_L] & 63) < VSRAM_SIZE) {
406 context->dma_val = context->vsram[context->regs[REG_DMASRC_L] & 63];
407 } else {
408 context->dma_val = 0;
409 }
410 break;
411 }
412 context->flags |= FLAG_DMA_PROG;
413 }
414 break;
415 }
416 if (!(context->flags & FLAG_DMA_PROG)) {
417 context->address += context->regs[REG_AUTOINC];
418 context->regs[REG_DMASRC_L] += 1;
419 if (!context->regs[REG_DMASRC_L]) {
420 context->regs[REG_DMASRC_M] += 1;
421 }
422 dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1;
423 context->regs[REG_DMALEN_H] = dma_len >> 8;
424 context->regs[REG_DMALEN_L] = dma_len;
425 if (!dma_len) {
426 context->flags &= ~FLAG_DMA_RUN;
427 }
428 }
429 } else {
430 fifo_entry * start = (context->fifo_end - FIFO_SIZE);
431 if (context->fifo_cur != start && start->cycle <= context->cycles) {
432 if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START)) {
433 context->flags |= FLAG_DMA_RUN;
434 context->dma_val = start->value;
435 context->address = start->address; //undo auto-increment
436 context->dma_cd = context->cd;
437 } else {
438 switch (start->cd & 0xF)
439 {
440 case VRAM_WRITE:
441 if (start->partial) {
442 //printf("VRAM Write: %X to %X\n", start->value, context->address ^ 1);
443 context->vdpmem[start->address ^ 1] = start->value;
444 } else {
445 //printf("VRAM Write High: %X to %X\n", start->value >> 8, context->address);
446 context->vdpmem[start->address] = start->value >> 8;
447 start->partial = 1;
448 //skip auto-increment and removal of entry from fifo
449 return;
450 }
451 break;
452 case CRAM_WRITE: {
453 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
454 write_cram(context, start->address, start->value);
455 break;
456 }
457 case VSRAM_WRITE:
458 if (((start->address/2) & 63) < VSRAM_SIZE) {
459 //printf("VSRAM Write: %X to %X\n", start->value, context->address);
460 context->vsram[(start->address/2) & 63] = start->value;
461 }
462 break;
463 }
464 //context->address += context->regs[REG_AUTOINC];
465 }
466 fifo_entry * cur = start+1;
467 if (cur < context->fifo_cur) {
468 memmove(start, cur, sizeof(fifo_entry) * (context->fifo_cur - cur));
469 }
470 context->fifo_cur -= 1;
471 } else {
472 context->flags |= FLAG_UNUSED_SLOT;
473 } 509 }
474 } 510 }
475 } 511 }
476 512
477 #define WINDOW_RIGHT 0x80 513 #define WINDOW_RIGHT 0x80
518 uint16_t line_offset, offset, mask; 554 uint16_t line_offset, offset, mask;
519 if (context->latched_mode & BIT_H40) { 555 if (context->latched_mode & BIT_H40) {
520 address &= 0xF000; 556 address &= 0xF000;
521 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; 557 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF;
522 mask = 0x7F; 558 mask = 0x7F;
523 559
524 } else { 560 } else {
525 address &= 0xF800; 561 address &= 0xF800;
526 line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF; 562 line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF;
527 mask = 0x3F; 563 mask = 0x3F;
528 } 564 }
560 } 596 }
561 if (context->double_res) { 597 if (context->double_res) {
562 vscroll <<= 1; 598 vscroll <<= 1;
563 vscroll |= 1; 599 vscroll |= 1;
564 } 600 }
565 vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? column : 0) + vsram_off] + line); 601 vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? (column-2)&63 : 0) + vsram_off] + line);
566 context->v_offset = vscroll & v_offset_mask; 602 context->v_offset = vscroll & v_offset_mask;
567 //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset); 603 //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset);
568 vscroll >>= vscroll_shift; 604 vscroll >>= vscroll_shift;
569 uint16_t hscroll_mask; 605 uint16_t hscroll_mask;
570 uint16_t v_mul; 606 uint16_t v_mul;
610 void read_map_scroll_b(uint16_t column, uint32_t line, vdp_context * context) 646 void read_map_scroll_b(uint16_t column, uint32_t line, vdp_context * context)
611 { 647 {
612 read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context); 648 read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context);
613 } 649 }
614 650
615 void render_map(uint16_t col, uint8_t * tmp_buf, vdp_context * context) 651 void render_map(uint16_t col, uint8_t * tmp_buf, uint8_t offset, vdp_context * context)
616 { 652 {
617 uint16_t address; 653 uint16_t address;
618 uint8_t shift, add; 654 uint8_t shift, add;
619 if (context->double_res) { 655 if (context->double_res) {
620 address = ((col & 0x3FF) << 6); 656 address = ((col & 0x3FF) << 6);
631 address += 4 * context->v_offset/*((context->v_offset << shift) + add)*/; 667 address += 4 * context->v_offset/*((context->v_offset << shift) + add)*/;
632 } 668 }
633 uint16_t pal_priority = (col >> 9) & 0x70; 669 uint16_t pal_priority = (col >> 9) & 0x70;
634 int32_t dir; 670 int32_t dir;
635 if (col & MAP_BIT_H_FLIP) { 671 if (col & MAP_BIT_H_FLIP) {
636 tmp_buf += 7; 672 offset += 7;
673 offset &= SCROLL_BUFFER_MASK;
637 dir = -1; 674 dir = -1;
638 } else { 675 } else {
639 dir = 1; 676 dir = 1;
640 } 677 }
641 for (uint32_t i=0; i < 4; i++, address++) 678 for (uint32_t i=0; i < 4; i++, address++)
642 { 679 {
643 *tmp_buf = pal_priority | (context->vdpmem[address] >> 4); 680 tmp_buf[offset] = pal_priority | (context->vdpmem[address] >> 4);
644 tmp_buf += dir; 681 offset += dir;
645 *tmp_buf = pal_priority | (context->vdpmem[address] & 0xF); 682 offset &= SCROLL_BUFFER_MASK;
646 tmp_buf += dir; 683 tmp_buf[offset] = pal_priority | (context->vdpmem[address] & 0xF);
684 offset += dir;
685 offset &= SCROLL_BUFFER_MASK;
647 } 686 }
648 } 687 }
649 688
650 void render_map_1(vdp_context * context) 689 void render_map_1(vdp_context * context)
651 { 690 {
652 render_map(context->col_1, context->tmp_buf_a+SCROLL_BUFFER_DRAW, context); 691 render_map(context->col_1, context->tmp_buf_a, context->buf_a_off, context);
653 } 692 }
654 693
655 void render_map_2(vdp_context * context) 694 void render_map_2(vdp_context * context)
656 { 695 {
657 render_map(context->col_2, context->tmp_buf_a+SCROLL_BUFFER_DRAW+8, context); 696 render_map(context->col_2, context->tmp_buf_a, context->buf_a_off+8, context);
658 } 697 }
659 698
660 void render_map_3(vdp_context * context) 699 void render_map_3(vdp_context * context)
661 { 700 {
662 render_map(context->col_1, context->tmp_buf_b+SCROLL_BUFFER_DRAW, context); 701 render_map(context->col_1, context->tmp_buf_b, context->buf_b_off, context);
663 } 702 }
664 703
665 void render_map_output(uint32_t line, int32_t col, vdp_context * context) 704 void render_map_output(uint32_t line, int32_t col, vdp_context * context)
666 { 705 {
667 if (line >= 240) { 706 if (line >= 240) {
668 return; 707 return;
669 } 708 }
670 render_map(context->col_2, context->tmp_buf_b+SCROLL_BUFFER_DRAW+8, context); 709 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
671 uint16_t *dst; 710 uint16_t *dst;
672 uint32_t *dst32; 711 uint32_t *dst32;
673 uint8_t *sprite_buf, *plane_a, *plane_b; 712 uint8_t *sprite_buf, *plane_a, *plane_b;
713 int plane_a_off, plane_b_off;
674 if (col) 714 if (col)
675 { 715 {
676 col-=2; 716 col-=2;
677 if (context->b32) { 717 if (context->b32) {
678 dst32 = context->framebuf; 718 dst32 = context->framebuf;
680 } else { 720 } else {
681 dst = context->framebuf; 721 dst = context->framebuf;
682 dst += line * 320 + col * 8; 722 dst += line * 320 + col * 8;
683 } 723 }
684 sprite_buf = context->linebuf + col * 8; 724 sprite_buf = context->linebuf + col * 8;
685 uint16_t a_src; 725 uint8_t a_src, src;
686 if (context->flags & FLAG_WINDOW) { 726 if (context->flags & FLAG_WINDOW) {
687 plane_a = context->tmp_buf_a + SCROLL_BUFFER_DRAW; 727 plane_a_off = context->buf_a_off;
688 //a_src = FBUF_SRC_W; 728 a_src = DBG_SRC_W;
689 } else { 729 } else {
690 plane_a = context->tmp_buf_a + SCROLL_BUFFER_DRAW - (context->hscroll_a & 0xF); 730 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF);
691 //a_src = FBUF_SRC_A; 731 a_src = DBG_SRC_A;
692 } 732 }
693 plane_b = context->tmp_buf_b + SCROLL_BUFFER_DRAW - (context->hscroll_b & 0xF); 733 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF);
694 uint16_t src;
695 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); 734 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
696 735
697 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { 736 if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
698 for (int i = 0; i < 16; ++plane_a, ++plane_b, ++sprite_buf, ++i) { 737 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) {
699 uint8_t pixel; 738 uint8_t pixel;
700 739 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK);
740 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK);
741 uint32_t * colors = context->colors;
701 src = 0; 742 src = 0;
702 uint8_t sprite_color = *sprite_buf & 0x3F; 743 uint8_t sprite_color = *sprite_buf & 0x3F;
703 if (sprite_color == 0x3E || sprite_color == 0x3F) { 744 if (sprite_color == 0x3E || sprite_color == 0x3F) {
704 if (sprite_color == 0x3F) { 745 if (sprite_color == 0x3F) {
705 src = CRAM_SIZE;//FBUF_SHADOW; 746 colors += CRAM_SIZE;
747 src = DBG_SHADOW;
706 } else { 748 } else {
707 src = CRAM_SIZE*2;//FBUF_HILIGHT; 749 colors += CRAM_SIZE*2;
750 src = DBG_HILIGHT;
708 } 751 }
709 if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) { 752 if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) {
710 pixel = *plane_a; 753 pixel = *plane_a;
711 //src |= a_src; 754 src |= a_src;
712 } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) { 755 } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) {
713 pixel = *plane_b; 756 pixel = *plane_b;
714 //src |= FBUF_SRC_B; 757 src |= DBG_SRC_B;
715 } else if (*plane_a & 0xF) { 758 } else if (*plane_a & 0xF) {
716 pixel = *plane_a; 759 pixel = *plane_a;
717 //src |= a_src; 760 src |= a_src;
718 } else if (*plane_b & 0xF){ 761 } else if (*plane_b & 0xF){
719 pixel = *plane_b; 762 pixel = *plane_b;
720 //src |= FBUF_SRC_B; 763 src |= DBG_SRC_B;
721 } else { 764 } else {
722 pixel = context->regs[REG_BG_COLOR] & 0x3F; 765 pixel = context->regs[REG_BG_COLOR] & 0x3F;
723 //src |= FBUF_SRC_BG; 766 src |= DBG_SRC_BG;
724 } 767 }
725 } else { 768 } else {
726 if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) { 769 if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) {
727 pixel = *sprite_buf; 770 pixel = *sprite_buf;
728 //src = FBUF_SRC_S; 771 src = DBG_SRC_S;
729 } else if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) { 772 } else if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) {
730 pixel = *plane_a; 773 pixel = *plane_a;
731 //src = a_src; 774 src = a_src;
732 } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) { 775 } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) {
733 pixel = *plane_b; 776 pixel = *plane_b;
734 //src = FBUF_SRC_B; 777 src = DBG_SRC_B;
735 } else { 778 } else {
736 if (!(*plane_a & BUF_BIT_PRIORITY || *plane_a & BUF_BIT_PRIORITY)) { 779 if (!(*plane_a & BUF_BIT_PRIORITY || *plane_a & BUF_BIT_PRIORITY)) {
737 src = CRAM_SIZE;//FBUF_SHADOW; 780 colors += CRAM_SIZE;
781 src = DBG_SHADOW;
738 } 782 }
739 if (*sprite_buf & 0xF) { 783 if (*sprite_buf & 0xF) {
740 pixel = *sprite_buf; 784 pixel = *sprite_buf;
741 if (*sprite_buf & 0xF == 0xE) { 785 if (*sprite_buf & 0xF == 0xE) {
742 src = 0;//FBUF_SRC_S; 786 colors = context->colors;
743 } /*else { 787 src = DBG_SRC_S;
744 src |= FBUF_SRC_S; 788 } else {
745 }*/ 789 src |= DBG_SRC_S;
790 }
746 } else if (*plane_a & 0xF) { 791 } else if (*plane_a & 0xF) {
747 pixel = *plane_a; 792 pixel = *plane_a;
748 //src |= a_src; 793 src |= a_src;
749 } else if (*plane_b & 0xF){ 794 } else if (*plane_b & 0xF){
750 pixel = *plane_b; 795 pixel = *plane_b;
751 //src |= FBUF_SRC_B; 796 src |= DBG_SRC_B;
752 } else { 797 } else {
753 pixel = context->regs[REG_BG_COLOR] & 0x3F; 798 pixel = context->regs[REG_BG_COLOR] & 0x3F;
754 //src |= FBUF_SRC_BG; 799 src |= DBG_SRC_BG;
755 } 800 }
756 } 801 }
757 } 802 }
758 pixel &= 0x3F; 803 pixel &= 0x3F;
759 pixel += src; 804 uint32_t outpixel;
805 if (context->debug) {
806 outpixel = context->debugcolors[src];
807 } else {
808 outpixel = colors[pixel];
809 }
760 if (context->b32) { 810 if (context->b32) {
761 *(dst32++) = context->colors[pixel]; 811 *(dst32++) = outpixel;
762 } else { 812 } else {
763 *(dst++) = context->colors[pixel]; 813 *(dst++) = outpixel;
764 } 814 }
765 //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; 815 //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src;
766 } 816 }
767 } else { 817 } else {
768 for (int i = 0; i < 16; ++plane_a, ++plane_b, ++sprite_buf, ++i) { 818 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) {
769 uint8_t pixel; 819 uint8_t pixel;
820 src = 0;
821 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK);
822 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK);
770 if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) { 823 if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) {
771 pixel = *sprite_buf; 824 pixel = *sprite_buf;
772 //src = FBUF_SRC_S; 825 src = DBG_SRC_S;
773 } else if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) { 826 } else if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) {
774 pixel = *plane_a; 827 pixel = *plane_a;
775 //src = a_src; 828 src = a_src;
776 } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) { 829 } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) {
777 pixel = *plane_b; 830 pixel = *plane_b;
778 //src = FBUF_SRC_B; 831 src = DBG_SRC_B;
779 } else if (*sprite_buf & 0xF) { 832 } else if (*sprite_buf & 0xF) {
780 pixel = *sprite_buf; 833 pixel = *sprite_buf;
781 //src = FBUF_SRC_S; 834 src = DBG_SRC_S;
782 } else if (*plane_a & 0xF) { 835 } else if (*plane_a & 0xF) {
783 pixel = *plane_a; 836 pixel = *plane_a;
784 //src = a_src; 837 src = a_src;
785 } else if (*plane_b & 0xF){ 838 } else if (*plane_b & 0xF){
786 pixel = *plane_b; 839 pixel = *plane_b;
787 //src = FBUF_SRC_B; 840 src = DBG_SRC_B;
788 } else { 841 } else {
789 pixel = context->regs[REG_BG_COLOR] & 0x3F; 842 pixel = context->regs[REG_BG_COLOR] & 0x3F;
790 //src = FBUF_SRC_BG; 843 src = DBG_SRC_BG;
844 }
845 uint32_t outpixel;
846 if (context->debug) {
847 outpixel = context->debugcolors[src];
848 } else {
849 outpixel = context->colors[pixel & 0x3F];
791 } 850 }
792 if (context->b32) { 851 if (context->b32) {
793 *(dst32++) = context->colors[pixel & 0x3F]; 852 *(dst32++) = outpixel;
794 } else { 853 } else {
795 *(dst++) = context->colors[pixel & 0x3F]; 854 *(dst++) = outpixel;
796 } 855 }
797 //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; 856 //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src;
798 } 857 }
799 } 858 }
800 } else { 859 } else {
802 //sprite_buf = context->linebuf + col * 8; 861 //sprite_buf = context->linebuf + col * 8;
803 //plane_a = context->tmp_buf_a + 16 - (context->hscroll_a & 0x7); 862 //plane_a = context->tmp_buf_a + 16 - (context->hscroll_a & 0x7);
804 //plane_b = context->tmp_buf_b + 16 - (context->hscroll_b & 0x7); 863 //plane_b = context->tmp_buf_b + 16 - (context->hscroll_b & 0x7);
805 //end = dst + 8; 864 //end = dst + 8;
806 } 865 }
807 866 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
808 uint16_t remaining; 867 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
809 if (!(context->flags & FLAG_WINDOW)) {
810 remaining = context->hscroll_a & 0xF;
811 memcpy(context->tmp_buf_a + SCROLL_BUFFER_DRAW - remaining, context->tmp_buf_a + SCROLL_BUFFER_SIZE - remaining, remaining);
812 }
813 remaining = context->hscroll_b & 0xF;
814 memcpy(context->tmp_buf_b + SCROLL_BUFFER_DRAW - remaining, context->tmp_buf_b + SCROLL_BUFFER_SIZE - remaining, remaining);
815 } 868 }
816 869
817 #define COLUMN_RENDER_BLOCK(column, startcyc) \ 870 #define COLUMN_RENDER_BLOCK(column, startcyc) \
818 case startcyc:\ 871 case startcyc:\
819 read_map_scroll_a(column, line, context);\ 872 read_map_scroll_a(column, line, context);\
1162 void latch_mode(vdp_context * context) 1215 void latch_mode(vdp_context * context)
1163 { 1216 {
1164 context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL); 1217 context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL);
1165 } 1218 }
1166 1219
1167 int is_refresh(vdp_context * context, uint32_t slot)
1168 {
1169 if (context->latched_mode & BIT_H40) {
1170 //TODO: Figure out the exact behavior that reduces DMA slots for direct color DMA demos
1171 return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210 || (slot < 6 && (context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) == CRAM_WRITE)));
1172 } else {
1173 //TODO: Figure out which slots are refresh when display is off in 32-cell mode
1174 //These numbers are guesses based on H40 numbers
1175 return (slot == 24 || slot == 56 || slot == 88 || slot == 120 || slot == 152 || (slot < 5 && (context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) == CRAM_WRITE)));
1176 //The numbers below are the refresh slots during active display
1177 //return (slot == 66 || slot == 98 || slot == 130 || slot == 162);
1178 }
1179 }
1180
1181 void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) 1220 void check_render_bg(vdp_context * context, int32_t line, uint32_t slot)
1182 { 1221 {
1183 if (line > 0) { 1222 if (line > 0) {
1184 line -= 1; 1223 line -= 1;
1185 int starti = -1; 1224 int starti = -1;
1186 if (context->latched_mode & BIT_H40) { 1225 if (context->latched_mode & BIT_H40) {
1187 if (slot >= 50 && slot < 210) { 1226 if (slot >= 55 && slot < 210) {
1188 uint32_t x = (slot-50)*2; 1227 uint32_t x = (slot-55)*2;
1189 starti = line * 320 + x; 1228 starti = line * 320 + x;
1190 } 1229 } else if (slot < 5) {
1191 } else { 1230 uint32_t x = (slot + 155)*2;
1192 if (slot >= 43 && slot < 171) { 1231 starti = (line-1)*320 + x;
1193 uint32_t x = (slot-43)*2; 1232 }
1233 } else {
1234 if (slot >= 48 && slot < 171) {
1235 uint32_t x = (slot-48)*2;
1194 starti = line * 320 + x; 1236 starti = line * 320 + x;
1237 } else if (slot < 5) {
1238 uint32_t x = (slot + 123)*2;
1239 starti = (line-1)*320 + x;
1195 } 1240 }
1196 } 1241 }
1197 if (starti >= 0) { 1242 if (starti >= 0) {
1198 if (context->b32) { 1243 if (context->b32) {
1199 uint32_t color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; 1244 uint32_t color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
1216 1261
1217 void vdp_run_context(vdp_context * context, uint32_t target_cycles) 1262 void vdp_run_context(vdp_context * context, uint32_t target_cycles)
1218 { 1263 {
1219 while(context->cycles < target_cycles) 1264 while(context->cycles < target_cycles)
1220 { 1265 {
1266 context->flags &= ~FLAG_UNUSED_SLOT;
1221 uint32_t line = context->cycles / MCLKS_LINE; 1267 uint32_t line = context->cycles / MCLKS_LINE;
1222 uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; 1268 uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE;
1223 if (!context->cycles) { 1269 if (!context->cycles) {
1224 latch_mode(context); 1270 latch_mode(context);
1225 } 1271 }
1328 inccycles = MCLKS_SLOT_H32; 1374 inccycles = MCLKS_SLOT_H32;
1329 slot = linecyc/MCLKS_SLOT_H32; 1375 slot = linecyc/MCLKS_SLOT_H32;
1330 } 1376 }
1331 if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { 1377 if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) {
1332 //first sort-of active line is treated as 255 internally 1378 //first sort-of active line is treated as 255 internally
1333 //it's used for gathering sprite info for line 1379 //it's used for gathering sprite info for line
1334 line = (line - 1) & 0xFF; 1380 line = (line - 1) & 0xFF;
1335 1381
1336 //Convert to slot number 1382 //Convert to slot number
1337 if (context->latched_mode & BIT_H40){ 1383 if (context->latched_mode & BIT_H40){
1338 vdp_h40(line, slot, context); 1384 vdp_h40(line, slot, context);
1339 } else { 1385 } else {
1340 vdp_h32(line, slot, context); 1386 vdp_h32(line, slot, context);
1345 } 1391 }
1346 if (line < active_lines) { 1392 if (line < active_lines) {
1347 check_render_bg(context, line, slot); 1393 check_render_bg(context, line, slot);
1348 } 1394 }
1349 } 1395 }
1396 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) {
1397 run_dma_src(context, slot);
1398 }
1350 context->cycles += inccycles; 1399 context->cycles += inccycles;
1351 } 1400 }
1352 } 1401 }
1353 1402
1354 uint32_t vdp_run_to_vblank(vdp_context * context) 1403 uint32_t vdp_run_to_vblank(vdp_context * context)
1384 } 1433 }
1385 } 1434 }
1386 1435
1387 int vdp_control_port_write(vdp_context * context, uint16_t value) 1436 int vdp_control_port_write(vdp_context * context, uint16_t value)
1388 { 1437 {
1389 //printf("control port write: %X\n", value); 1438 //printf("control port write: %X at %d\n", value, context->cycles);
1390 if (context->flags & FLAG_DMA_RUN) { 1439 if (context->flags & FLAG_DMA_RUN) {
1391 return -1; 1440 return -1;
1392 } 1441 }
1393 if (context->flags & FLAG_PENDING) { 1442 if (context->flags & FLAG_PENDING) {
1394 context->address = (context->address & 0x3FFF) | (value << 14); 1443 context->address = (context->address & 0x3FFF) | (value << 14);
1399 // 1448 //
1400 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { 1449 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) {
1401 //DMA copy or 68K -> VDP, transfer starts immediately 1450 //DMA copy or 68K -> VDP, transfer starts immediately
1402 context->flags |= FLAG_DMA_RUN; 1451 context->flags |= FLAG_DMA_RUN;
1403 context->dma_cd = context->cd; 1452 context->dma_cd = context->cd;
1453 //printf("DMA start at cycle %d\n", context->cycles);
1404 if (!(context->regs[REG_DMASRC_H] & 0x80)) { 1454 if (!(context->regs[REG_DMASRC_H] & 0x80)) {
1405 //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]); 1455 //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]);
1406 return 1; 1456 return 1;
1407 } else { 1457 } else {
1408 //printf("DMA Copy Address: %X, New CD: %X, Source: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); 1458 //printf("DMA Copy Address: %X, New CD: %X, Source: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]);
1413 } 1463 }
1414 } else { 1464 } else {
1415 if ((value & 0xC000) == 0x8000) { 1465 if ((value & 0xC000) == 0x8000) {
1416 //Register write 1466 //Register write
1417 uint8_t reg = (value >> 8) & 0x1F; 1467 uint8_t reg = (value >> 8) & 0x1F;
1418 if (reg < VDP_REGS) { 1468 if (reg < (context->regs[REG_MODE_2] & BIT_MODE_5 ? VDP_REGS : 0xA)) {
1419 //printf("register %d set to %X\n", reg, value & 0xFF); 1469 //printf("register %d set to %X\n", reg, value & 0xFF);
1470 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) {
1471 context->hv_latch = vdp_hv_counter_read(context);
1472 }
1420 context->regs[reg] = value; 1473 context->regs[reg] = value;
1421 if (reg == REG_MODE_2) {
1422 //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled");
1423 }
1424 if (reg == REG_MODE_4) { 1474 if (reg == REG_MODE_4) {
1425 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); 1475 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
1426 if (!context->double_res) { 1476 if (!context->double_res) {
1427 context->framebuf = context->oddbuf; 1477 context->framebuf = context->oddbuf;
1428 } 1478 }
1429 } 1479 }
1480 context->cd &= 0x3C;
1430 } 1481 }
1431 } else { 1482 } else {
1432 context->flags |= FLAG_PENDING; 1483 context->flags |= FLAG_PENDING;
1433 context->address = (context->address &0xC000) | (value & 0x3FFF); 1484 context->address = (context->address &0xC000) | (value & 0x3FFF);
1434 context->cd = (context->cd &0x3C) | (value >> 14); 1485 context->cd = (context->cd &0x3C) | (value >> 14);
1437 return 0; 1488 return 0;
1438 } 1489 }
1439 1490
1440 int vdp_data_port_write(vdp_context * context, uint16_t value) 1491 int vdp_data_port_write(vdp_context * context, uint16_t value)
1441 { 1492 {
1442 //printf("data port write: %X\n", value); 1493 //printf("data port write: %X at %d\n", value, context->cycles);
1443 if (context->flags & FLAG_DMA_RUN) { 1494 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) {
1444 return -1; 1495 return -1;
1445 }
1446 if (!(context->cd & 1)) {
1447 //ignore writes when cd is configured for read
1448 return 0;
1449 } 1496 }
1450 context->flags &= ~FLAG_PENDING; 1497 context->flags &= ~FLAG_PENDING;
1451 /*if (context->fifo_cur == context->fifo_end) { 1498 /*if (context->fifo_cur == context->fifo_end) {
1452 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); 1499 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles);
1453 }*/ 1500 }*/
1454 while (context->fifo_cur == context->fifo_end) { 1501 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) {
1502 context->flags &= ~FLAG_DMA_RUN;
1503 }
1504 while (context->fifo_write == context->fifo_read) {
1455 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); 1505 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20));
1456 } 1506 }
1457 context->fifo_cur->cycle = context->cycles; 1507 fifo_entry * cur = context->fifo + context->fifo_write;
1458 context->fifo_cur->address = context->address; 1508 cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
1459 context->fifo_cur->value = value; 1509 cur->address = context->address;
1460 context->fifo_cur->cd = context->cd; 1510 cur->value = value;
1461 context->fifo_cur->partial = 0; 1511 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) {
1462 context->fifo_cur++; 1512 context->flags |= FLAG_DMA_RUN;
1513 }
1514 cur->cd = context->cd;
1515 cur->partial = 0;
1516 if (context->fifo_read < 0) {
1517 context->fifo_read = context->fifo_write;
1518 }
1519 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
1463 context->address += context->regs[REG_AUTOINC]; 1520 context->address += context->regs[REG_AUTOINC];
1464 return 0; 1521 return 0;
1465 } 1522 }
1466 1523
1524 void vdp_test_port_write(vdp_context * context, uint16_t value)
1525 {
1526 //TODO: implement test register
1527 }
1528
1467 uint16_t vdp_control_port_read(vdp_context * context) 1529 uint16_t vdp_control_port_read(vdp_context * context)
1468 { 1530 {
1469 context->flags &= ~FLAG_PENDING; 1531 context->flags &= ~FLAG_PENDING;
1470 uint16_t value = 0x3400; 1532 uint16_t value = 0x3400;
1471 if (context->fifo_cur == (context->fifo_end - FIFO_SIZE)) { 1533 if (context->fifo_read < 0) {
1472 value |= 0x200; 1534 value |= 0x200;
1473 } 1535 }
1474 if (context->fifo_cur == context->fifo_end) { 1536 if (context->fifo_read == context->fifo_write) {
1475 value |= 0x100; 1537 value |= 0x100;
1476 } 1538 }
1477 if (context->flags2 & FLAG2_VINT_PENDING) { 1539 if (context->flags2 & FLAG2_VINT_PENDING) {
1478 value |= 0x80; 1540 value |= 0x80;
1479 } 1541 }
1480 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { 1542 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) {
1481 value |= 0x10; 1543 value |= 0x10;
1482 } 1544 }
1483 uint32_t line= context->cycles / MCLKS_LINE; 1545 uint32_t line= context->cycles / MCLKS_LINE;
1484 uint32_t linecyc = context->cycles % MCLKS_LINE; 1546 uint32_t linecyc = context->cycles % MCLKS_LINE;
1485 if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE)) { 1547 if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) {
1486 value |= 0x8; 1548 value |= 0x8;
1487 } 1549 }
1488 if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { 1550 if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) {
1489 value |= 0x4; 1551 value |= 0x4;
1490 } 1552 }
1492 value |= 0x2; 1554 value |= 0x2;
1493 } 1555 }
1494 if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify 1556 if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify
1495 value |= 0x1; 1557 value |= 0x1;
1496 } 1558 }
1559 //printf("status read at cycle %d returned %X\n", context->cycles, value);
1497 //TODO: Sprite overflow, sprite collision, odd frame flag 1560 //TODO: Sprite overflow, sprite collision, odd frame flag
1498 return value; 1561 return value;
1499 } 1562 }
1563
1564 #define CRAM_BITS 0xEEE
1565 #define VSRAM_BITS 0x7FF
1566 #define VSRAM_DIRTY_BITS 0xF800
1500 1567
1501 uint16_t vdp_data_port_read(vdp_context * context) 1568 uint16_t vdp_data_port_read(vdp_context * context)
1502 { 1569 {
1503 context->flags &= ~FLAG_PENDING; 1570 context->flags &= ~FLAG_PENDING;
1504 if (context->cd & 1) { 1571 if (context->cd & 1) {
1505 return 0; 1572 return 0;
1506 } 1573 }
1507 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense 1574 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense
1508 context->flags &= ~FLAG_UNUSED_SLOT; 1575 context->flags &= ~FLAG_UNUSED_SLOT;
1576 //context->flags2 |= FLAG2_READ_PENDING;
1509 while (!(context->flags & FLAG_UNUSED_SLOT)) { 1577 while (!(context->flags & FLAG_UNUSED_SLOT)) {
1510 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); 1578 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20));
1511 } 1579 }
1512 uint16_t value = 0; 1580 uint16_t value = 0;
1513 switch (context->cd & 0xF) 1581 switch (context->cd & 0xF)
1514 { 1582 {
1515 case VRAM_READ: 1583 case VRAM_READ:
1516 value = context->vdpmem[context->address] << 8; 1584 value = context->vdpmem[context->address & 0xFFFE] << 8;
1517 context->flags &= ~FLAG_UNUSED_SLOT; 1585 context->flags &= ~FLAG_UNUSED_SLOT;
1586 context->flags2 |= FLAG2_READ_PENDING;
1518 while (!(context->flags & FLAG_UNUSED_SLOT)) { 1587 while (!(context->flags & FLAG_UNUSED_SLOT)) {
1519 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); 1588 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20));
1520 } 1589 }
1521 value |= context->vdpmem[context->address ^ 1]; 1590 value |= context->vdpmem[context->address | 1];
1591 break;
1592 case VRAM_READ8:
1593 value = context->vdpmem[context->address ^ 1];
1594 value |= context->fifo[context->fifo_write].value & 0xFF00;
1522 break; 1595 break;
1523 case CRAM_READ: 1596 case CRAM_READ:
1524 value = context->cram[(context->address/2) & (CRAM_SIZE-1)]; 1597 value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS;
1525 break; 1598 value |= context->fifo[context->fifo_write].value & ~CRAM_BITS;
1526 case VSRAM_READ: 1599 break;
1527 if (((context->address / 2) & 63) < VSRAM_SIZE) { 1600 case VSRAM_READ: {
1528 value = context->vsram[context->address & 63]; 1601 uint16_t address = (context->address /2) & 63;
1529 } 1602 if (address >= VSRAM_SIZE) {
1530 break; 1603 address = 0;
1604 }
1605 value = context->vsram[address] & VSRAM_BITS;
1606 value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS;
1607 break;
1608 }
1531 } 1609 }
1532 context->address += context->regs[REG_AUTOINC]; 1610 context->address += context->regs[REG_AUTOINC];
1533 return value; 1611 return value;
1534 } 1612 }
1535 1613
1536 uint16_t vdp_hv_counter_read(vdp_context * context) 1614 uint16_t vdp_hv_counter_read(vdp_context * context)
1537 { 1615 {
1538 //TODO: deal with clock adjustemnts handled in vdp_run_context 1616 if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) {
1617 return context->hv_latch;
1618 }
1539 uint32_t line= context->cycles / MCLKS_LINE; 1619 uint32_t line= context->cycles / MCLKS_LINE;
1540 if (!line) { 1620 if (!line) {
1541 line = 0xFF; 1621 line = 0xFF;
1542 } else { 1622 } else {
1543 line--; 1623 line--;
1640 } 1720 }
1641 } 1721 }
1642 return (line << 8) | linecyc; 1722 return (line << 8) | linecyc;
1643 } 1723 }
1644 1724
1725 uint16_t vdp_test_port_read(vdp_context * context)
1726 {
1727 //TODO: Find out what actually gets returned here
1728 return 0xFFFF;
1729 }
1730
1645 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) 1731 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
1646 { 1732 {
1647 context->cycles -= deduction; 1733 context->cycles -= deduction;
1648 for(fifo_entry * start = (context->fifo_end - FIFO_SIZE); start < context->fifo_cur; start++) { 1734 if (context->fifo_read >= 0) {
1649 if (start->cycle >= deduction) { 1735 int32_t idx = context->fifo_read;
1650 start->cycle -= deduction; 1736 do {
1651 } else { 1737 if (context->fifo[idx].cycle >= deduction) {
1652 start->cycle = 0; 1738 context->fifo[idx].cycle -= deduction;
1653 } 1739 } else {
1740 context->fifo[idx].cycle = 0;
1741 }
1742 idx = (idx+1) & (FIFO_SIZE-1);
1743 } while(idx != context->fifo_write);
1654 } 1744 }
1655 } 1745 }
1656 1746
1657 uint32_t vdp_next_hint(vdp_context * context) 1747 uint32_t vdp_next_hint(vdp_context * context)
1658 { 1748 {
1715 } else if(int_num ==4) { 1805 } else if(int_num ==4) {
1716 context->flags2 &= ~FLAG2_HINT_PENDING; 1806 context->flags2 &= ~FLAG2_HINT_PENDING;
1717 } 1807 }
1718 } 1808 }
1719 1809
1720 #define GST_VDP_REGS 0xFA
1721 #define GST_VDP_MEM 0x12478
1722
1723 uint8_t vdp_load_gst(vdp_context * context, FILE * state_file)
1724 {
1725 uint8_t tmp_buf[CRAM_SIZE*2];
1726 fseek(state_file, GST_VDP_REGS, SEEK_SET);
1727 if (fread(context->regs, 1, VDP_REGS, state_file) != VDP_REGS) {
1728 fputs("Failed to read VDP registers from savestate\n", stderr);
1729 return 0;
1730 }
1731 context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
1732 if (!context->double_res) {
1733 context->framebuf = context->oddbuf;
1734 }
1735 latch_mode(context);
1736 if (fread(tmp_buf, 1, sizeof(tmp_buf), state_file) != sizeof(tmp_buf)) {
1737 fputs("Failed to read CRAM from savestate\n", stderr);
1738 return 0;
1739 }
1740 for (int i = 0; i < CRAM_SIZE; i++) {
1741 uint16_t value;
1742 context->cram[i] = value = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
1743 context->colors[i] = color_map[value & 0xEEE];
1744 context->colors[i + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW];
1745 context->colors[i + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT];
1746 }
1747 if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) {
1748 fputs("Failed to read VSRAM from savestate\n", stderr);
1749 return 0;
1750 }
1751 for (int i = 0; i < VSRAM_SIZE; i++) {
1752 context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
1753 }
1754 fseek(state_file, GST_VDP_MEM, SEEK_SET);
1755 if (fread(context->vdpmem, 1, VRAM_SIZE, state_file) != VRAM_SIZE) {
1756 fputs("Failed to read VRAM from savestate\n", stderr);
1757 return 0;
1758 }
1759 return 1;
1760 }
1761
1762 void vdp_save_state(vdp_context * context, FILE * outfile)
1763 {
1764 uint8_t tmp_buf[CRAM_SIZE*2];
1765 fseek(outfile, GST_VDP_REGS, SEEK_SET);
1766 fwrite(context->regs, 1, VDP_REGS, outfile);
1767 for (int i = 0; i < CRAM_SIZE; i++) {
1768 tmp_buf[i*2] = context->cram[i];
1769 tmp_buf[i*2+1] = context->cram[i] >> 8;
1770 }
1771 fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile);
1772 for (int i = 0; i < VSRAM_SIZE; i++) {
1773 tmp_buf[i*2] = context->vsram[i];
1774 tmp_buf[i*2+1] = context->vsram[i] >> 8;
1775 }
1776 fwrite(tmp_buf, 2, VSRAM_SIZE, outfile);
1777 fseek(outfile, GST_VDP_MEM, SEEK_SET);
1778 fwrite(context->vdpmem, 1, VRAM_SIZE, outfile);
1779 }
1780