Mercurial > repos > blastem
comparison vdp.c @ 803:236a184bf6f0
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 26 Jul 2015 16:51:03 -0700 |
parents | 0565b2c1a034 |
children | ac65086c031e |
comparison
equal
deleted
inserted
replaced
802:6811f601008f | 803:236a184bf6f0 |
---|---|
7 #include "blastem.h" | 7 #include "blastem.h" |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 #include <string.h> | 9 #include <string.h> |
10 #include "render.h" | 10 #include "render.h" |
11 | 11 |
12 #define NTSC_ACTIVE 225 | 12 #define NTSC_INACTIVE_START 224 |
13 #define PAL_ACTIVE 241 | 13 #define PAL_INACTIVE_START 240 |
14 #define BUF_BIT_PRIORITY 0x40 | 14 #define BUF_BIT_PRIORITY 0x40 |
15 #define MAP_BIT_PRIORITY 0x8000 | 15 #define MAP_BIT_PRIORITY 0x8000 |
16 #define MAP_BIT_H_FLIP 0x800 | 16 #define MAP_BIT_H_FLIP 0x800 |
17 #define MAP_BIT_V_FLIP 0x1000 | 17 #define MAP_BIT_V_FLIP 0x1000 |
18 | 18 |
20 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) | 20 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) |
21 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) | 21 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) |
22 | 22 |
23 #define MCLKS_SLOT_H40 16 | 23 #define MCLKS_SLOT_H40 16 |
24 #define MCLKS_SLOT_H32 20 | 24 #define MCLKS_SLOT_H32 20 |
25 #define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after | 25 #define VINT_SLOT_H40 4 //21 slots before HSYNC, 16 during, 10 after |
26 #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_SLOT_H32 4 //old value was 23, but recent tests suggest the actual value is close to the H40 one |
27 #define HSYNC_SLOT_H40 21 | 27 #define HSYNC_SLOT_H40 234 |
28 #define MCLK_WEIRD_END (HSYNC_SLOT_H40*MCLKS_SLOT_H40 + 332) | 28 #define HSYNC_END_H40 (HSYNC_SLOT_H40+17) |
29 #define SLOT_WEIRD_END (HSYNC_SLOT_H40+17) | |
30 #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) | 29 #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) |
31 #define HBLANK_CLEAR_H40 (MCLK_WEIRD_END+61*4) | 30 #define HBLANK_START_H40 178 //should be 179 according to Nemesis, but 178 seems to fit slightly better with my test ROM results |
32 #define HBLANK_CLEAR_H32 (HSYNC_END_H32 + 46*5) | 31 #define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results |
32 #define HBLANK_START_H32 233 //should be 147 according to Nemesis which is very different from my test ROM result | |
33 #define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results | |
34 #define LINE_CHANGE_H40 165 | |
35 #define LINE_CHANGE_H32 132 | |
36 #define VBLANK_START_H40 (LINE_CHANGE_H40+2) | |
37 #define VBLANK_START_H32 (LINE_CHANGE_H32+2) | |
33 #define FIFO_LATENCY 3 | 38 #define FIFO_LATENCY 3 |
34 | 39 |
35 int32_t color_map[1 << 12]; | 40 int32_t color_map[1 << 12]; |
36 uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; | 41 uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; |
37 | 42 |
43 {127, 0, 127} //Sprites | 48 {127, 0, 127} //Sprites |
44 }; | 49 }; |
45 | 50 |
46 uint8_t color_map_init_done; | 51 uint8_t color_map_init_done; |
47 | 52 |
48 void init_vdp_context(vdp_context * context) | 53 void init_vdp_context(vdp_context * context, uint8_t region_pal) |
49 { | 54 { |
50 memset(context, 0, sizeof(*context)); | 55 memset(context, 0, sizeof(*context)); |
51 context->vdpmem = malloc(VRAM_SIZE); | 56 context->vdpmem = malloc(VRAM_SIZE); |
52 memset(context->vdpmem, 0, VRAM_SIZE); | 57 memset(context->vdpmem, 0, VRAM_SIZE); |
53 /* | 58 /* |
55 if (headless) { | 60 if (headless) { |
56 context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); | 61 context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); |
57 memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); | 62 memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); |
58 context->evenbuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); | 63 context->evenbuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); |
59 memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); | 64 memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); |
60 context->b32 = 1; | |
61 } else { | 65 } else { |
62 render_alloc_surfaces(context); | 66 render_alloc_surfaces(context); |
63 context->b32 = render_depth() == 32; | |
64 } | 67 } |
65 context->framebuf = context->oddbuf; | 68 context->framebuf = context->oddbuf; |
66 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); | 69 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); |
67 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); | 70 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); |
68 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; | 71 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; |
130 } | 133 } |
131 } | 134 } |
132 context->debugcolors[color] = render_map_color(r, g, b); | 135 context->debugcolors[color] = render_map_color(r, g, b); |
133 } | 136 } |
134 } | 137 } |
138 if (region_pal) { | |
139 context->flags2 |= FLAG2_REGION_PAL; | |
140 } | |
135 } | 141 } |
136 | 142 |
137 int is_refresh(vdp_context * context, uint32_t slot) | 143 int is_refresh(vdp_context * context, uint32_t slot) |
138 { | 144 { |
139 if (context->latched_mode & BIT_H40) { | 145 if (context->regs[REG_MODE_4] & BIT_H40) { |
140 return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210); | 146 return slot == 250 || slot == 26 || slot == 59 || slot == 90 || slot == 122 || slot == 154; |
141 } else { | 147 } else { |
142 //TODO: Figure out which slots are refresh when display is off in 32-cell mode | 148 //TODO: Figure out which slots are refresh when display is off in 32-cell mode |
143 //These numbers are guesses based on H40 numbers | 149 //These numbers are guesses based on H40 numbers |
144 return (slot == 24 || slot == 56 || slot == 88 || slot == 120 || slot == 152); | 150 return slot == 243 || slot == 19 || slot == 51 || slot == 83 || slot == 115; |
145 //The numbers below are the refresh slots during active display | 151 //The numbers below are the refresh slots during active display |
146 //return (slot == 66 || slot == 98 || slot == 130 || slot == 162); | 152 //return (slot == 29 || slot == 61 || slot == 93 || slot == 125); |
147 } | 153 } |
148 } | 154 } |
149 | 155 |
150 void render_sprite_cells(vdp_context * context) | 156 void render_sprite_cells(vdp_context * context) |
151 { | 157 { |
201 current_index = link; | 207 current_index = link; |
202 count++; | 208 count++; |
203 } while (current_index != 0 && count < 80); | 209 } while (current_index != 0 && count < 80); |
204 } | 210 } |
205 | 211 |
206 void vdp_print_reg_explain(vdp_context * context) | |
207 { | |
208 char * hscroll[] = {"full", "7-line", "cell", "line"}; | |
209 printf("**Mode Group**\n" | |
210 "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n" | |
211 "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" | |
212 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" | |
213 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", | |
214 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, | |
215 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", | |
216 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", | |
217 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, | |
218 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", | |
219 hscroll[context->regs[REG_MODE_3] & 0x3], | |
220 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled"); | |
221 printf("\n**Table Group**\n" | |
222 "02: %.2X | Scroll A Name Table: $%.4X\n" | |
223 "03: %.2X | Window Name Table: $%.4X\n" | |
224 "04: %.2X | Scroll B Name Table: $%.4X\n" | |
225 "05: %.2X | Sprite Attribute Table: $%.4X\n" | |
226 "0D: %.2X | HScroll Data Table: $%.4X\n", | |
227 context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10, | |
228 context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10, | |
229 context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13, | |
230 context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3E : 0x3F)) << 9, | |
231 context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x1F) << 10); | |
232 char * sizes[] = {"32", "64", "invalid", "128"}; | |
233 printf("\n**Misc Group**\n" | |
234 "07: %.2X | Backdrop Color: $%X\n" | |
235 "0A: %.2X | H-Int Counter: %u\n" | |
236 "0F: %.2X | Auto-increment: $%X\n" | |
237 "10: %.2X | Scroll A/B Size: %sx%s\n", | |
238 context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR], | |
239 context->regs[REG_HINT], context->regs[REG_HINT], | |
240 context->regs[REG_AUTOINC], context->regs[REG_AUTOINC], | |
241 context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]); | |
242 printf("\n**Internal Group**\n" | |
243 "Address: %X\n" | |
244 "CD: %X\n" | |
245 "Pending: %s\n", | |
246 context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); | |
247 | |
248 //TODO: Window Group, DMA Group | |
249 } | |
250 | |
251 void scan_sprite_table(uint32_t line, vdp_context * context) | |
252 { | |
253 if (context->sprite_index && context->slot_counter) { | |
254 line += 1; | |
255 line &= 0xFF; | |
256 uint16_t ymask, ymin; | |
257 uint8_t height_mult; | |
258 if (context->double_res) { | |
259 line *= 2; | |
260 if (context->framebuf != context->oddbuf) { | |
261 line++; | |
262 } | |
263 ymask = 0x3FF; | |
264 ymin = 256; | |
265 height_mult = 16; | |
266 } else { | |
267 ymask = 0x1FF; | |
268 ymin = 128; | |
269 height_mult = 8; | |
270 } | |
271 context->sprite_index &= 0x7F; | |
272 if (context->latched_mode & BIT_H40) { | |
273 if (context->sprite_index >= MAX_SPRITES_FRAME) { | |
274 context->sprite_index = 0; | |
275 return; | |
276 } | |
277 } else if(context->sprite_index >= MAX_SPRITES_FRAME_H32) { | |
278 context->sprite_index = 0; | |
279 return; | |
280 } | |
281 //TODO: Read from SAT cache rather than from VRAM | |
282 uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9; | |
283 uint16_t address = context->sprite_index * 8 + sat_address; | |
284 line += ymin; | |
285 uint16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & ymask; | |
286 uint8_t height = ((context->vdpmem[address+2] & 0x3) + 1) * height_mult; | |
287 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); | |
288 if (y <= line && line < (y + height)) { | |
289 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); | |
290 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; | |
291 context->sprite_info_list[context->slot_counter].index = context->sprite_index; | |
292 context->sprite_info_list[context->slot_counter].y = y-ymin; | |
293 } | |
294 context->sprite_index = context->vdpmem[address+3] & 0x7F; | |
295 if (context->sprite_index && context->slot_counter) | |
296 { | |
297 address = context->sprite_index * 8 + sat_address; | |
298 y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & ymask; | |
299 height = ((context->vdpmem[address+2] & 0x3) + 1) * height_mult; | |
300 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); | |
301 if (y <= line && line < (y + height)) { | |
302 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); | |
303 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; | |
304 context->sprite_info_list[context->slot_counter].index = context->sprite_index; | |
305 context->sprite_info_list[context->slot_counter].y = y-ymin; | |
306 } | |
307 context->sprite_index = context->vdpmem[address+3] & 0x7F; | |
308 } | |
309 } | |
310 } | |
311 | |
312 void read_sprite_x(uint32_t line, vdp_context * context) | |
313 { | |
314 if (context->cur_slot >= context->slot_counter) { | |
315 if (context->sprite_draws) { | |
316 line += 1; | |
317 line &= 0xFF; | |
318 //in tiles | |
319 uint8_t width = ((context->sprite_info_list[context->cur_slot].size >> 2) & 0x3) + 1; | |
320 //in pixels | |
321 uint8_t height = ((context->sprite_info_list[context->cur_slot].size & 0x3) + 1) * 8; | |
322 if (context->double_res) { | |
323 line *= 2; | |
324 if (context->framebuf != context->oddbuf) { | |
325 line++; | |
326 } | |
327 height *= 2; | |
328 } | |
329 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; | |
330 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; | |
331 uint8_t pal_priority = (tileinfo >> 9) & 0x70; | |
332 uint8_t row; | |
333 if (tileinfo & MAP_BIT_V_FLIP) { | |
334 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; | |
335 } else { | |
336 row = line-context->sprite_info_list[context->cur_slot].y; | |
337 } | |
338 uint16_t address; | |
339 if (context->double_res) { | |
340 address = ((tileinfo & 0x3FF) << 6) + row * 4; | |
341 } else { | |
342 address = ((tileinfo & 0x7FF) << 5) + row * 4; | |
343 } | |
344 int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF; | |
345 if (x) { | |
346 context->flags |= FLAG_CAN_MASK; | |
347 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { | |
348 context->flags |= FLAG_MASKED; | |
349 } | |
350 | |
351 context->flags &= ~FLAG_DOT_OFLOW; | |
352 int16_t i; | |
353 if (context->flags & FLAG_MASKED) { | |
354 for (i=0; i < width && context->sprite_draws; i++) { | |
355 --context->sprite_draws; | |
356 context->sprite_draw_list[context->sprite_draws].x_pos = -128; | |
357 } | |
358 } else { | |
359 x -= 128; | |
360 int16_t base_x = x; | |
361 int16_t dir; | |
362 if (tileinfo & MAP_BIT_H_FLIP) { | |
363 x += (width-1) * 8; | |
364 dir = -8; | |
365 } else { | |
366 dir = 8; | |
367 } | |
368 //printf("Sprite %d | x: %d, y: %d, width: %d, height: %d, pal_priority: %X, row: %d, tile addr: %X\n", context->sprite_info_list[context->cur_slot].index, x, context->sprite_info_list[context->cur_slot].y, width, height, pal_priority, row, address); | |
369 for (i=0; i < width && context->sprite_draws; i++, x += dir) { | |
370 --context->sprite_draws; | |
371 context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4; | |
372 context->sprite_draw_list[context->sprite_draws].x_pos = x; | |
373 context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority; | |
374 context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0; | |
375 } | |
376 } | |
377 if (i < width) { | |
378 context->flags |= FLAG_DOT_OFLOW; | |
379 } | |
380 context->cur_slot--; | |
381 } else { | |
382 context->flags |= FLAG_DOT_OFLOW; | |
383 } | |
384 } | |
385 } | |
386 | |
387 void write_cram(vdp_context * context, uint16_t address, uint16_t value) | |
388 { | |
389 uint16_t addr = (address/2) & (CRAM_SIZE-1); | |
390 context->cram[addr] = value; | |
391 context->colors[addr] = color_map[value & 0xEEE]; | |
392 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; | |
393 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; | |
394 } | |
395 | |
396 #define VRAM_READ 0 //0000 | 212 #define VRAM_READ 0 //0000 |
397 #define VRAM_WRITE 1 //0001 | 213 #define VRAM_WRITE 1 //0001 |
398 //2 would trigger register write 0010 | 214 //2 would trigger register write 0010 |
399 #define CRAM_WRITE 3 //0011 | 215 #define CRAM_WRITE 3 //0011 |
400 #define VSRAM_READ 4 //0100 | 216 #define VSRAM_READ 4 //0100 |
408 #define VRAM_READ8 0xC //1100 | 224 #define VRAM_READ8 0xC //1100 |
409 //D is a mystery 1101 | 225 //D is a mystery 1101 |
410 //E would trigger register write 1110 | 226 //E would trigger register write 1110 |
411 //F is a mystery 1111 | 227 //F is a mystery 1111 |
412 #define DMA_START 0x20 | 228 #define DMA_START 0x20 |
229 | |
230 const char * cd_name(uint8_t cd) | |
231 { | |
232 switch (cd & 0xF) | |
233 { | |
234 case VRAM_READ: | |
235 return "VRAM read"; | |
236 case VRAM_WRITE: | |
237 return "VRAM write"; | |
238 case CRAM_WRITE: | |
239 return "CRAM write"; | |
240 case VSRAM_READ: | |
241 return "VSRAM read"; | |
242 case VSRAM_WRITE: | |
243 return "VSRAM write"; | |
244 case VRAM_READ8: | |
245 return "VRAM read (undocumented 8-bit mode)"; | |
246 default: | |
247 return "invalid"; | |
248 } | |
249 } | |
250 | |
251 void vdp_print_reg_explain(vdp_context * context) | |
252 { | |
253 char * hscroll[] = {"full", "7-line", "cell", "line"}; | |
254 printf("**Mode Group**\n" | |
255 "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n" | |
256 "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" | |
257 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" | |
258 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", | |
259 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", (context->regs[REG_MODE_1] & BIT_PAL_SEL) != 0, | |
260 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", | |
261 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", | |
262 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, | |
263 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", | |
264 hscroll[context->regs[REG_MODE_3] & 0x3], | |
265 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled"); | |
266 printf("\n**Table Group**\n" | |
267 "02: %.2X | Scroll A Name Table: $%.4X\n" | |
268 "03: %.2X | Window Name Table: $%.4X\n" | |
269 "04: %.2X | Scroll B Name Table: $%.4X\n" | |
270 "05: %.2X | Sprite Attribute Table: $%.4X\n" | |
271 "0D: %.2X | HScroll Data Table: $%.4X\n", | |
272 context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10, | |
273 context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10, | |
274 context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13, | |
275 context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x7E : 0x7F)) << 9, | |
276 context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x3F) << 10); | |
277 char * sizes[] = {"32", "64", "invalid", "128"}; | |
278 printf("\n**Misc Group**\n" | |
279 "07: %.2X | Backdrop Color: $%X\n" | |
280 "0A: %.2X | H-Int Counter: %u\n" | |
281 "0F: %.2X | Auto-increment: $%X\n" | |
282 "10: %.2X | Scroll A/B Size: %sx%s\n", | |
283 context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR], | |
284 context->regs[REG_HINT], context->regs[REG_HINT], | |
285 context->regs[REG_AUTOINC], context->regs[REG_AUTOINC], | |
286 context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]); | |
287 char * src_types[] = {"68K", "68K", "Copy", "Fill"}; | |
288 printf("\n**DMA Group**\n" | |
289 "13: %.2X |\n" | |
290 "14: %.2X | DMA Length: $%.4X words\n" | |
291 "15: %.2X |\n" | |
292 "16: %.2X |\n" | |
293 "17: %.2X | DMA Source Address: $%.6X, Type: %s\n", | |
294 context->regs[REG_DMALEN_L], | |
295 context->regs[REG_DMALEN_H], context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L], | |
296 context->regs[REG_DMASRC_L], | |
297 context->regs[REG_DMASRC_M], | |
298 context->regs[REG_DMASRC_H], | |
299 context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L] << 1, | |
300 src_types[context->regs[REG_DMASRC_H] >> 6 & 3]); | |
301 printf("\n**Internal Group**\n" | |
302 "Address: %X\n" | |
303 "CD: %X - %s\n" | |
304 "Pending: %s\n" | |
305 "VCounter: %d\n" | |
306 "HCounter: %d\n", | |
307 context->address, context->cd, cd_name(context->cd), (context->flags & FLAG_PENDING) ? "true" : "false", | |
308 context->vcounter, context->hslot*2); | |
309 | |
310 //TODO: Window Group, DMA Group | |
311 } | |
312 | |
313 void scan_sprite_table(uint32_t line, vdp_context * context) | |
314 { | |
315 if (context->sprite_index && context->slot_counter) { | |
316 line += 1; | |
317 line &= 0xFF; | |
318 uint16_t ymask, ymin; | |
319 uint8_t height_mult; | |
320 if (context->double_res) { | |
321 line *= 2; | |
322 if (context->framebuf != context->oddbuf) { | |
323 line++; | |
324 } | |
325 ymask = 0x3FF; | |
326 ymin = 256; | |
327 height_mult = 16; | |
328 } else { | |
329 ymask = 0x1FF; | |
330 ymin = 128; | |
331 height_mult = 8; | |
332 } | |
333 context->sprite_index &= 0x7F; | |
334 if (context->regs[REG_MODE_4] & BIT_H40) { | |
335 if (context->sprite_index >= MAX_SPRITES_FRAME) { | |
336 context->sprite_index = 0; | |
337 return; | |
338 } | |
339 } else if(context->sprite_index >= MAX_SPRITES_FRAME_H32) { | |
340 context->sprite_index = 0; | |
341 return; | |
342 } | |
343 //TODO: Read from SAT cache rather than from VRAM | |
344 uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9; | |
345 uint16_t address = context->sprite_index * 8 + sat_address; | |
346 line += ymin; | |
347 uint16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & ymask; | |
348 uint8_t height = ((context->vdpmem[address+2] & 0x3) + 1) * height_mult; | |
349 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); | |
350 if (y <= line && line < (y + height)) { | |
351 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); | |
352 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; | |
353 context->sprite_info_list[context->slot_counter].index = context->sprite_index; | |
354 context->sprite_info_list[context->slot_counter].y = y-ymin; | |
355 } | |
356 context->sprite_index = context->vdpmem[address+3] & 0x7F; | |
357 if (context->sprite_index && context->slot_counter) | |
358 { | |
359 address = context->sprite_index * 8 + sat_address; | |
360 y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & ymask; | |
361 height = ((context->vdpmem[address+2] & 0x3) + 1) * height_mult; | |
362 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); | |
363 if (y <= line && line < (y + height)) { | |
364 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); | |
365 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; | |
366 context->sprite_info_list[context->slot_counter].index = context->sprite_index; | |
367 context->sprite_info_list[context->slot_counter].y = y-ymin; | |
368 } | |
369 context->sprite_index = context->vdpmem[address+3] & 0x7F; | |
370 } | |
371 } | |
372 } | |
373 | |
374 void read_sprite_x(uint32_t line, vdp_context * context) | |
375 { | |
376 if (context->cur_slot >= context->slot_counter) { | |
377 if (context->sprite_draws) { | |
378 line += 1; | |
379 line &= 0xFF; | |
380 //in tiles | |
381 uint8_t width = ((context->sprite_info_list[context->cur_slot].size >> 2) & 0x3) + 1; | |
382 //in pixels | |
383 uint8_t height = ((context->sprite_info_list[context->cur_slot].size & 0x3) + 1) * 8; | |
384 if (context->double_res) { | |
385 line *= 2; | |
386 if (context->framebuf != context->oddbuf) { | |
387 line++; | |
388 } | |
389 height *= 2; | |
390 } | |
391 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; | |
392 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; | |
393 uint8_t pal_priority = (tileinfo >> 9) & 0x70; | |
394 uint8_t row; | |
395 if (tileinfo & MAP_BIT_V_FLIP) { | |
396 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; | |
397 } else { | |
398 row = line-context->sprite_info_list[context->cur_slot].y; | |
399 } | |
400 uint16_t address; | |
401 if (context->double_res) { | |
402 address = ((tileinfo & 0x3FF) << 6) + row * 4; | |
403 } else { | |
404 address = ((tileinfo & 0x7FF) << 5) + row * 4; | |
405 } | |
406 int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF; | |
407 if (x) { | |
408 context->flags |= FLAG_CAN_MASK; | |
409 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { | |
410 context->flags |= FLAG_MASKED; | |
411 } | |
412 | |
413 context->flags &= ~FLAG_DOT_OFLOW; | |
414 int16_t i; | |
415 if (context->flags & FLAG_MASKED) { | |
416 for (i=0; i < width && context->sprite_draws; i++) { | |
417 --context->sprite_draws; | |
418 context->sprite_draw_list[context->sprite_draws].x_pos = -128; | |
419 } | |
420 } else { | |
421 x -= 128; | |
422 int16_t base_x = x; | |
423 int16_t dir; | |
424 if (tileinfo & MAP_BIT_H_FLIP) { | |
425 x += (width-1) * 8; | |
426 dir = -8; | |
427 } else { | |
428 dir = 8; | |
429 } | |
430 //printf("Sprite %d | x: %d, y: %d, width: %d, height: %d, pal_priority: %X, row: %d, tile addr: %X\n", context->sprite_info_list[context->cur_slot].index, x, context->sprite_info_list[context->cur_slot].y, width, height, pal_priority, row, address); | |
431 for (i=0; i < width && context->sprite_draws; i++, x += dir) { | |
432 --context->sprite_draws; | |
433 context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4; | |
434 context->sprite_draw_list[context->sprite_draws].x_pos = x; | |
435 context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority; | |
436 context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0; | |
437 } | |
438 } | |
439 if (i < width) { | |
440 context->flags |= FLAG_DOT_OFLOW; | |
441 } | |
442 context->cur_slot--; | |
443 } else { | |
444 context->flags |= FLAG_DOT_OFLOW; | |
445 } | |
446 } | |
447 } | |
448 | |
449 void write_cram(vdp_context * context, uint16_t address, uint16_t value) | |
450 { | |
451 uint16_t addr = (address/2) & (CRAM_SIZE-1); | |
452 context->cram[addr] = value; | |
453 context->colors[addr] = color_map[value & 0xEEE]; | |
454 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; | |
455 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; | |
456 } | |
413 | 457 |
414 void external_slot(vdp_context * context) | 458 void external_slot(vdp_context * context) |
415 { | 459 { |
416 fifo_entry * start = context->fifo + context->fifo_read; | 460 fifo_entry * start = context->fifo + context->fifo_read; |
417 /*if (context->flags2 & FLAG2_READ_PENDING) { | 461 /*if (context->flags2 & FLAG2_READ_PENDING) { |
439 write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value); | 483 write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value); |
440 break; | 484 break; |
441 } | 485 } |
442 case VSRAM_WRITE: | 486 case VSRAM_WRITE: |
443 if (((start->address/2) & 63) < VSRAM_SIZE) { | 487 if (((start->address/2) & 63) < VSRAM_SIZE) { |
444 //printf("VSRAM Write: %X to %X\n", start->value, context->address); | 488 //printf("VSRAM Write: %X to %X @ vcounter: %d, hslot: %d, cycle: %d\n", start->value, context->address, context->vcounter, context->hslot, context->cycles); |
445 context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value; | 489 context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value; |
446 } | 490 } |
447 | 491 |
448 break; | 492 break; |
449 } | 493 } |
470 //68K -> VDP | 514 //68K -> VDP |
471 case 0: | 515 case 0: |
472 case 0x40: | 516 case 0x40: |
473 if (!slot || !is_refresh(context, slot-1)) { | 517 if (!slot || !is_refresh(context, slot-1)) { |
474 cur = context->fifo + context->fifo_write; | 518 cur = context->fifo + context->fifo_write; |
475 cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; | 519 cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; |
476 cur->address = context->address; | 520 cur->address = context->address; |
477 cur->value = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); | 521 cur->value = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); |
478 cur->cd = context->cd; | 522 cur->cd = context->cd; |
479 cur->partial = 0; | 523 cur->partial = 0; |
480 if (context->fifo_read < 0) { | 524 if (context->fifo_read < 0) { |
516 context->address += context->regs[REG_AUTOINC]; | 560 context->address += context->regs[REG_AUTOINC]; |
517 uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; | 561 uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; |
518 context->regs[REG_DMALEN_H] = dma_len >> 8; | 562 context->regs[REG_DMALEN_H] = dma_len >> 8; |
519 context->regs[REG_DMALEN_L] = dma_len; | 563 context->regs[REG_DMALEN_L] = dma_len; |
520 if (!dma_len) { | 564 if (!dma_len) { |
521 //printf("DMA end at cycle %d\n", context->cycles); | 565 //printf("DMA end at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", context->cycles, context->frame, context->vcounter, context->hslot); |
522 context->flags &= ~FLAG_DMA_RUN; | 566 context->flags &= ~FLAG_DMA_RUN; |
523 context->cd &= 0xF; | 567 context->cd &= 0xF; |
524 } | 568 } |
525 } | 569 } |
526 } | 570 } |
565 bottom_line = (context->regs[REG_WINDOW_V] & 0x1F) << window_line_shift; | 609 bottom_line = (context->regs[REG_WINDOW_V] & 0x1F) << window_line_shift; |
566 } | 610 } |
567 if ((column >= left_col && column < right_col) || (line >= top_line && line < bottom_line)) { | 611 if ((column >= left_col && column < right_col) || (line >= top_line && line < bottom_line)) { |
568 uint16_t address = context->regs[REG_WINDOW] << 10; | 612 uint16_t address = context->regs[REG_WINDOW] << 10; |
569 uint16_t line_offset, offset, mask; | 613 uint16_t line_offset, offset, mask; |
570 if (context->latched_mode & BIT_H40) { | 614 if (context->regs[REG_MODE_4] & BIT_H40) { |
571 address &= 0xF000; | 615 address &= 0xF000; |
572 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; | 616 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; |
573 mask = 0x7F; | 617 mask = 0x7F; |
574 | 618 |
575 } else { | 619 } else { |
611 } | 655 } |
612 if (context->double_res) { | 656 if (context->double_res) { |
613 vscroll <<= 1; | 657 vscroll <<= 1; |
614 vscroll |= 1; | 658 vscroll |= 1; |
615 } | 659 } |
616 vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? (column-2)&63 : 0) + vsram_off] + line); | 660 //TODO: Further research on vscroll latch behavior and the "first column bug" |
661 if (!column) { | |
662 if (context->regs[REG_MODE_3] & BIT_VSCROLL) { | |
663 if (context->regs[REG_MODE_4] & BIT_H40) { | |
664 //Based on observed behavior documented by Eke-Eke, I'm guessing the VDP | |
665 //ends up fetching the last value on the VSRAM bus in the H40 case | |
666 //getting the last latched value should be close enough for now | |
667 if (!vsram_off) { | |
668 context->vscroll_latch[0] = context->vscroll_latch[1]; | |
669 } | |
670 } else { | |
671 //supposedly it's always forced to 0 in the H32 case | |
672 context->vscroll_latch[0] = context->vscroll_latch[1] = 0; | |
673 } | |
674 } else { | |
675 context->vscroll_latch[vsram_off] = context->vsram[vsram_off]; | |
676 } | |
677 } else if (context->regs[REG_MODE_3] & BIT_VSCROLL) { | |
678 context->vscroll_latch[vsram_off] = context->vsram[column - 2 + vsram_off]; | |
679 } | |
680 vscroll &= context->vscroll_latch[vsram_off] + line; | |
617 context->v_offset = vscroll & v_offset_mask; | 681 context->v_offset = vscroll & v_offset_mask; |
618 //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); | 682 //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); |
619 vscroll >>= vscroll_shift; | 683 vscroll >>= vscroll_shift; |
620 uint16_t hscroll_mask; | 684 uint16_t hscroll_mask; |
621 uint16_t v_mul; | 685 uint16_t v_mul; |
720 { | 784 { |
721 if (line >= 240) { | 785 if (line >= 240) { |
722 return; | 786 return; |
723 } | 787 } |
724 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); | 788 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); |
725 uint16_t *dst; | 789 uint32_t *dst; |
726 uint32_t *dst32; | |
727 uint8_t *sprite_buf, *plane_a, *plane_b; | 790 uint8_t *sprite_buf, *plane_a, *plane_b; |
728 int plane_a_off, plane_b_off; | 791 int plane_a_off, plane_b_off; |
729 if (col) | 792 if (col) |
730 { | 793 { |
731 col-=2; | 794 col-=2; |
732 if (context->b32) { | 795 dst = context->framebuf; |
733 dst32 = context->framebuf; | 796 dst += line * 320 + col * 8; |
734 dst32 += line * 320 + col * 8; | 797 if (context->debug < 2) { |
735 } else { | 798 sprite_buf = context->linebuf + col * 8; |
736 dst = context->framebuf; | 799 uint8_t a_src, src; |
737 dst += line * 320 + col * 8; | 800 if (context->flags & FLAG_WINDOW) { |
738 } | 801 plane_a_off = context->buf_a_off; |
739 sprite_buf = context->linebuf + col * 8; | 802 a_src = DBG_SRC_W; |
740 uint8_t a_src, src; | 803 } else { |
741 if (context->flags & FLAG_WINDOW) { | 804 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); |
742 plane_a_off = context->buf_a_off; | 805 a_src = DBG_SRC_A; |
743 a_src = DBG_SRC_W; | 806 } |
744 } else { | 807 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); |
745 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); | 808 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); |
746 a_src = DBG_SRC_A; | 809 |
747 } | 810 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { |
748 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); | 811 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { |
749 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); | 812 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); |
750 | 813 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); |
751 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { | 814 uint8_t pixel = context->regs[REG_BG_COLOR]; |
752 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { | 815 uint32_t *colors = context->colors; |
753 uint8_t pixel; | 816 src = DBG_SRC_BG; |
754 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); | 817 if (*plane_b & 0xF) { |
755 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); | 818 pixel = *plane_b; |
756 uint32_t * colors = context->colors; | 819 src = DBG_SRC_B; |
757 src = 0; | 820 } |
758 pixel = context->regs[REG_BG_COLOR]; | 821 uint8_t intensity = *plane_b & BUF_BIT_PRIORITY; |
759 src = DBG_SRC_BG; | 822 if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { |
760 if (*plane_b & 0xF) { | 823 pixel = *plane_a; |
761 pixel = *plane_b; | 824 src = DBG_SRC_A; |
762 src = DBG_SRC_B; | 825 } |
763 } | 826 intensity |= *plane_a & BUF_BIT_PRIORITY; |
764 if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { | 827 if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { |
765 pixel = *plane_a; | 828 if ((*sprite_buf & 0x3F) == 0x3E) { |
766 src = DBG_SRC_A; | 829 intensity += BUF_BIT_PRIORITY; |
767 } | 830 } else if ((*sprite_buf & 0x3F) == 0x3F) { |
768 if (*sprite_buf & 0xF) { | 831 intensity = 0; |
769 uint8_t sprite_color = *sprite_buf & 0x3F; | 832 } else { |
770 if (sprite_color == 0x3E) { | 833 pixel = *sprite_buf; |
834 src = DBG_SRC_S; | |
835 if ((pixel & 0xF) == 0xE) { | |
836 intensity = BUF_BIT_PRIORITY; | |
837 } else { | |
838 intensity |= pixel & BUF_BIT_PRIORITY; | |
839 } | |
840 } | |
841 } | |
842 if (!intensity) { | |
843 src |= DBG_SHADOW; | |
844 colors += CRAM_SIZE; | |
845 } else if (intensity == BUF_BIT_PRIORITY*2) { | |
846 src |= DBG_HILIGHT; | |
771 colors += CRAM_SIZE*2; | 847 colors += CRAM_SIZE*2; |
772 src |= DBG_HILIGHT; | 848 } |
773 } else if (sprite_color == 0x3F) { | 849 |
774 colors += CRAM_SIZE; | 850 uint32_t outpixel; |
775 src |= DBG_SHADOW; | 851 if (context->debug) { |
776 } else if ((*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { | 852 outpixel = context->debugcolors[src]; |
853 } else { | |
854 outpixel = colors[pixel & 0x3F]; | |
855 } | |
856 *(dst++) = outpixel; | |
857 } | |
858 } else { | |
859 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { | |
860 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); | |
861 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); | |
862 uint8_t pixel = context->regs[REG_BG_COLOR]; | |
863 src = DBG_SRC_BG; | |
864 if (*plane_b & 0xF) { | |
865 pixel = *plane_b; | |
866 src = DBG_SRC_B; | |
867 } | |
868 if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { | |
869 pixel = *plane_a; | |
870 src = DBG_SRC_A; | |
871 } | |
872 if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { | |
777 pixel = *sprite_buf; | 873 pixel = *sprite_buf; |
778 src = DBG_SRC_S; | 874 src = DBG_SRC_S; |
779 if ((pixel & 0xF) == 0xE) { | |
780 src |= DBG_SHADOW; | |
781 colors += CRAM_SIZE; | |
782 } | |
783 | |
784 } | 875 } |
785 } else if (!((*plane_a | *plane_b) & BUF_BIT_PRIORITY)) { | 876 uint32_t outpixel; |
786 colors += CRAM_SIZE; | 877 if (context->debug) { |
787 src |= DBG_SHADOW; | 878 outpixel = context->debugcolors[src]; |
788 } | 879 } else { |
789 pixel &= 0x3F; | 880 outpixel = context->colors[pixel & 0x3F]; |
790 uint32_t outpixel; | 881 } |
791 if (context->debug) { | |
792 outpixel = context->debugcolors[src]; | |
793 } else { | |
794 outpixel = colors[pixel]; | |
795 } | |
796 if (context->b32) { | |
797 *(dst32++) = outpixel; | |
798 } else { | |
799 *(dst++) = outpixel; | 882 *(dst++) = outpixel; |
800 } | 883 } |
801 //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; | 884 } |
802 } | 885 } else if (context->debug == 2) { |
803 } else { | 886 if (col < 32) { |
804 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { | 887 *(dst++) = context->colors[col * 2]; |
805 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); | 888 *(dst++) = context->colors[col * 2]; |
806 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); | 889 *(dst++) = context->colors[col * 2]; |
807 uint8_t pixel = context->regs[REG_BG_COLOR]; | 890 *(dst++) = context->colors[col * 2]; |
808 src = DBG_SRC_BG; | 891 *(dst++) = context->colors[col * 2 + 1]; |
809 if (*plane_b & 0xF) { | 892 *(dst++) = context->colors[col * 2 + 1]; |
810 pixel = *plane_b; | 893 *(dst++) = context->colors[col * 2 + 1]; |
811 src = DBG_SRC_B; | 894 *(dst++) = context->colors[col * 2 + 1]; |
812 } | 895 *(dst++) = context->colors[col * 2 + 2]; |
813 if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { | 896 *(dst++) = context->colors[col * 2 + 2]; |
814 pixel = *plane_a; | 897 *(dst++) = context->colors[col * 2 + 2]; |
815 src = DBG_SRC_A; | 898 *(dst++) = context->colors[col * 2 + 2]; |
816 } | 899 *(dst++) = context->colors[col * 2 + 3]; |
817 if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { | 900 *(dst++) = context->colors[col * 2 + 3]; |
818 pixel = *sprite_buf; | 901 *(dst++) = context->colors[col * 2 + 3]; |
819 src = DBG_SRC_S; | 902 *(dst++) = context->colors[col * 2 + 3]; |
820 } | 903 } else if (col == 32 || line >= 192) { |
821 uint32_t outpixel; | 904 for (int32_t i = 0; i < 16; i ++) { |
822 if (context->debug) { | 905 *(dst++) = 0; |
823 outpixel = context->debugcolors[src]; | 906 } |
824 } else { | 907 } else { |
825 outpixel = context->colors[pixel & 0x3F]; | 908 for (int32_t i = 0; i < 16; i ++) { |
826 } | 909 *(dst++) = context->colors[line / 3 + (col - 34) * 0x20]; |
827 if (context->b32) { | 910 } |
828 *(dst32++) = outpixel; | 911 } |
829 } else { | 912 } else { |
830 *(dst++) = outpixel; | 913 uint32_t base = (context->debug - 3) * 0x200; |
831 } | 914 uint32_t cell = base + (line / 8) * (context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32) + col; |
915 uint32_t address = (cell * 32 + (line % 8) * 4) & 0xFFFF; | |
916 for (int32_t i = 0; i < 4; i ++) { | |
917 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)]; | |
918 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)]; | |
919 address++; | |
920 } | |
921 cell++; | |
922 address = (cell * 32 + (line % 8) * 4) & 0xFFFF; | |
923 for (int32_t i = 0; i < 4; i ++) { | |
924 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)]; | |
925 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)]; | |
926 address++; | |
832 } | 927 } |
833 } | 928 } |
834 } | 929 } |
835 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; | 930 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; |
836 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; | 931 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; |
891 { | 986 { |
892 uint16_t address; | 987 uint16_t address; |
893 uint32_t mask; | 988 uint32_t mask; |
894 switch(linecyc) | 989 switch(linecyc) |
895 { | 990 { |
991 case 165: | |
992 case 166: | |
993 external_slot(context); | |
994 break; | |
896 //sprite render to line buffer starts | 995 //sprite render to line buffer starts |
897 case 0: | 996 case 167: |
898 context->cur_slot = MAX_DRAWS-1; | 997 case 168: |
899 memset(context->linebuf, 0, LINEBUF_SIZE); | 998 case 169: |
900 case 1: | 999 case 170: |
901 case 2: | |
902 case 3: | |
903 if (line == 0xFF) { | 1000 if (line == 0xFF) { |
904 external_slot(context); | 1001 external_slot(context); |
905 } else { | 1002 } else { |
906 render_sprite_cells(context); | 1003 render_sprite_cells(context); |
907 } | 1004 } |
908 break; | 1005 break; |
909 //sprite attribute table scan starts | 1006 //sprite attribute table scan starts |
910 case 4: | 1007 case 171: |
911 render_sprite_cells( context); | 1008 render_sprite_cells( context); |
912 context->sprite_index = 0x80; | |
913 context->slot_counter = MAX_SPRITES_LINE; | |
914 scan_sprite_table(line, context); | 1009 scan_sprite_table(line, context); |
915 break; | 1010 break; |
916 case 5: | 1011 case 172: |
917 case 6: | 1012 case 173: |
918 case 7: | 1013 case 174: |
919 case 8: | 1014 case 175: |
920 case 9: | 1015 case 176: |
921 case 10: | 1016 case 177: |
922 case 11: | 1017 case 178: |
923 case 12: | 1018 case 179: |
924 case 13: | 1019 case 180: |
925 case 14: | 1020 case 181: |
926 case 15: | 1021 case 182: |
927 case 16: | 1022 case 229: |
928 case 17: | 1023 case 230: |
929 case 18: | 1024 case 231: |
930 case 19: | 1025 case 232: |
931 case 20: | 1026 case 233: |
932 //!HSYNC asserted | 1027 //!HSYNC asserted |
933 case 21: | 1028 case 234: |
934 case 22: | 1029 case 235: |
935 render_sprite_cells(context); | 1030 render_sprite_cells(context); |
936 scan_sprite_table(line, context); | 1031 scan_sprite_table(line, context); |
937 break; | 1032 break; |
938 case 23: | 1033 case 236: |
939 external_slot(context); | 1034 external_slot(context); |
940 break; | 1035 break; |
941 case 24: | 1036 case 237: |
942 case 25: | 1037 case 238: |
943 case 26: | 1038 case 239: |
944 case 27: | 1039 case 240: |
945 case 28: | 1040 case 241: |
946 case 29: | 1041 case 242: |
947 case 30: | 1042 case 243: |
948 case 31: | 1043 case 244: |
949 case 32: | 1044 case 245: |
950 case 33: | 1045 case 246: |
951 case 34: | 1046 case 247: |
952 render_sprite_cells(context); | 1047 render_sprite_cells(context); |
953 scan_sprite_table(line, context); | 1048 scan_sprite_table(line, context); |
954 break; | 1049 break; |
955 case 35: | 1050 case 248: |
956 address = (context->regs[REG_HSCROLL] & 0x3F) << 10; | 1051 address = (context->regs[REG_HSCROLL] & 0x3F) << 10; |
957 mask = 0; | 1052 mask = 0; |
958 if (context->regs[REG_MODE_3] & 0x2) { | 1053 if (context->regs[REG_MODE_3] & 0x2) { |
959 mask |= 0xF8; | 1054 mask |= 0xF8; |
960 } | 1055 } |
965 address += line * 4; | 1060 address += line * 4; |
966 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; | 1061 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; |
967 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; | 1062 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; |
968 //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); | 1063 //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); |
969 break; | 1064 break; |
970 case 36: | 1065 case 249: |
971 //!HSYNC high | 1066 //!HSYNC high |
972 case 37: | 1067 case 250: |
973 case 38: | 1068 case 251: |
974 case 39: | 1069 case 252: |
975 render_sprite_cells(context); | 1070 render_sprite_cells(context); |
976 scan_sprite_table(line, context); | 1071 scan_sprite_table(line, context); |
977 break; | 1072 break; |
978 case 40: | 1073 case 253: |
979 read_map_scroll_a(0, line, context); | 1074 read_map_scroll_a(0, line, context); |
980 break; | 1075 break; |
981 case 41: | 1076 case 254: |
982 render_sprite_cells(context); | 1077 render_sprite_cells(context); |
983 scan_sprite_table(line, context); | 1078 scan_sprite_table(line, context); |
984 break; | 1079 break; |
985 case 42: | 1080 case 255: |
986 render_map_1(context); | 1081 render_map_1(context); |
987 scan_sprite_table(line, context);//Just a guess | 1082 scan_sprite_table(line, context);//Just a guess |
988 break; | 1083 break; |
989 case 43: | 1084 case 0: |
990 render_map_2(context); | 1085 render_map_2(context); |
991 scan_sprite_table(line, context);//Just a guess | 1086 scan_sprite_table(line, context);//Just a guess |
992 break; | 1087 break; |
993 case 44: | 1088 case 1: |
994 read_map_scroll_b(0, line, context); | 1089 read_map_scroll_b(0, line, context); |
995 break; | 1090 break; |
996 case 45: | 1091 case 2: |
997 render_sprite_cells(context); | 1092 render_sprite_cells(context); |
998 scan_sprite_table(line, context); | 1093 scan_sprite_table(line, context); |
999 break; | 1094 break; |
1000 case 46: | 1095 case 3: |
1001 render_map_3(context); | 1096 render_map_3(context); |
1002 scan_sprite_table(line, context);//Just a guess | 1097 scan_sprite_table(line, context);//Just a guess |
1003 break; | 1098 break; |
1004 case 47: | 1099 case 4: |
1005 render_map_output(line, 0, context); | 1100 render_map_output(line, 0, context); |
1006 scan_sprite_table(line, context);//Just a guess | 1101 scan_sprite_table(line, context);//Just a guess |
1007 //reverse context slot counter so it counts the number of sprite slots | 1102 //reverse context slot counter so it counts the number of sprite slots |
1008 //filled rather than the number of available slots | 1103 //filled rather than the number of available slots |
1009 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; | 1104 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; |
1010 context->cur_slot = MAX_SPRITES_LINE-1; | 1105 context->cur_slot = MAX_SPRITES_LINE-1; |
1011 context->sprite_draws = MAX_DRAWS; | 1106 context->sprite_draws = MAX_DRAWS; |
1012 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); | 1107 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); |
1013 break; | 1108 break; |
1014 COLUMN_RENDER_BLOCK(2, 48) | 1109 COLUMN_RENDER_BLOCK(2, 5) |
1015 COLUMN_RENDER_BLOCK(4, 56) | 1110 COLUMN_RENDER_BLOCK(4, 13) |
1016 COLUMN_RENDER_BLOCK(6, 64) | 1111 COLUMN_RENDER_BLOCK(6, 21) |
1017 COLUMN_RENDER_BLOCK_REFRESH(8, 72) | 1112 COLUMN_RENDER_BLOCK_REFRESH(8, 29) |
1018 COLUMN_RENDER_BLOCK(10, 80) | 1113 COLUMN_RENDER_BLOCK(10, 37) |
1019 COLUMN_RENDER_BLOCK(12, 88) | 1114 COLUMN_RENDER_BLOCK(12, 45) |
1020 COLUMN_RENDER_BLOCK(14, 96) | 1115 COLUMN_RENDER_BLOCK(14, 53) |
1021 COLUMN_RENDER_BLOCK_REFRESH(16, 104) | 1116 COLUMN_RENDER_BLOCK_REFRESH(16, 61) |
1022 COLUMN_RENDER_BLOCK(18, 112) | 1117 COLUMN_RENDER_BLOCK(18, 69) |
1023 COLUMN_RENDER_BLOCK(20, 120) | 1118 COLUMN_RENDER_BLOCK(20, 77) |
1024 COLUMN_RENDER_BLOCK(22, 128) | 1119 COLUMN_RENDER_BLOCK(22, 85) |
1025 COLUMN_RENDER_BLOCK_REFRESH(24, 136) | 1120 COLUMN_RENDER_BLOCK_REFRESH(24, 93) |
1026 COLUMN_RENDER_BLOCK(26, 144) | 1121 COLUMN_RENDER_BLOCK(26, 101) |
1027 COLUMN_RENDER_BLOCK(28, 152) | 1122 COLUMN_RENDER_BLOCK(28, 109) |
1028 COLUMN_RENDER_BLOCK(30, 160) | 1123 COLUMN_RENDER_BLOCK(30, 117) |
1029 COLUMN_RENDER_BLOCK_REFRESH(32, 168) | 1124 COLUMN_RENDER_BLOCK_REFRESH(32, 125) |
1030 COLUMN_RENDER_BLOCK(34, 176) | 1125 COLUMN_RENDER_BLOCK(34, 133) |
1031 COLUMN_RENDER_BLOCK(36, 184) | 1126 COLUMN_RENDER_BLOCK(36, 141) |
1032 COLUMN_RENDER_BLOCK(38, 192) | 1127 COLUMN_RENDER_BLOCK(38, 149) |
1033 COLUMN_RENDER_BLOCK_REFRESH(40, 200) | 1128 COLUMN_RENDER_BLOCK_REFRESH(40, 157) |
1034 case 208: | |
1035 case 209: | |
1036 external_slot(context); | |
1037 break; | |
1038 default: | |
1039 //leftovers from HSYNC clock change nonsense | |
1040 break; | |
1041 } | 1129 } |
1042 } | 1130 } |
1043 | 1131 |
1044 void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) | 1132 void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) |
1045 { | 1133 { |
1046 uint16_t address; | 1134 uint16_t address; |
1047 uint32_t mask; | 1135 uint32_t mask; |
1048 switch(linecyc) | 1136 switch(linecyc) |
1049 { | 1137 { |
1138 case 132: | |
1139 case 133: | |
1140 external_slot(context); | |
1141 break; | |
1050 //sprite render to line buffer starts | 1142 //sprite render to line buffer starts |
1051 case 0: | 1143 case 134: |
1052 context->cur_slot = MAX_DRAWS_H32-1; | 1144 case 135: |
1053 memset(context->linebuf, 0, LINEBUF_SIZE); | 1145 case 136: |
1054 case 1: | 1146 case 137: |
1055 case 2: | |
1056 case 3: | |
1057 if (line == 0xFF) { | 1147 if (line == 0xFF) { |
1058 external_slot(context); | 1148 external_slot(context); |
1059 } else { | 1149 } else { |
1060 render_sprite_cells(context); | 1150 render_sprite_cells(context); |
1061 } | 1151 } |
1062 break; | 1152 break; |
1063 //sprite attribute table scan starts | 1153 //sprite attribute table scan starts |
1064 case 4: | 1154 case 138: |
1065 render_sprite_cells( context); | 1155 render_sprite_cells( context); |
1066 context->sprite_index = 0x80; | |
1067 context->slot_counter = MAX_SPRITES_LINE_H32; | |
1068 scan_sprite_table(line, context); | 1156 scan_sprite_table(line, context); |
1069 break; | 1157 break; |
1070 case 5: | 1158 case 139: |
1071 case 6: | 1159 case 140: |
1072 case 7: | 1160 case 141: |
1073 case 8: | 1161 case 142: |
1074 case 9: | 1162 case 143: |
1075 case 10: | 1163 case 144: |
1076 case 11: | 1164 case 145: |
1077 case 12: | 1165 case 146: |
1078 case 13: | 1166 case 147: |
1079 render_sprite_cells(context); | 1167 render_sprite_cells(context); |
1080 scan_sprite_table(line, context); | 1168 scan_sprite_table(line, context); |
1081 case 14: | 1169 case 233: |
1082 external_slot(context); | 1170 external_slot(context); |
1083 break; | 1171 break; |
1084 case 15: | 1172 case 234: |
1085 case 16: | 1173 case 235: |
1086 case 17: | 1174 case 236: |
1087 case 18: | 1175 case 237: |
1088 case 19: | 1176 case 238: |
1089 //HSYNC start | 1177 //HSYNC start |
1090 case 20: | 1178 case 239: |
1091 case 21: | 1179 case 240: |
1092 case 22: | 1180 case 241: |
1093 case 23: | 1181 case 242: |
1094 case 24: | 1182 case 243: |
1095 case 25: | 1183 case 244: |
1096 case 26: | 1184 case 245: |
1097 render_sprite_cells(context); | 1185 render_sprite_cells(context); |
1098 scan_sprite_table(line, context); | 1186 scan_sprite_table(line, context); |
1099 break; | 1187 break; |
1100 case 27: | 1188 case 246: |
1101 external_slot(context); | 1189 external_slot(context); |
1102 break; | 1190 break; |
1103 case 28: | 1191 case 247: |
1104 address = (context->regs[REG_HSCROLL] & 0x3F) << 10; | 1192 address = (context->regs[REG_HSCROLL] & 0x3F) << 10; |
1105 mask = 0; | 1193 mask = 0; |
1106 if (context->regs[REG_MODE_3] & 0x2) { | 1194 if (context->regs[REG_MODE_3] & 0x2) { |
1107 mask |= 0xF8; | 1195 mask |= 0xF8; |
1108 } | 1196 } |
1113 address += line * 4; | 1201 address += line * 4; |
1114 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; | 1202 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; |
1115 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; | 1203 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; |
1116 //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); | 1204 //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); |
1117 break; | 1205 break; |
1118 case 29: | 1206 case 248: |
1119 case 30: | 1207 case 249: |
1120 case 31: | 1208 case 250: |
1121 case 32: | 1209 case 251: |
1122 render_sprite_cells(context); | 1210 render_sprite_cells(context); |
1123 scan_sprite_table(line, context); | 1211 scan_sprite_table(line, context); |
1124 break; | 1212 break; |
1125 //!HSYNC high | 1213 //!HSYNC high |
1126 case 33: | 1214 case 252: |
1127 read_map_scroll_a(0, line, context); | 1215 read_map_scroll_a(0, line, context); |
1128 break; | 1216 break; |
1129 case 34: | 1217 case 253: |
1130 render_sprite_cells(context); | 1218 render_sprite_cells(context); |
1131 scan_sprite_table(line, context); | 1219 scan_sprite_table(line, context); |
1132 break; | 1220 break; |
1133 case 35: | 1221 case 254: |
1134 render_map_1(context); | 1222 render_map_1(context); |
1135 scan_sprite_table(line, context);//Just a guess | 1223 scan_sprite_table(line, context);//Just a guess |
1136 break; | 1224 break; |
1137 case 36: | 1225 case 255: |
1138 render_map_2(context); | 1226 render_map_2(context); |
1139 scan_sprite_table(line, context);//Just a guess | 1227 scan_sprite_table(line, context);//Just a guess |
1140 break; | 1228 break; |
1141 case 37: | 1229 case 0: |
1142 read_map_scroll_b(0, line, context); | 1230 read_map_scroll_b(0, line, context); |
1143 break; | 1231 break; |
1144 case 38: | 1232 case 1: |
1145 render_sprite_cells(context); | 1233 render_sprite_cells(context); |
1146 scan_sprite_table(line, context); | 1234 scan_sprite_table(line, context); |
1147 break; | 1235 break; |
1148 case 39: | 1236 case 2: |
1149 render_map_3(context); | 1237 render_map_3(context); |
1150 scan_sprite_table(line, context);//Just a guess | 1238 scan_sprite_table(line, context);//Just a guess |
1151 break; | 1239 break; |
1152 case 40: | 1240 case 3: |
1153 render_map_output(line, 0, context); | 1241 render_map_output(line, 0, context); |
1154 scan_sprite_table(line, context);//Just a guess | 1242 scan_sprite_table(line, context);//Just a guess |
1155 //reverse context slot counter so it counts the number of sprite slots | 1243 //reverse context slot counter so it counts the number of sprite slots |
1156 //filled rather than the number of available slots | 1244 //filled rather than the number of available slots |
1157 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; | 1245 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; |
1158 context->cur_slot = MAX_SPRITES_LINE_H32-1; | 1246 context->cur_slot = MAX_SPRITES_LINE_H32-1; |
1159 context->sprite_draws = MAX_DRAWS_H32; | 1247 context->sprite_draws = MAX_DRAWS_H32; |
1160 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); | 1248 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); |
1161 break; | 1249 break; |
1162 COLUMN_RENDER_BLOCK(2, 41) | 1250 COLUMN_RENDER_BLOCK(2, 4) |
1163 COLUMN_RENDER_BLOCK(4, 49) | 1251 COLUMN_RENDER_BLOCK(4, 12) |
1164 COLUMN_RENDER_BLOCK(6, 57) | 1252 COLUMN_RENDER_BLOCK(6, 20) |
1165 COLUMN_RENDER_BLOCK_REFRESH(8, 65) | 1253 COLUMN_RENDER_BLOCK_REFRESH(8, 28) |
1166 COLUMN_RENDER_BLOCK(10, 73) | 1254 COLUMN_RENDER_BLOCK(10, 36) |
1167 COLUMN_RENDER_BLOCK(12, 81) | 1255 COLUMN_RENDER_BLOCK(12, 44) |
1168 COLUMN_RENDER_BLOCK(14, 89) | 1256 COLUMN_RENDER_BLOCK(14, 52) |
1169 COLUMN_RENDER_BLOCK_REFRESH(16, 97) | 1257 COLUMN_RENDER_BLOCK_REFRESH(16, 60) |
1170 COLUMN_RENDER_BLOCK(18, 105) | 1258 COLUMN_RENDER_BLOCK(18, 68) |
1171 COLUMN_RENDER_BLOCK(20, 113) | 1259 COLUMN_RENDER_BLOCK(20, 76) |
1172 COLUMN_RENDER_BLOCK(22, 121) | 1260 COLUMN_RENDER_BLOCK(22, 84) |
1173 COLUMN_RENDER_BLOCK_REFRESH(24, 129) | 1261 COLUMN_RENDER_BLOCK_REFRESH(24, 92) |
1174 COLUMN_RENDER_BLOCK(26, 137) | 1262 COLUMN_RENDER_BLOCK(26, 100) |
1175 COLUMN_RENDER_BLOCK(28, 145) | 1263 COLUMN_RENDER_BLOCK(28, 108) |
1176 COLUMN_RENDER_BLOCK(30, 153) | 1264 COLUMN_RENDER_BLOCK(30, 116) |
1177 COLUMN_RENDER_BLOCK_REFRESH(32, 161) | 1265 COLUMN_RENDER_BLOCK_REFRESH(32, 124) |
1178 case 169: | |
1179 case 170: | |
1180 external_slot(context); | |
1181 break; | |
1182 } | 1266 } |
1183 } | 1267 } |
1184 | 1268 |
1185 void vdp_h40_line(uint32_t line, vdp_context * context) | 1269 void vdp_h40_line(uint32_t line, vdp_context * context) |
1186 { | 1270 { |
1187 context->cur_slot = MAX_DRAWS-1; | 1271 context->cur_slot = MAX_DRAWS-1; |
1188 memset(context->linebuf, 0, LINEBUF_SIZE); | 1272 memset(context->linebuf, 0, LINEBUF_SIZE); |
1189 if (line == 0xFF) { | 1273 if (line == 0xFF) { |
1274 external_slot(context); | |
1275 if (context->flags & FLAG_DMA_RUN) { | |
1276 run_dma_src(context, 0); | |
1277 } | |
1278 external_slot(context); | |
1279 if (context->flags & FLAG_DMA_RUN) { | |
1280 run_dma_src(context, 0); | |
1281 } | |
1190 external_slot(context); | 1282 external_slot(context); |
1191 if (context->flags & FLAG_DMA_RUN) { | 1283 if (context->flags & FLAG_DMA_RUN) { |
1192 run_dma_src(context, 0); | 1284 run_dma_src(context, 0); |
1193 } | 1285 } |
1194 external_slot(context); | 1286 external_slot(context); |
1238 } | 1330 } |
1239 read_sprite_x(line, context); | 1331 read_sprite_x(line, context); |
1240 | 1332 |
1241 read_sprite_x(line, context); | 1333 read_sprite_x(line, context); |
1242 } | 1334 } |
1243 external_slot(context); | 1335 |
1244 if (context->flags & FLAG_DMA_RUN) { | |
1245 run_dma_src(context, 0); | |
1246 } | |
1247 external_slot(context); | |
1248 return; | 1336 return; |
1337 } | |
1338 external_slot(context); | |
1339 if (context->flags & FLAG_DMA_RUN) { | |
1340 run_dma_src(context, 0); | |
1341 } | |
1342 external_slot(context); | |
1343 if (context->flags & FLAG_DMA_RUN) { | |
1344 run_dma_src(context, 0); | |
1249 } | 1345 } |
1250 | 1346 |
1251 render_sprite_cells(context); | 1347 render_sprite_cells(context); |
1252 render_sprite_cells(context); | 1348 render_sprite_cells(context); |
1253 render_sprite_cells(context); | 1349 render_sprite_cells(context); |
1354 read_map_scroll_b(column, line, context); | 1450 read_map_scroll_b(column, line, context); |
1355 read_sprite_x(line, context); | 1451 read_sprite_x(line, context); |
1356 render_map_3(context); | 1452 render_map_3(context); |
1357 render_map_output(line, column, context); | 1453 render_map_output(line, column, context); |
1358 } | 1454 } |
1359 external_slot(context); | |
1360 if (context->flags & FLAG_DMA_RUN) { | |
1361 run_dma_src(context, 0); | |
1362 } | |
1363 external_slot(context); | |
1364 } | 1455 } |
1365 | 1456 |
1366 void latch_mode(vdp_context * context) | 1457 void latch_mode(vdp_context * context) |
1367 { | 1458 { |
1368 context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL); | 1459 context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; |
1369 } | 1460 } |
1370 | 1461 |
1371 void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) | 1462 void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) |
1372 { | 1463 { |
1373 if (line > 0) { | 1464 int starti = -1; |
1374 line -= 1; | 1465 if (context->regs[REG_MODE_4] & BIT_H40) { |
1375 int starti = -1; | 1466 if (slot >= 12 && slot < 172) { |
1376 if (context->latched_mode & BIT_H40) { | 1467 uint32_t x = (slot-12)*2; |
1377 if (slot >= 55 && slot < 210) { | 1468 starti = line * 320 + x; |
1378 uint32_t x = (slot-55)*2; | 1469 } |
1379 starti = line * 320 + x; | 1470 } else { |
1380 } else if (slot < 5) { | 1471 if (slot >= 11 && slot < 139) { |
1381 uint32_t x = (slot + 155)*2; | 1472 uint32_t x = (slot-11)*2; |
1382 starti = (line-1)*320 + x; | 1473 starti = line * 320 + x; |
1383 } | 1474 } |
1384 } else { | 1475 } |
1385 if (slot >= 48 && slot < 171) { | 1476 if (starti >= 0) { |
1386 uint32_t x = (slot-48)*2; | 1477 uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; |
1387 starti = line * 320 + x; | 1478 uint32_t * start = context->framebuf; |
1388 } else if (slot < 5) { | 1479 start += starti; |
1389 uint32_t x = (slot + 123)*2; | 1480 for (int i = 0; i < 2; i++) { |
1390 starti = (line-1)*320 + x; | 1481 *(start++) = color; |
1391 } | 1482 } |
1392 } | 1483 } |
1393 if (starti >= 0) { | 1484 } |
1394 if (context->b32) { | 1485 |
1395 uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; | 1486 uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; |
1396 uint32_t * start = context->framebuf; | 1487 |
1397 start += starti; | 1488 void vdp_advance_line(vdp_context *context) |
1398 for (int i = 0; i < 2; i++) { | 1489 { |
1399 *(start++) = color; | 1490 context->vcounter++; |
1400 } | 1491 context->vcounter &= 0x1FF; |
1401 } else { | 1492 if (context->flags2 & FLAG2_REGION_PAL) { |
1402 uint16_t color = context->colors[context->regs[REG_BG_COLOR]]; | 1493 if (context->latched_mode & BIT_PAL) { |
1403 uint16_t * start = context->framebuf; | 1494 if (context->vcounter == 0x10B) { |
1404 start += starti; | 1495 context->vcounter = 0x1D2; |
1405 for (int i = 0; i < 2; i++) { | 1496 } |
1406 *(start++) = color; | 1497 } else if (context->vcounter == 0x103){ |
1407 } | 1498 context->vcounter = 0x1CA; |
1408 } | 1499 } |
1409 } | 1500 } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { |
1501 context->vcounter = 0x1E5; | |
1502 } | |
1503 | |
1504 if (context->vcounter > (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { | |
1505 context->hint_counter = context->regs[REG_HINT]; | |
1506 } else if (context->hint_counter) { | |
1507 context->hint_counter--; | |
1508 } else { | |
1509 context->flags2 |= FLAG2_HINT_PENDING; | |
1510 context->pending_hint_start = context->cycles; | |
1511 context->hint_counter = context->regs[REG_HINT]; | |
1410 } | 1512 } |
1411 } | 1513 } |
1412 | 1514 |
1413 void vdp_run_context(vdp_context * context, uint32_t target_cycles) | 1515 void vdp_run_context(vdp_context * context, uint32_t target_cycles) |
1414 { | 1516 { |
1415 while(context->cycles < target_cycles) | 1517 while(context->cycles < target_cycles) |
1416 { | 1518 { |
1417 context->flags &= ~FLAG_UNUSED_SLOT; | 1519 context->flags &= ~FLAG_UNUSED_SLOT; |
1418 uint32_t line = context->cycles / MCLKS_LINE; | 1520 uint32_t line = context->vcounter; |
1419 uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; | 1521 uint32_t slot = context->hslot; |
1420 if (!context->cycles) { | 1522 |
1523 if (!line && !slot) { | |
1524 //TODO: Figure out when this actually happens | |
1421 latch_mode(context); | 1525 latch_mode(context); |
1422 } | 1526 } |
1423 uint32_t linecyc = context->cycles % MCLKS_LINE; | 1527 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; |
1424 if (linecyc == 0) { | 1528 |
1425 if (line <= 1 || line >= active_lines) { | 1529 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; |
1426 context->hint_counter = context->regs[REG_HINT]; | 1530 if (is_h40) { |
1427 } else if (context->hint_counter) { | 1531 if (slot == 167) { |
1428 context->hint_counter--; | 1532 context->cur_slot = MAX_DRAWS-1; |
1533 memset(context->linebuf, 0, LINEBUF_SIZE); | |
1534 } else if (slot == 171) { | |
1535 context->sprite_index = 0x80; | |
1536 context->slot_counter = MAX_SPRITES_LINE; | |
1537 } | |
1538 } else { | |
1539 if (slot == 134) { | |
1540 context->cur_slot = MAX_DRAWS_H32-1; | |
1541 memset(context->linebuf, 0, LINEBUF_SIZE); | |
1542 } else if (slot == 138) { | |
1543 context->sprite_index = 0x80; | |
1544 context->slot_counter = MAX_SPRITES_LINE_H32; | |
1545 } | |
1546 } | |
1547 if(line == inactive_start) { | |
1548 uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32; | |
1549 if (slot == intslot) { | |
1550 context->flags2 |= FLAG2_VINT_PENDING; | |
1551 context->pending_vint_start = context->cycles; | |
1552 } | |
1553 } | |
1554 uint32_t inccycles; | |
1555 //line 0x1FF is basically active even though it's not displayed | |
1556 uint8_t active_slot = line < inactive_start || line == 0x1FF; | |
1557 if (is_h40) { | |
1558 if (slot < HSYNC_SLOT_H40 || slot >= HSYNC_END_H40) { | |
1559 inccycles = MCLKS_SLOT_H40; | |
1429 } else { | 1560 } else { |
1430 context->flags2 |= FLAG2_HINT_PENDING; | 1561 inccycles = h40_hsync_cycles[slot-HSYNC_SLOT_H40]; |
1431 context->hint_counter = context->regs[REG_HINT]; | 1562 } |
1432 } | 1563 //the first inactive line behaves as an active one for the first 4 slots |
1433 } else if(line == active_lines) { | 1564 if (line == inactive_start && slot > 166 && slot < 171) { |
1434 uint32_t intcyc = context->latched_mode & BIT_H40 ? VINT_CYCLE_H40 : VINT_CYCLE_H32; | 1565 active_slot = 1; |
1435 if (linecyc == intcyc) { | |
1436 context->flags2 |= FLAG2_VINT_PENDING; | |
1437 } | |
1438 } | |
1439 uint32_t inccycles, slot; | |
1440 if (context->latched_mode & BIT_H40){ | |
1441 if (linecyc < MCLKS_SLOT_H40*HSYNC_SLOT_H40) { | |
1442 slot = linecyc/MCLKS_SLOT_H40; | |
1443 inccycles = MCLKS_SLOT_H40; | |
1444 } else if(linecyc < MCLK_WEIRD_END) { | |
1445 switch(linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)) | |
1446 { | |
1447 case 0: | |
1448 inccycles = 19; | |
1449 slot = 0; | |
1450 break; | |
1451 case 19: | |
1452 slot = 1; | |
1453 inccycles = 20; | |
1454 break; | |
1455 case 39: | |
1456 slot = 2; | |
1457 inccycles = 20; | |
1458 break; | |
1459 case 59: | |
1460 slot = 3; | |
1461 inccycles = 20; | |
1462 break; | |
1463 case 79: | |
1464 slot = 4; | |
1465 inccycles = 18; | |
1466 break; | |
1467 case 97: | |
1468 slot = 5; | |
1469 inccycles = 20; | |
1470 break; | |
1471 case 117: | |
1472 slot = 6; | |
1473 inccycles = 20; | |
1474 break; | |
1475 case 137: | |
1476 slot = 7; | |
1477 inccycles = 20; | |
1478 break; | |
1479 case 157: | |
1480 slot = 8; | |
1481 inccycles = 18; | |
1482 break; | |
1483 case 175: | |
1484 slot = 9; | |
1485 inccycles = 20; | |
1486 break; | |
1487 case 195: | |
1488 slot = 10; | |
1489 inccycles = 20; | |
1490 break; | |
1491 case 215: | |
1492 slot = 11; | |
1493 inccycles = 20; | |
1494 break; | |
1495 case 235: | |
1496 slot = 12; | |
1497 inccycles = 18; | |
1498 break; | |
1499 case 253: | |
1500 slot = 13; | |
1501 inccycles = 20; | |
1502 break; | |
1503 case 273: | |
1504 slot = 14; | |
1505 inccycles = 20; | |
1506 break; | |
1507 case 293: | |
1508 slot = 15; | |
1509 inccycles = 20; | |
1510 break; | |
1511 case 313: | |
1512 slot = 16; | |
1513 inccycles = 19; | |
1514 break; | |
1515 default: | |
1516 fprintf(stderr, "cycles after weirdness %d\n", linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)); | |
1517 exit(1); | |
1518 } | |
1519 slot += HSYNC_SLOT_H40; | |
1520 } else { | |
1521 slot = (linecyc-MCLK_WEIRD_END)/MCLKS_SLOT_H40 + SLOT_WEIRD_END; | |
1522 inccycles = MCLKS_SLOT_H40; | |
1523 } | 1566 } |
1524 } else { | 1567 } else { |
1525 inccycles = MCLKS_SLOT_H32; | 1568 inccycles = MCLKS_SLOT_H32; |
1526 slot = linecyc/MCLKS_SLOT_H32; | 1569 //the first inactive line behaves as an active one for the first 4 slots |
1527 } | 1570 if (line == inactive_start && slot > 166 && slot < 171) { |
1528 if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { | 1571 active_slot = 1; |
1529 //first sort-of active line is treated as 255 internally | 1572 } |
1530 //it's used for gathering sprite info for line | 1573 } |
1531 line = (line - 1) & 0xFF; | 1574 uint8_t inc_slot = 1; |
1532 | 1575 if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { |
1533 //Convert to slot number | 1576 //run VDP rendering for a slot or a line |
1534 if (context->latched_mode & BIT_H40){ | 1577 if (is_h40) { |
1535 if (!slot && line != (active_lines-1) && (target_cycles - context->cycles) >= MCLKS_LINE) { | 1578 if (slot == LINE_CHANGE_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { |
1536 vdp_h40_line(line, context); | 1579 vdp_h40_line(line, context); |
1537 inccycles = MCLKS_LINE; | 1580 inccycles = MCLKS_LINE; |
1581 inc_slot = 0; | |
1538 } else { | 1582 } else { |
1539 vdp_h40(line, slot, context); | 1583 vdp_h40(line, slot, context); |
1540 } | 1584 } |
1541 } else { | 1585 } else { |
1542 vdp_h32(line, slot, context); | 1586 vdp_h32(line, slot, context); |
1543 } | 1587 } |
1544 } else { | 1588 } else { |
1545 if (!is_refresh(context, slot)) { | 1589 if (!is_refresh(context, slot)) { |
1546 external_slot(context); | 1590 external_slot(context); |
1547 } | 1591 } |
1548 if (line < active_lines) { | 1592 if (line < inactive_start) { |
1549 check_render_bg(context, line, slot); | 1593 check_render_bg(context, line, slot); |
1550 } | 1594 } |
1551 } | 1595 } |
1552 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { | 1596 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { |
1553 run_dma_src(context, slot); | 1597 run_dma_src(context, slot); |
1554 } | 1598 } |
1555 context->cycles += inccycles; | 1599 context->cycles += inccycles; |
1600 if (inc_slot) { | |
1601 context->hslot++; | |
1602 context->hslot &= 0xFF; | |
1603 if (is_h40) { | |
1604 if (context->hslot == LINE_CHANGE_H40) { | |
1605 vdp_advance_line(context); | |
1606 if (context->vcounter == (inactive_start + 8)) { | |
1607 context->frame++; | |
1608 } | |
1609 } else if (context->hslot == 183) { | |
1610 context->hslot = 229; | |
1611 } | |
1612 } else { | |
1613 if (context->hslot == LINE_CHANGE_H32) { | |
1614 vdp_advance_line(context); | |
1615 if (context->vcounter == (inactive_start + 8)) { | |
1616 context->frame++; | |
1617 } | |
1618 } else if (context->hslot == 148) { | |
1619 context->hslot = 233; | |
1620 } | |
1621 } | |
1622 | |
1623 } else { | |
1624 vdp_advance_line(context); | |
1625 } | |
1556 } | 1626 } |
1557 } | 1627 } |
1558 | 1628 |
1559 uint32_t vdp_run_to_vblank(vdp_context * context) | 1629 uint32_t vdp_run_to_vblank(vdp_context * context) |
1560 { | 1630 { |
1561 uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_ACTIVE : NTSC_ACTIVE) * MCLKS_LINE; | 1631 uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_INACTIVE_START : NTSC_INACTIVE_START) * MCLKS_LINE; |
1562 vdp_run_context(context, target_cycles); | 1632 vdp_run_context(context, target_cycles); |
1563 return context->cycles; | 1633 return context->cycles; |
1564 } | 1634 } |
1565 | 1635 |
1566 void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) | 1636 void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) |
1568 for(;;) { | 1638 for(;;) { |
1569 uint32_t dmalen = (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]; | 1639 uint32_t dmalen = (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]; |
1570 if (!dmalen) { | 1640 if (!dmalen) { |
1571 dmalen = 0x10000; | 1641 dmalen = 0x10000; |
1572 } | 1642 } |
1573 uint32_t min_dma_complete = dmalen * (context->latched_mode & BIT_H40 ? 16 : 20); | 1643 uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20); |
1574 if ((context->regs[REG_DMASRC_H] & 0xC0) == 0xC0 || (context->cd & 0xF) == VRAM_WRITE) { | 1644 if ((context->regs[REG_DMASRC_H] & 0xC0) == 0xC0 || (context->cd & 0xF) == VRAM_WRITE) { |
1575 //DMA copies take twice as long to complete since they require a read and a write | 1645 //DMA copies take twice as long to complete since they require a read and a write |
1576 //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word | 1646 //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word |
1577 min_dma_complete *= 2; | 1647 min_dma_complete *= 2; |
1578 } | 1648 } |
1604 // | 1674 // |
1605 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { | 1675 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { |
1606 //DMA copy or 68K -> VDP, transfer starts immediately | 1676 //DMA copy or 68K -> VDP, transfer starts immediately |
1607 context->flags |= FLAG_DMA_RUN; | 1677 context->flags |= FLAG_DMA_RUN; |
1608 context->dma_cd = context->cd; | 1678 context->dma_cd = context->cd; |
1609 //printf("DMA start at cycle %d\n", context->cycles); | 1679 //printf("DMA start (length: %X) at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L], context->cycles, context->frame, context->vcounter, context->hslot); |
1610 if (!(context->regs[REG_DMASRC_H] & 0x80)) { | 1680 if (!(context->regs[REG_DMASRC_H] & 0x80)) { |
1611 //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]); | 1681 //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]); |
1612 return 1; | 1682 return 1; |
1613 } else { | 1683 } else { |
1614 //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]); | 1684 //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]); |
1627 context->hv_latch = vdp_hv_counter_read(context); | 1697 context->hv_latch = vdp_hv_counter_read(context); |
1628 } | 1698 } |
1629 if (reg == REG_BG_COLOR) { | 1699 if (reg == REG_BG_COLOR) { |
1630 value &= 0x3F; | 1700 value &= 0x3F; |
1631 } | 1701 } |
1702 /*if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) { | |
1703 printf("Mode changed from H%d to H%d @ %d, frame: %d\n", context->regs[reg] & BIT_H40 ? 40 : 32, value & BIT_H40 ? 40 : 32, context->cycles, context->frame); | |
1704 }*/ | |
1632 context->regs[reg] = value; | 1705 context->regs[reg] = value; |
1633 if (reg == REG_MODE_4) { | 1706 if (reg == REG_MODE_4) { |
1634 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); | 1707 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); |
1635 if (!context->double_res) { | 1708 if (!context->double_res) { |
1636 context->framebuf = context->oddbuf; | 1709 context->framebuf = context->oddbuf; |
1637 } | 1710 } |
1638 } | 1711 } |
1639 context->cd &= 0x3C; | 1712 context->cd &= 0x3C; |
1640 } | 1713 } |
1641 } else { | 1714 } else { |
1642 context->flags |= FLAG_PENDING; | 1715 context->flags |= FLAG_PENDING; |
1643 context->address = (context->address &0xC000) | (value & 0x3FFF); | 1716 context->address = (context->address &0xC000) | (value & 0x3FFF); |
1659 }*/ | 1732 }*/ |
1660 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { | 1733 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { |
1661 context->flags &= ~FLAG_DMA_RUN; | 1734 context->flags &= ~FLAG_DMA_RUN; |
1662 } | 1735 } |
1663 while (context->fifo_write == context->fifo_read) { | 1736 while (context->fifo_write == context->fifo_read) { |
1664 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); | 1737 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); |
1665 } | 1738 } |
1666 fifo_entry * cur = context->fifo + context->fifo_write; | 1739 fifo_entry * cur = context->fifo + context->fifo_write; |
1667 cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; | 1740 cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; |
1668 cur->address = context->address; | 1741 cur->address = context->address; |
1669 cur->value = value; | 1742 cur->value = value; |
1670 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { | 1743 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { |
1671 context->flags |= FLAG_DMA_RUN; | 1744 context->flags |= FLAG_DMA_RUN; |
1672 } | 1745 } |
1673 cur->cd = context->cd; | 1746 cur->cd = context->cd; |
1674 cur->partial = 0; | 1747 cur->partial = 0; |
1675 if (context->fifo_read < 0) { | 1748 if (context->fifo_read < 0) { |
1707 context->flags2 &= ~FLAG2_SPRITE_COLLIDE; | 1780 context->flags2 &= ~FLAG2_SPRITE_COLLIDE; |
1708 } | 1781 } |
1709 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { | 1782 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { |
1710 value |= 0x10; | 1783 value |= 0x10; |
1711 } | 1784 } |
1712 uint32_t line= context->cycles / MCLKS_LINE; | 1785 uint32_t line= context->vcounter; |
1713 uint32_t linecyc = context->cycles % MCLKS_LINE; | 1786 uint32_t slot = context->hslot; |
1714 if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { | 1787 uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); |
1788 if ( | |
1789 ( | |
1790 line > inactive_start | |
1791 && line < 0x1FF | |
1792 ) | |
1793 || (line == inactive_start | |
1794 && ( | |
1795 slot >= (context->regs[REG_MODE_4] & BIT_H40 ? VBLANK_START_H40 : VBLANK_START_H32) | |
1796 || slot < (context->regs[REG_MODE_4] & BIT_H40 ? LINE_CHANGE_H40 : LINE_CHANGE_H32) | |
1797 ) | |
1798 ) | |
1799 || (line == 0x1FF | |
1800 && slot < (context->regs[REG_MODE_4] & BIT_H40 ? VBLANK_START_H40 : VBLANK_START_H32)) | |
1801 && slot >= (context->regs[REG_MODE_4] & BIT_H40 ? LINE_CHANGE_H40 : LINE_CHANGE_H32) | |
1802 || !(context->regs[REG_MODE_2] & BIT_DISP_EN) | |
1803 ) { | |
1715 value |= 0x8; | 1804 value |= 0x8; |
1716 } | 1805 } |
1717 if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { | 1806 if (context->regs[REG_MODE_4] & BIT_H40) { |
1718 value |= 0x4; | 1807 if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) { |
1808 value |= 0x4; | |
1809 } | |
1810 } else { | |
1811 if (slot < HBLANK_END_H32 || slot > HBLANK_START_H32) { | |
1812 value |= 0x4; | |
1813 } | |
1719 } | 1814 } |
1720 if (context->flags & FLAG_DMA_RUN) { | 1815 if (context->flags & FLAG_DMA_RUN) { |
1721 value |= 0x2; | 1816 value |= 0x2; |
1722 } | 1817 } |
1723 if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify | 1818 if (context->flags2 & FLAG2_REGION_PAL) { |
1724 value |= 0x1; | 1819 value |= 0x1; |
1725 } | 1820 } |
1726 //printf("status read at cycle %d returned %X\n", context->cycles, value); | 1821 //printf("status read at cycle %d returned %X\n", context->cycles, value); |
1727 return value; | 1822 return value; |
1728 } | 1823 } |
1739 } | 1834 } |
1740 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense | 1835 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense |
1741 context->flags &= ~FLAG_UNUSED_SLOT; | 1836 context->flags &= ~FLAG_UNUSED_SLOT; |
1742 //context->flags2 |= FLAG2_READ_PENDING; | 1837 //context->flags2 |= FLAG2_READ_PENDING; |
1743 while (!(context->flags & FLAG_UNUSED_SLOT)) { | 1838 while (!(context->flags & FLAG_UNUSED_SLOT)) { |
1744 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); | 1839 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); |
1745 } | 1840 } |
1746 uint16_t value = 0; | 1841 uint16_t value = 0; |
1747 switch (context->cd & 0xF) | 1842 switch (context->cd & 0xF) |
1748 { | 1843 { |
1749 case VRAM_READ: | 1844 case VRAM_READ: |
1750 value = context->vdpmem[context->address & 0xFFFE] << 8; | 1845 value = context->vdpmem[context->address & 0xFFFE] << 8; |
1751 context->flags &= ~FLAG_UNUSED_SLOT; | 1846 context->flags &= ~FLAG_UNUSED_SLOT; |
1752 context->flags2 |= FLAG2_READ_PENDING; | 1847 context->flags2 |= FLAG2_READ_PENDING; |
1753 while (!(context->flags & FLAG_UNUSED_SLOT)) { | 1848 while (!(context->flags & FLAG_UNUSED_SLOT)) { |
1754 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); | 1849 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); |
1755 } | 1850 } |
1756 value |= context->vdpmem[context->address | 1]; | 1851 value |= context->vdpmem[context->address | 1]; |
1757 break; | 1852 break; |
1758 case VRAM_READ8: | 1853 case VRAM_READ8: |
1759 value = context->vdpmem[context->address ^ 1]; | 1854 value = context->vdpmem[context->address ^ 1]; |
1780 uint16_t vdp_hv_counter_read(vdp_context * context) | 1875 uint16_t vdp_hv_counter_read(vdp_context * context) |
1781 { | 1876 { |
1782 if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) { | 1877 if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) { |
1783 return context->hv_latch; | 1878 return context->hv_latch; |
1784 } | 1879 } |
1785 uint32_t line= context->cycles / MCLKS_LINE; | 1880 uint32_t line= context->vcounter & 0xFF; |
1786 if (!line) { | 1881 uint32_t linecyc = context->hslot; |
1787 line = 0xFF; | |
1788 } else { | |
1789 line--; | |
1790 if (line > 0xEA) { | |
1791 line = (line + 0xFA) & 0xFF; | |
1792 } | |
1793 } | |
1794 uint32_t linecyc = context->cycles % MCLKS_LINE; | |
1795 if (context->latched_mode & BIT_H40) { | |
1796 uint32_t slot; | |
1797 if (linecyc < MCLKS_SLOT_H40*HSYNC_SLOT_H40) { | |
1798 slot = linecyc/MCLKS_SLOT_H40; | |
1799 } else if(linecyc < MCLK_WEIRD_END) { | |
1800 switch(linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)) | |
1801 { | |
1802 case 0: | |
1803 slot = 0; | |
1804 break; | |
1805 case 19: | |
1806 slot = 1; | |
1807 break; | |
1808 case 39: | |
1809 slot = 2; | |
1810 break; | |
1811 case 59: | |
1812 slot = 2; | |
1813 break; | |
1814 case 79: | |
1815 slot = 3; | |
1816 break; | |
1817 case 97: | |
1818 slot = 4; | |
1819 break; | |
1820 case 117: | |
1821 slot = 5; | |
1822 break; | |
1823 case 137: | |
1824 slot = 6; | |
1825 break; | |
1826 case 157: | |
1827 slot = 7; | |
1828 break; | |
1829 case 175: | |
1830 slot = 8; | |
1831 break; | |
1832 case 195: | |
1833 slot = 9; | |
1834 break; | |
1835 case 215: | |
1836 slot = 11; | |
1837 break; | |
1838 case 235: | |
1839 slot = 12; | |
1840 break; | |
1841 case 253: | |
1842 slot = 13; | |
1843 break; | |
1844 case 273: | |
1845 slot = 14; | |
1846 break; | |
1847 case 293: | |
1848 slot = 15; | |
1849 break; | |
1850 case 313: | |
1851 slot = 16; | |
1852 break; | |
1853 default: | |
1854 fprintf(stderr, "cycles after weirdness %d\n", linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)); | |
1855 exit(1); | |
1856 } | |
1857 slot += HSYNC_SLOT_H40; | |
1858 } else { | |
1859 slot = (linecyc-MCLK_WEIRD_END)/MCLKS_SLOT_H40 + SLOT_WEIRD_END; | |
1860 } | |
1861 linecyc = slot * 2; | |
1862 if (linecyc >= 86) { | |
1863 linecyc -= 86; | |
1864 } else { | |
1865 linecyc += 334; | |
1866 } | |
1867 if (linecyc > 0x16C) { | |
1868 linecyc += 92; | |
1869 } | |
1870 } else { | |
1871 linecyc /= 10; | |
1872 if (linecyc >= 74) { | |
1873 linecyc -= 74; | |
1874 } else { | |
1875 linecyc += 268; | |
1876 } | |
1877 if (linecyc > 0x127) { | |
1878 linecyc += 170; | |
1879 } | |
1880 } | |
1881 linecyc &= 0xFF; | 1882 linecyc &= 0xFF; |
1882 if (context->double_res) { | 1883 if (context->double_res) { |
1883 line <<= 1; | 1884 line <<= 1; |
1884 if (line & 0x100) { | 1885 if (line & 0x100) { |
1885 line |= 1; | 1886 line |= 1; |
1895 } | 1896 } |
1896 | 1897 |
1897 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) | 1898 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) |
1898 { | 1899 { |
1899 context->cycles -= deduction; | 1900 context->cycles -= deduction; |
1901 if (context->pending_vint_start >= deduction) { | |
1902 context->pending_vint_start -= deduction; | |
1903 } else { | |
1904 context->pending_vint_start = 0; | |
1905 } | |
1906 if (context->pending_hint_start >= deduction) { | |
1907 context->pending_hint_start -= deduction; | |
1908 } else { | |
1909 context->pending_hint_start = 0; | |
1910 } | |
1900 if (context->fifo_read >= 0) { | 1911 if (context->fifo_read >= 0) { |
1901 int32_t idx = context->fifo_read; | 1912 int32_t idx = context->fifo_read; |
1902 do { | 1913 do { |
1903 if (context->fifo[idx].cycle >= deduction) { | 1914 if (context->fifo[idx].cycle >= deduction) { |
1904 context->fifo[idx].cycle -= deduction; | 1915 context->fifo[idx].cycle -= deduction; |
1908 idx = (idx+1) & (FIFO_SIZE-1); | 1919 idx = (idx+1) & (FIFO_SIZE-1); |
1909 } while(idx != context->fifo_write); | 1920 } while(idx != context->fifo_write); |
1910 } | 1921 } |
1911 } | 1922 } |
1912 | 1923 |
1924 uint32_t vdp_cycles_hslot_wrap_h40(vdp_context * context) | |
1925 { | |
1926 if (context->hslot < 183) { | |
1927 return MCLKS_LINE - context->hslot * MCLKS_SLOT_H40; | |
1928 } else if (context->hslot < HSYNC_END_H40) { | |
1929 uint32_t before_hsync = context->hslot < HSYNC_SLOT_H40 ? (HSYNC_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40 : 0; | |
1930 uint32_t hsync = 0; | |
1931 for (int i = context->hslot <= HSYNC_SLOT_H40 ? 0 : context->hslot - HSYNC_SLOT_H40; i < sizeof(h40_hsync_cycles)/sizeof(uint32_t); i++) | |
1932 { | |
1933 hsync += h40_hsync_cycles[i]; | |
1934 } | |
1935 uint32_t after_hsync = (256- HSYNC_END_H40) * MCLKS_SLOT_H40; | |
1936 return before_hsync + hsync + after_hsync; | |
1937 } else { | |
1938 return (256-context->hslot) * MCLKS_SLOT_H40; | |
1939 } | |
1940 } | |
1941 | |
1942 uint32_t vdp_cycles_next_line(vdp_context * context) | |
1943 { | |
1944 if (context->regs[REG_MODE_4] & BIT_H40) { | |
1945 if (context->hslot < LINE_CHANGE_H40) { | |
1946 return (LINE_CHANGE_H40 - context->hslot) * MCLKS_SLOT_H40; | |
1947 } else { | |
1948 return vdp_cycles_hslot_wrap_h40(context) + LINE_CHANGE_H40 * MCLKS_SLOT_H40; | |
1949 } | |
1950 } else { | |
1951 if (context->hslot < LINE_CHANGE_H32) { | |
1952 return (LINE_CHANGE_H32 - context->hslot) * MCLKS_SLOT_H32; | |
1953 } else if (context->hslot < 148) { | |
1954 return MCLKS_LINE - (context->hslot - LINE_CHANGE_H32) * MCLKS_SLOT_H32; | |
1955 } else { | |
1956 return (256-context->hslot + LINE_CHANGE_H32) * MCLKS_SLOT_H32; | |
1957 } | |
1958 } | |
1959 } | |
1960 | |
1961 uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) | |
1962 { | |
1963 uint32_t jump_start, jump_dst; | |
1964 if (context->flags2 & FLAG2_REGION_PAL) { | |
1965 if (context->latched_mode & BIT_PAL) { | |
1966 jump_start = 0x10B; | |
1967 jump_dst = 0x1D2; | |
1968 } else { | |
1969 jump_start = 0x103; | |
1970 jump_dst = 0x1CA; | |
1971 } | |
1972 } else { | |
1973 if (context->latched_mode & BIT_PAL) { | |
1974 jump_start = 0; | |
1975 jump_dst = 0; | |
1976 } else { | |
1977 jump_start = 0xEB; | |
1978 jump_dst = 0x1E5; | |
1979 } | |
1980 } | |
1981 uint32_t lines; | |
1982 if (context->vcounter < target) { | |
1983 if (target < jump_start) { | |
1984 lines = target - context->vcounter; | |
1985 } else { | |
1986 lines = jump_start - context->vcounter + target - jump_dst; | |
1987 } | |
1988 } else { | |
1989 if (context->vcounter < jump_start) { | |
1990 lines = jump_start - context->vcounter + 512 - jump_dst; | |
1991 } else { | |
1992 lines = 512 - context->vcounter; | |
1993 } | |
1994 if (target < jump_start) { | |
1995 lines += target; | |
1996 } else { | |
1997 lines += jump_start + target - jump_dst; | |
1998 } | |
1999 } | |
2000 return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context); | |
2001 } | |
2002 | |
2003 uint32_t vdp_frame_end_line(vdp_context * context) | |
2004 { | |
2005 uint32_t frame_end; | |
2006 if (context->flags2 & FLAG2_REGION_PAL) { | |
2007 if (context->latched_mode & BIT_PAL) { | |
2008 frame_end = PAL_INACTIVE_START + 8; | |
2009 } else { | |
2010 frame_end = NTSC_INACTIVE_START + 8; | |
2011 } | |
2012 } else { | |
2013 if (context->latched_mode & BIT_PAL) { | |
2014 frame_end = 512; | |
2015 } else { | |
2016 frame_end = NTSC_INACTIVE_START + 8; | |
2017 } | |
2018 } | |
2019 return frame_end; | |
2020 } | |
2021 | |
2022 uint32_t vdp_cycles_to_frame_end(vdp_context * context) | |
2023 { | |
2024 return context->cycles + vdp_cycles_to_line(context, vdp_frame_end_line(context)); | |
2025 } | |
2026 | |
1913 uint32_t vdp_next_hint(vdp_context * context) | 2027 uint32_t vdp_next_hint(vdp_context * context) |
1914 { | 2028 { |
1915 if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) { | 2029 if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) { |
1916 return 0xFFFFFFFF; | 2030 return 0xFFFFFFFF; |
1917 } | 2031 } |
1918 if (context->flags2 & FLAG2_HINT_PENDING) { | 2032 if (context->flags2 & FLAG2_HINT_PENDING) { |
1919 return context->cycles; | 2033 return context->pending_hint_start; |
1920 } | 2034 } |
1921 uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; | 2035 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; |
1922 uint32_t line = context->cycles / MCLKS_LINE; | 2036 uint32_t hint_line; |
1923 if (line >= active_lines) { | 2037 if (context->vcounter + context->hint_counter >= inactive_start) { |
1924 return 0xFFFFFFFF; | 2038 if (context->regs[REG_HINT] > inactive_start) { |
1925 } | 2039 return 0xFFFFFFFF; |
1926 uint32_t linecyc = context->cycles % MCLKS_LINE; | 2040 } |
1927 uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc; | 2041 hint_line = context->regs[REG_HINT]; |
1928 if (!line) { | 2042 } else { |
1929 hcycle += MCLKS_LINE; | 2043 hint_line = context->vcounter + context->hint_counter + 1; |
1930 } | 2044 } |
1931 return hcycle; | 2045 |
2046 return context->cycles + vdp_cycles_to_line(context, hint_line); | |
1932 } | 2047 } |
1933 | 2048 |
1934 uint32_t vdp_next_vint(vdp_context * context) | 2049 uint32_t vdp_next_vint(vdp_context * context) |
1935 { | 2050 { |
1936 if (!(context->regs[REG_MODE_2] & BIT_VINT_EN)) { | 2051 if (!(context->regs[REG_MODE_2] & BIT_VINT_EN)) { |
1937 return 0xFFFFFFFF; | 2052 return 0xFFFFFFFF; |
1938 } | 2053 } |
1939 if (context->flags2 & FLAG2_VINT_PENDING) { | 2054 if (context->flags2 & FLAG2_VINT_PENDING) { |
1940 return context->cycles; | 2055 return context->pending_vint_start; |
1941 } | 2056 } |
1942 uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; | 2057 |
1943 uint32_t vcycle = MCLKS_LINE * active_lines; | 2058 |
1944 if (context->latched_mode & BIT_H40) { | 2059 return vdp_next_vint_z80(context); |
1945 vcycle += VINT_CYCLE_H40; | 2060 } |
2061 | |
2062 uint32_t vdp_next_vint_z80(vdp_context * context) | |
2063 { | |
2064 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; | |
2065 if (context->vcounter == inactive_start) { | |
2066 if (context->regs[REG_MODE_4] & BIT_H40) { | |
2067 if (context->hslot >= LINE_CHANGE_H40) { | |
2068 return context->cycles + vdp_cycles_hslot_wrap_h40(context) + VINT_SLOT_H40 * MCLKS_SLOT_H40; | |
2069 } else if (context->hslot <= VINT_SLOT_H40) { | |
2070 return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40; | |
2071 } | |
2072 } else { | |
2073 if (context->hslot >= LINE_CHANGE_H32) { | |
2074 if (context->hslot < 148) { | |
2075 return context->cycles + (VINT_SLOT_H32 + 148 - context->hslot + 256 - 233) * MCLKS_SLOT_H32; | |
2076 } else { | |
2077 return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32; | |
2078 } | |
2079 } else if (context->hslot <= VINT_SLOT_H32) { | |
2080 return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32; | |
2081 } | |
2082 } | |
2083 } | |
2084 int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); | |
2085 if (context->regs[REG_MODE_4] & BIT_H40) { | |
2086 cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 - VINT_SLOT_H40) * MCLKS_SLOT_H40; | |
1946 } else { | 2087 } else { |
1947 vcycle += VINT_CYCLE_H32; | 2088 cycles_to_vint += (VINT_SLOT_H32 + 148 - LINE_CHANGE_H32 + 256 - 233) * MCLKS_SLOT_H32; |
1948 } | 2089 } |
1949 if (vcycle < context->cycles) { | 2090 return context->cycles + cycles_to_vint; |
1950 return 0xFFFFFFFF; | |
1951 } | |
1952 return vcycle; | |
1953 } | |
1954 | |
1955 uint32_t vdp_next_vint_z80(vdp_context * context) | |
1956 { | |
1957 uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; | |
1958 uint32_t vcycle = MCLKS_LINE * active_lines; | |
1959 if (context->latched_mode & BIT_H40) { | |
1960 vcycle += VINT_CYCLE_H40; | |
1961 } else { | |
1962 vcycle += VINT_CYCLE_H32; | |
1963 } | |
1964 return vcycle; | |
1965 } | 2091 } |
1966 | 2092 |
1967 void vdp_int_ack(vdp_context * context, uint16_t int_num) | 2093 void vdp_int_ack(vdp_context * context, uint16_t int_num) |
1968 { | 2094 { |
1969 if (int_num == 6) { | 2095 if (int_num == 6) { |