Mercurial > repos > blastem
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 |