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