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 {