Mercurial > repos > blastem
comparison vdp.c @ 413:36fbbced25c2
Initial work on interlace
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 22 Jun 2013 21:19:43 -0700 |
parents | f8c6f8684cd6 |
children | 51ee0f117365 |
comparison
equal
deleted
inserted
replaced
412:00d5a2b532f4 | 413:36fbbced25c2 |
---|---|
7 #define PAL_ACTIVE 241 | 7 #define PAL_ACTIVE 241 |
8 #define BUF_BIT_PRIORITY 0x40 | 8 #define BUF_BIT_PRIORITY 0x40 |
9 #define MAP_BIT_PRIORITY 0x8000 | 9 #define MAP_BIT_PRIORITY 0x8000 |
10 #define MAP_BIT_H_FLIP 0x800 | 10 #define MAP_BIT_H_FLIP 0x800 |
11 #define MAP_BIT_V_FLIP 0x1000 | 11 #define MAP_BIT_V_FLIP 0x1000 |
12 | |
13 //Mode reg 1 | |
14 #define BIT_HINT_EN 0x10 | |
15 #define BIT_PAL_SEL 0x04 | |
16 #define BIT_HVC_LATCH 0x02 | |
17 #define BIT_DISP_DIS 0x01 | |
18 | |
19 //Mode reg 2 | |
20 #define BIT_DISP_EN 0x40 | |
21 #define BIT_VINT_EN 0x20 | |
22 #define BIT_DMA_ENABLE 0x10 | |
23 #define BIT_PAL 0x08 | |
24 #define BIT_MODE_5 0x04 | |
25 | |
26 //Mode reg 3 | |
27 #define BIT_EINT_EN 0x10 | |
28 #define BIT_VSCROLL 0x04 | |
29 | |
30 //Mode reg 4 | |
31 #define BIT_H40 0x01 | |
32 #define BIT_HILIGHT 0x8 | |
33 | 12 |
34 #define SCROLL_BUFFER_SIZE 32 | 13 #define SCROLL_BUFFER_SIZE 32 |
35 #define SCROLL_BUFFER_DRAW 16 | 14 #define SCROLL_BUFFER_DRAW 16 |
36 | 15 |
37 #define FIFO_SIZE 4 | 16 #define FIFO_SIZE 4 |
50 void init_vdp_context(vdp_context * context) | 29 void init_vdp_context(vdp_context * context) |
51 { | 30 { |
52 memset(context, 0, sizeof(*context)); | 31 memset(context, 0, sizeof(*context)); |
53 context->vdpmem = malloc(VRAM_SIZE); | 32 context->vdpmem = malloc(VRAM_SIZE); |
54 memset(context->vdpmem, 0, VRAM_SIZE); | 33 memset(context->vdpmem, 0, VRAM_SIZE); |
55 context->framebuf = malloc(FRAMEBUF_SIZE); | 34 context->oddbuf = context->framebuf = malloc(FRAMEBUF_SIZE); |
56 memset(context->framebuf, 0, FRAMEBUF_SIZE); | 35 memset(context->framebuf, 0, FRAMEBUF_SIZE); |
36 context->evenbuf = malloc(FRAMEBUF_SIZE); | |
37 memset(context->evenbuf, 0, FRAMEBUF_SIZE); | |
57 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); | 38 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); |
58 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); | 39 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); |
59 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; | 40 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; |
60 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; | 41 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; |
61 context->sprite_draws = MAX_DRAWS; | 42 context->sprite_draws = MAX_DRAWS; |
156 void scan_sprite_table(uint32_t line, vdp_context * context) | 137 void scan_sprite_table(uint32_t line, vdp_context * context) |
157 { | 138 { |
158 if (context->sprite_index && context->slot_counter) { | 139 if (context->sprite_index && context->slot_counter) { |
159 line += 1; | 140 line += 1; |
160 line &= 0xFF; | 141 line &= 0xFF; |
142 uint16_t ymask, ymin; | |
143 uint8_t height_mult; | |
144 if (context->double_res) { | |
145 line *= 2; | |
146 if (context->framebuf != context->oddbuf) { | |
147 line++; | |
148 } | |
149 ymask = 0x3FF; | |
150 ymin = 256; | |
151 height_mult = 16; | |
152 } else { | |
153 ymask = 0x1FF; | |
154 ymin = 128; | |
155 height_mult = 8; | |
156 } | |
161 context->sprite_index &= 0x7F; | 157 context->sprite_index &= 0x7F; |
162 if (context->latched_mode & BIT_H40) { | 158 if (context->latched_mode & BIT_H40) { |
163 if (context->sprite_index >= MAX_SPRITES_FRAME) { | 159 if (context->sprite_index >= MAX_SPRITES_FRAME) { |
164 context->sprite_index = 0; | 160 context->sprite_index = 0; |
165 return; | 161 return; |
169 return; | 165 return; |
170 } | 166 } |
171 //TODO: Read from SAT cache rather than from VRAM | 167 //TODO: Read from SAT cache rather than from VRAM |
172 uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9; | 168 uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9; |
173 uint16_t address = context->sprite_index * 8 + sat_address; | 169 uint16_t address = context->sprite_index * 8 + sat_address; |
174 line += 128; | 170 line += ymin; |
175 uint16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; | 171 uint16_t y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; |
176 uint8_t height = ((context->vdpmem[address+2] & 0x3) + 1) * 8; | 172 uint8_t height = ((context->vdpmem[address+2] & 0x3) + 1) * height_mult; |
177 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); | 173 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); |
178 if (y <= line && line < (y + height)) { | 174 if (y <= line && line < (y + height)) { |
179 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); | 175 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); |
180 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; | 176 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; |
181 context->sprite_info_list[context->slot_counter].index = context->sprite_index; | 177 context->sprite_info_list[context->slot_counter].index = context->sprite_index; |
182 context->sprite_info_list[context->slot_counter].y = y-128; | 178 context->sprite_info_list[context->slot_counter].y = y-ymin; |
183 } | 179 } |
184 context->sprite_index = context->vdpmem[address+3] & 0x7F; | 180 context->sprite_index = context->vdpmem[address+3] & 0x7F; |
185 if (context->sprite_index && context->slot_counter) | 181 if (context->sprite_index && context->slot_counter) |
186 { | 182 { |
187 address = context->sprite_index * 8 + sat_address; | 183 address = context->sprite_index * 8 + sat_address; |
188 y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; | 184 y = ((context->vdpmem[address] & 0x3) << 8 | context->vdpmem[address+1]) & 0x1FF; |
189 height = ((context->vdpmem[address+2] & 0x3) + 1) * 8; | 185 height = ((context->vdpmem[address+2] & 0x3) + 1) * height_mult; |
190 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); | 186 //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height); |
191 if (y <= line && line < (y + height)) { | 187 if (y <= line && line < (y + height)) { |
192 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); | 188 //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line); |
193 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; | 189 context->sprite_info_list[--(context->slot_counter)].size = context->vdpmem[address+2]; |
194 context->sprite_info_list[context->slot_counter].index = context->sprite_index; | 190 context->sprite_info_list[context->slot_counter].index = context->sprite_index; |
195 context->sprite_info_list[context->slot_counter].y = y-128; | 191 context->sprite_info_list[context->slot_counter].y = y-ymin; |
196 } | 192 } |
197 context->sprite_index = context->vdpmem[address+3] & 0x7F; | 193 context->sprite_index = context->vdpmem[address+3] & 0x7F; |
198 } | 194 } |
199 } | 195 } |
200 } | 196 } |
207 line &= 0xFF; | 203 line &= 0xFF; |
208 //in tiles | 204 //in tiles |
209 uint8_t width = ((context->sprite_info_list[context->cur_slot].size >> 2) & 0x3) + 1; | 205 uint8_t width = ((context->sprite_info_list[context->cur_slot].size >> 2) & 0x3) + 1; |
210 //in pixels | 206 //in pixels |
211 uint8_t height = ((context->sprite_info_list[context->cur_slot].size & 0x3) + 1) * 8; | 207 uint8_t height = ((context->sprite_info_list[context->cur_slot].size & 0x3) + 1) * 8; |
208 if (context->double_res) { | |
209 line *= 2; | |
210 if (context->framebuf != context->oddbuf) { | |
211 line++; | |
212 } | |
213 height *= 2; | |
214 } | |
212 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; | 215 uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; |
213 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; | 216 uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; |
214 uint8_t pal_priority = (tileinfo >> 9) & 0x70; | 217 uint8_t pal_priority = (tileinfo >> 9) & 0x70; |
215 uint8_t row; | 218 uint8_t row; |
216 if (tileinfo & MAP_BIT_V_FLIP) { | 219 if (tileinfo & MAP_BIT_V_FLIP) { |
217 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; | 220 row = (context->sprite_info_list[context->cur_slot].y + height - 1) - line; |
218 } else { | 221 } else { |
219 row = line-context->sprite_info_list[context->cur_slot].y; | 222 row = line-context->sprite_info_list[context->cur_slot].y; |
220 } | 223 } |
221 uint16_t address = ((tileinfo & 0x7FF) << 5) + row * 4; | 224 uint16_t address; |
225 if (context->double_res) { | |
226 address = ((tileinfo & 0x3FF) << 6) + row * 4; | |
227 } else { | |
228 address = ((tileinfo & 0x7FF) << 5) + row * 4; | |
229 } | |
222 int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF; | 230 int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF; |
223 if (x) { | 231 if (x) { |
224 context->flags |= FLAG_CAN_MASK; | 232 context->flags |= FLAG_CAN_MASK; |
225 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { | 233 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { |
226 context->flags |= FLAG_MASKED; | 234 context->flags |= FLAG_MASKED; |
430 #define WINDOW_RIGHT 0x80 | 438 #define WINDOW_RIGHT 0x80 |
431 #define WINDOW_DOWN 0x80 | 439 #define WINDOW_DOWN 0x80 |
432 | 440 |
433 void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_t address, uint16_t hscroll_val, vdp_context * context) | 441 void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_t address, uint16_t hscroll_val, vdp_context * context) |
434 { | 442 { |
443 /*if (context->double_res) { | |
444 line *= 2; | |
445 if (context->framebuf != context->oddbuf) { | |
446 line++; | |
447 } | |
448 }*/ | |
435 if (!vsram_off) { | 449 if (!vsram_off) { |
436 uint16_t left_col, right_col; | 450 uint16_t left_col, right_col; |
437 if (context->regs[REG_WINDOW_H] & WINDOW_RIGHT) { | 451 if (context->regs[REG_WINDOW_H] & WINDOW_RIGHT) { |
438 left_col = (context->regs[REG_WINDOW_H] & 0x1F) * 2; | 452 left_col = (context->regs[REG_WINDOW_H] & 0x1F) * 2; |
439 right_col = 42; | 453 right_col = 42; |
491 break; | 505 break; |
492 case 0x30: | 506 case 0x30: |
493 vscroll = 0x3FF; | 507 vscroll = 0x3FF; |
494 break; | 508 break; |
495 } | 509 } |
510 /*if (context->double_res) { | |
511 vscroll <<= 1; | |
512 vscroll |= 1; | |
513 }*/ | |
496 vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? column : 0) + vsram_off] + line); | 514 vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? column : 0) + vsram_off] + line); |
497 context->v_offset = vscroll & 0x7; | 515 context->v_offset = vscroll & 0x7; |
498 //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); | 516 //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); |
499 vscroll /= 8; | 517 vscroll /= 8; |
500 uint16_t hscroll_mask; | 518 uint16_t hscroll_mask; |
543 read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context); | 561 read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context); |
544 } | 562 } |
545 | 563 |
546 void render_map(uint16_t col, uint8_t * tmp_buf, vdp_context * context) | 564 void render_map(uint16_t col, uint8_t * tmp_buf, vdp_context * context) |
547 { | 565 { |
548 uint16_t address = ((col & 0x7FF) << 5); | 566 uint16_t address; |
567 uint8_t shift, add; | |
568 if (context->double_res) { | |
569 address = ((col & 0x3FF) << 6); | |
570 shift = 1; | |
571 add = context->framebuf != context->oddbuf ? 1 : 0; | |
572 } else { | |
573 address = ((col & 0x7FF) << 5); | |
574 shift = 0; | |
575 add = 0; | |
576 } | |
549 if (col & MAP_BIT_V_FLIP) { | 577 if (col & MAP_BIT_V_FLIP) { |
550 address += 28 - 4 * context->v_offset; | 578 address += 28 - 4 * ((context->v_offset << shift) + add); |
551 } else { | 579 } else { |
552 address += 4 * context->v_offset; | 580 address += 4 * ((context->v_offset << shift) + add); |
553 } | 581 } |
554 uint16_t pal_priority = (col >> 9) & 0x70; | 582 uint16_t pal_priority = (col >> 9) & 0x70; |
555 int32_t dir; | 583 int32_t dir; |
556 if (col & MAP_BIT_H_FLIP) { | 584 if (col & MAP_BIT_H_FLIP) { |
557 tmp_buf += 7; | 585 tmp_buf += 7; |
1312 //printf("register %d set to %X\n", reg, value & 0xFF); | 1340 //printf("register %d set to %X\n", reg, value & 0xFF); |
1313 context->regs[reg] = value; | 1341 context->regs[reg] = value; |
1314 if (reg == REG_MODE_2) { | 1342 if (reg == REG_MODE_2) { |
1315 //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); | 1343 //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); |
1316 } | 1344 } |
1345 if (reg == REG_MODE_4) { | |
1346 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); | |
1347 } | |
1317 } | 1348 } |
1318 } else { | 1349 } else { |
1319 context->flags |= FLAG_PENDING; | 1350 context->flags |= FLAG_PENDING; |
1320 context->address = (context->address &0xC000) | (value & 0x3FFF); | 1351 context->address = (context->address &0xC000) | (value & 0x3FFF); |
1321 context->cd = (context->cd &0x3C) | (value >> 14); | 1352 context->cd = (context->cd &0x3C) | (value >> 14); |
1360 } | 1391 } |
1361 if (context->fifo_cur == context->fifo_end) { | 1392 if (context->fifo_cur == context->fifo_end) { |
1362 value |= 0x100; | 1393 value |= 0x100; |
1363 } | 1394 } |
1364 if (context->flags2 & FLAG2_VINT_PENDING) { | 1395 if (context->flags2 & FLAG2_VINT_PENDING) { |
1365 value |- 0x80; | 1396 value |= 0x80; |
1397 } | |
1398 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { | |
1399 value |= 0x10; | |
1366 } | 1400 } |
1367 uint32_t line= context->cycles / MCLKS_LINE; | 1401 uint32_t line= context->cycles / MCLKS_LINE; |
1368 uint32_t linecyc = context->cycles % MCLKS_LINE; | 1402 uint32_t linecyc = context->cycles % MCLKS_LINE; |
1369 if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE)) { | 1403 if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE)) { |
1370 value |= 0x8; | 1404 value |= 0x8; |
1515 if (linecyc > 0x127) { | 1549 if (linecyc > 0x127) { |
1516 linecyc += 170; | 1550 linecyc += 170; |
1517 } | 1551 } |
1518 } | 1552 } |
1519 linecyc &= 0xFF; | 1553 linecyc &= 0xFF; |
1554 if (context->double_res) { | |
1555 line <<= 1; | |
1556 if (line & 0x100) { | |
1557 line |= 1; | |
1558 } | |
1559 } | |
1520 return (line << 8) | linecyc; | 1560 return (line << 8) | linecyc; |
1521 } | 1561 } |
1522 | 1562 |
1523 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) | 1563 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) |
1524 { | 1564 { |