Mercurial > repos > blastem
comparison vdp.c @ 450:3758bcdae5de
Fix bug that caused a DMA fill to start after another DMA operation completed if the FIFO is not empty
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 01 Sep 2013 12:11:28 -0700 |
parents | b3cee2fe690b |
children | 608815ab4ff2 |
comparison
equal
deleted
inserted
replaced
448:e85a107e6ec0 | 450:3758bcdae5de |
---|---|
123 | 123 |
124 void render_sprite_cells(vdp_context * context) | 124 void render_sprite_cells(vdp_context * context) |
125 { | 125 { |
126 if (context->cur_slot >= context->sprite_draws) { | 126 if (context->cur_slot >= context->sprite_draws) { |
127 sprite_draw * d = context->sprite_draw_list + context->cur_slot; | 127 sprite_draw * d = context->sprite_draw_list + context->cur_slot; |
128 | 128 |
129 uint16_t dir; | 129 uint16_t dir; |
130 int16_t x; | 130 int16_t x; |
131 if (d->h_flip) { | 131 if (d->h_flip) { |
132 x = d->x_pos + 7; | 132 x = d->x_pos + 7; |
133 dir = -1; | 133 dir = -1; |
162 int16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; | 162 int16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; |
163 int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF; | 163 int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF; |
164 uint16_t link = context->vdpmem[address+3] & 0x7F; | 164 uint16_t link = context->vdpmem[address+3] & 0x7F; |
165 uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3; | 165 uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3; |
166 uint8_t pri = context->vdpmem[address + 4] >> 7; | 166 uint8_t pri = context->vdpmem[address + 4] >> 7; |
167 uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; | 167 uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; |
168 //printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern); | 168 //printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern); |
169 current_index = link; | 169 current_index = link; |
170 count++; | 170 count++; |
171 } while (current_index != 0 && count < 80); | 171 } while (current_index != 0 && count < 80); |
172 } | 172 } |
177 printf("**Mode Group**\n" | 177 printf("**Mode Group**\n" |
178 "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n" | 178 "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n" |
179 "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" | 179 "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" |
180 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" | 180 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" |
181 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", | 181 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", |
182 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, | 182 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, |
183 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", | 183 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", |
184 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", | 184 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", |
185 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, | 185 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, |
186 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", | 186 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", |
187 hscroll[context->regs[REG_MODE_3] & 0x3], | 187 hscroll[context->regs[REG_MODE_3] & 0x3], |
188 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled"); | 188 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled"); |
189 printf("\n**Table Group**\n" | 189 printf("\n**Table Group**\n" |
201 printf("\n**Misc Group**\n" | 201 printf("\n**Misc Group**\n" |
202 "07: %.2X | Backdrop Color: $%X\n" | 202 "07: %.2X | Backdrop Color: $%X\n" |
203 "0A: %.2X | H-Int Counter: %u\n" | 203 "0A: %.2X | H-Int Counter: %u\n" |
204 "0F: %.2X | Auto-increment: $%X\n" | 204 "0F: %.2X | Auto-increment: $%X\n" |
205 "10: %.2X | Scroll A/B Size: %sx%s\n", | 205 "10: %.2X | Scroll A/B Size: %sx%s\n", |
206 context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, | 206 context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, |
207 context->regs[REG_HINT], context->regs[REG_HINT], | 207 context->regs[REG_HINT], context->regs[REG_HINT], |
208 context->regs[REG_AUTOINC], context->regs[REG_AUTOINC], | 208 context->regs[REG_AUTOINC], context->regs[REG_AUTOINC], |
209 context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]); | 209 context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]); |
210 printf("\n**Internal Group**\n" | 210 printf("\n**Internal Group**\n" |
211 "Address: %X\n" | 211 "Address: %X\n" |
212 "CD: %X\n" | 212 "CD: %X\n" |
213 "Pending: %s\n", | 213 "Pending: %s\n", |
214 context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); | 214 context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); |
215 | 215 |
216 //TODO: Window Group, DMA Group | 216 //TODO: Window Group, DMA Group |
217 } | 217 } |
218 | 218 |
219 void scan_sprite_table(uint32_t line, vdp_context * context) | 219 void scan_sprite_table(uint32_t line, vdp_context * context) |
220 { | 220 { |
221 if (context->sprite_index && context->slot_counter) { | 221 if (context->sprite_index && context->slot_counter) { |
293 line++; | 293 line++; |
294 } | 294 } |
295 height *= 2; | 295 height *= 2; |
296 } | 296 } |
297 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; | 297 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; |
298 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; | 298 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; |
299 uint8_t pal_priority = (tileinfo >> 9) & 0x70; | 299 uint8_t pal_priority = (tileinfo >> 9) & 0x70; |
300 uint8_t row; | 300 uint8_t row; |
301 if (tileinfo & MAP_BIT_V_FLIP) { | 301 if (tileinfo & MAP_BIT_V_FLIP) { |
302 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; | 302 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; |
303 } else { | 303 } else { |
313 if (x) { | 313 if (x) { |
314 context->flags |= FLAG_CAN_MASK; | 314 context->flags |= FLAG_CAN_MASK; |
315 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { | 315 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { |
316 context->flags |= FLAG_MASKED; | 316 context->flags |= FLAG_MASKED; |
317 } | 317 } |
318 | 318 |
319 context->flags &= ~FLAG_DOT_OFLOW; | 319 context->flags &= ~FLAG_DOT_OFLOW; |
320 int16_t i; | 320 int16_t i; |
321 if (context->flags & FLAG_MASKED) { | 321 if (context->flags & FLAG_MASKED) { |
322 for (i=0; i < width && context->sprite_draws; i++) { | 322 for (i=0; i < width && context->sprite_draws; i++) { |
323 --context->sprite_draws; | 323 --context->sprite_draws; |
413 //Charles MacDonald's VDP doc says that the low byte gets written first | 413 //Charles MacDonald's VDP doc says that the low byte gets written first |
414 context->vdpmem[context->address] = context->dma_val; | 414 context->vdpmem[context->address] = context->dma_val; |
415 context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF); | 415 context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF); |
416 break; | 416 break; |
417 case CRAM_WRITE: | 417 case CRAM_WRITE: |
418 write_cram(context, context->address, context->dma_val); | 418 write_cram(context, context->address, context->dma_val); |
419 //printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles); | 419 //printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles); |
420 break; | 420 break; |
421 case VSRAM_WRITE: | 421 case VSRAM_WRITE: |
422 if (((context->address/2) & 63) < VSRAM_SIZE) { | 422 if (((context->address/2) & 63) < VSRAM_SIZE) { |
423 context->vsram[(context->address/2) & 63] = context->dma_val; | 423 context->vsram[(context->address/2) & 63] = context->dma_val; |
476 } | 476 } |
477 dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; | 477 dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; |
478 context->regs[REG_DMALEN_H] = dma_len >> 8; | 478 context->regs[REG_DMALEN_H] = dma_len >> 8; |
479 context->regs[REG_DMALEN_L] = dma_len; | 479 context->regs[REG_DMALEN_L] = dma_len; |
480 if (!dma_len) { | 480 if (!dma_len) { |
481 printf("DMA end at cycle %d\n", context->cycles); | |
481 context->flags &= ~FLAG_DMA_RUN; | 482 context->flags &= ~FLAG_DMA_RUN; |
482 } | 483 } |
483 } | 484 } |
484 } else { | 485 } else { |
485 fifo_entry * start = (context->fifo_end - FIFO_SIZE); | 486 fifo_entry * start = (context->fifo_end - FIFO_SIZE); |
486 if (context->fifo_cur != start && start->cycle <= context->cycles) { | 487 if (context->fifo_cur != start && start->cycle <= context->cycles) { |
487 if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START)) { | 488 if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { |
489 printf("DMA fill started at %d\n", context->cycles); | |
488 context->flags |= FLAG_DMA_RUN; | 490 context->flags |= FLAG_DMA_RUN; |
489 context->dma_val = start->value; | 491 context->dma_val = start->value; |
490 context->address = start->address; //undo auto-increment | 492 context->address = start->address; //undo auto-increment |
491 context->dma_cd = context->cd; | 493 context->dma_cd = context->cd; |
492 } else { | 494 } else { |
573 uint16_t line_offset, offset, mask; | 575 uint16_t line_offset, offset, mask; |
574 if (context->latched_mode & BIT_H40) { | 576 if (context->latched_mode & BIT_H40) { |
575 address &= 0xF000; | 577 address &= 0xF000; |
576 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; | 578 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; |
577 mask = 0x7F; | 579 mask = 0x7F; |
578 | 580 |
579 } else { | 581 } else { |
580 address &= 0xF800; | 582 address &= 0xF800; |
581 line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF; | 583 line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF; |
582 mask = 0x3F; | 584 mask = 0x3F; |
583 } | 585 } |
749 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); | 751 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); |
750 a_src = DBG_SRC_A; | 752 a_src = DBG_SRC_A; |
751 } | 753 } |
752 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); | 754 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); |
753 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); | 755 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); |
754 | 756 |
755 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { | 757 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { |
756 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { | 758 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { |
757 uint8_t pixel; | 759 uint8_t pixel; |
758 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); | 760 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); |
759 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); | 761 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); |
1400 inccycles = MCLKS_SLOT_H32; | 1402 inccycles = MCLKS_SLOT_H32; |
1401 slot = linecyc/MCLKS_SLOT_H32; | 1403 slot = linecyc/MCLKS_SLOT_H32; |
1402 } | 1404 } |
1403 if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { | 1405 if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { |
1404 //first sort-of active line is treated as 255 internally | 1406 //first sort-of active line is treated as 255 internally |
1405 //it's used for gathering sprite info for line | 1407 //it's used for gathering sprite info for line |
1406 line = (line - 1) & 0xFF; | 1408 line = (line - 1) & 0xFF; |
1407 | 1409 |
1408 //Convert to slot number | 1410 //Convert to slot number |
1409 if (context->latched_mode & BIT_H40){ | 1411 if (context->latched_mode & BIT_H40){ |
1410 vdp_h40(line, slot, context); | 1412 vdp_h40(line, slot, context); |
1411 } else { | 1413 } else { |
1412 vdp_h32(line, slot, context); | 1414 vdp_h32(line, slot, context); |
1456 } | 1458 } |
1457 } | 1459 } |
1458 | 1460 |
1459 int vdp_control_port_write(vdp_context * context, uint16_t value) | 1461 int vdp_control_port_write(vdp_context * context, uint16_t value) |
1460 { | 1462 { |
1461 //printf("control port write: %X\n", value); | 1463 printf("control port write: %X at %d\n", value, context->cycles); |
1462 if (context->flags & FLAG_DMA_RUN) { | 1464 if (context->flags & FLAG_DMA_RUN) { |
1463 return -1; | 1465 return -1; |
1464 } | 1466 } |
1465 if (context->flags & FLAG_PENDING) { | 1467 if (context->flags & FLAG_PENDING) { |
1466 context->address = (context->address & 0x3FFF) | (value << 14); | 1468 context->address = (context->address & 0x3FFF) | (value << 14); |
1467 context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); | 1469 context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); |
1468 context->flags &= ~FLAG_PENDING; | 1470 context->flags &= ~FLAG_PENDING; |
1469 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); | 1471 printf("New Address: %X, New CD: %X\n", context->address, context->cd); |
1470 if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { | 1472 if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { |
1471 // | 1473 // |
1472 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { | 1474 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { |
1473 //DMA copy or 68K -> VDP, transfer starts immediately | 1475 //DMA copy or 68K -> VDP, transfer starts immediately |
1474 context->flags |= FLAG_DMA_RUN; | 1476 context->flags |= FLAG_DMA_RUN; |
1475 context->dma_cd = context->cd; | 1477 context->dma_cd = context->cd; |
1478 printf("DMA start at cycle %d\n", context->cycles); | |
1476 if (!(context->regs[REG_DMASRC_H] & 0x80)) { | 1479 if (!(context->regs[REG_DMASRC_H] & 0x80)) { |
1477 //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]); | 1480 //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]); |
1478 return 1; | 1481 return 1; |
1479 } else { | 1482 } else { |
1480 //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]); | 1483 //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]); |
1481 } | 1484 } |
1482 } else { | 1485 } else { |
1483 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); | 1486 printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); |
1484 } | 1487 } |
1485 } | 1488 } |
1486 } else { | 1489 } else { |
1487 if ((value & 0xC000) == 0x8000) { | 1490 if ((value & 0xC000) == 0x8000) { |
1488 //Register write | 1491 //Register write |
1489 uint8_t reg = (value >> 8) & 0x1F; | 1492 uint8_t reg = (value >> 8) & 0x1F; |
1490 if (reg < VDP_REGS) { | 1493 if (reg < VDP_REGS) { |
1491 //printf("register %d set to %X\n", reg, value & 0xFF); | 1494 printf("register %d set to %X\n", reg, value & 0xFF); |
1492 context->regs[reg] = value; | 1495 context->regs[reg] = value; |
1493 if (reg == REG_MODE_2) { | 1496 if (reg == REG_MODE_2) { |
1494 //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); | 1497 //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); |
1495 } | 1498 } |
1496 if (reg == REG_MODE_4) { | 1499 if (reg == REG_MODE_4) { |
1509 return 0; | 1512 return 0; |
1510 } | 1513 } |
1511 | 1514 |
1512 int vdp_data_port_write(vdp_context * context, uint16_t value) | 1515 int vdp_data_port_write(vdp_context * context, uint16_t value) |
1513 { | 1516 { |
1514 //printf("data port write: %X\n", value); | 1517 printf("data port write: %X at %d\n", value, context->cycles); |
1515 if (context->flags & FLAG_DMA_RUN) { | 1518 if (context->flags & FLAG_DMA_RUN) { |
1516 return -1; | 1519 return -1; |
1517 } | 1520 } |
1518 if (!(context->cd & 1)) { | 1521 if (!(context->cd & 1)) { |
1519 //ignore writes when cd is configured for read | 1522 //ignore writes when cd is configured for read |