comparison vdp.c @ 451:b7c3b2d22858

Added support for saving savestates. Added gst savestate format test harness
author Mike Pavone <pavone@retrodev.com>
date Fri, 26 Jul 2013 19:55:04 -0700
parents b3cee2fe690b
children 608815ab4ff2
comparison
equal deleted inserted replaced
448:e85a107e6ec0 451:b7c3b2d22858
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;
573 uint16_t line_offset, offset, mask; 573 uint16_t line_offset, offset, mask;
574 if (context->latched_mode & BIT_H40) { 574 if (context->latched_mode & BIT_H40) {
575 address &= 0xF000; 575 address &= 0xF000;
576 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; 576 line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF;
577 mask = 0x7F; 577 mask = 0x7F;
578 578
579 } else { 579 } else {
580 address &= 0xF800; 580 address &= 0xF800;
581 line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF; 581 line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF;
582 mask = 0x3F; 582 mask = 0x3F;
583 } 583 }
749 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); 749 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF);
750 a_src = DBG_SRC_A; 750 a_src = DBG_SRC_A;
751 } 751 }
752 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); 752 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF);
753 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); 753 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
754 754
755 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { 755 if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
756 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { 756 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) {
757 uint8_t pixel; 757 uint8_t pixel;
758 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); 758 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); 759 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK);
1400 inccycles = MCLKS_SLOT_H32; 1400 inccycles = MCLKS_SLOT_H32;
1401 slot = linecyc/MCLKS_SLOT_H32; 1401 slot = linecyc/MCLKS_SLOT_H32;
1402 } 1402 }
1403 if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { 1403 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 1404 //first sort-of active line is treated as 255 internally
1405 //it's used for gathering sprite info for line 1405 //it's used for gathering sprite info for line
1406 line = (line - 1) & 0xFF; 1406 line = (line - 1) & 0xFF;
1407 1407
1408 //Convert to slot number 1408 //Convert to slot number
1409 if (context->latched_mode & BIT_H40){ 1409 if (context->latched_mode & BIT_H40){
1410 vdp_h40(line, slot, context); 1410 vdp_h40(line, slot, context);
1411 } else { 1411 } else {
1412 vdp_h32(line, slot, context); 1412 vdp_h32(line, slot, context);
1787 } else if(int_num ==4) { 1787 } else if(int_num ==4) {
1788 context->flags2 &= ~FLAG2_HINT_PENDING; 1788 context->flags2 &= ~FLAG2_HINT_PENDING;
1789 } 1789 }
1790 } 1790 }
1791 1791
1792 #define GST_VDP_REGS 0xFA
1793 #define GST_VDP_MEM 0x12478
1794
1795 uint8_t vdp_load_gst(vdp_context * context, FILE * state_file)
1796 {
1797 uint8_t tmp_buf[CRAM_SIZE*2];
1798 fseek(state_file, GST_VDP_REGS, SEEK_SET);
1799 if (fread(context->regs, 1, VDP_REGS, state_file) != VDP_REGS) {
1800 fputs("Failed to read VDP registers from savestate\n", stderr);
1801 return 0;
1802 }
1803 context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
1804 if (!context->double_res) {
1805 context->framebuf = context->oddbuf;
1806 }
1807 latch_mode(context);
1808 if (fread(tmp_buf, 1, sizeof(tmp_buf), state_file) != sizeof(tmp_buf)) {
1809 fputs("Failed to read CRAM from savestate\n", stderr);
1810 return 0;
1811 }
1812 for (int i = 0; i < CRAM_SIZE; i++) {
1813 uint16_t value;
1814 context->cram[i] = value = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
1815 context->colors[i] = color_map[value & 0xEEE];
1816 context->colors[i + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW];
1817 context->colors[i + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT];
1818 }
1819 if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) {
1820 fputs("Failed to read VSRAM from savestate\n", stderr);
1821 return 0;
1822 }
1823 for (int i = 0; i < VSRAM_SIZE; i++) {
1824 context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
1825 }
1826 fseek(state_file, GST_VDP_MEM, SEEK_SET);
1827 if (fread(context->vdpmem, 1, VRAM_SIZE, state_file) != VRAM_SIZE) {
1828 fputs("Failed to read VRAM from savestate\n", stderr);
1829 return 0;
1830 }
1831 return 1;
1832 }
1833
1834 void vdp_save_state(vdp_context * context, FILE * outfile)
1835 {
1836 uint8_t tmp_buf[CRAM_SIZE*2];
1837 fseek(outfile, GST_VDP_REGS, SEEK_SET);
1838 fwrite(context->regs, 1, VDP_REGS, outfile);
1839 for (int i = 0; i < CRAM_SIZE; i++) {
1840 tmp_buf[i*2] = context->cram[i];
1841 tmp_buf[i*2+1] = context->cram[i] >> 8;
1842 }
1843 fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile);
1844 for (int i = 0; i < VSRAM_SIZE; i++) {
1845 tmp_buf[i*2] = context->vsram[i];
1846 tmp_buf[i*2+1] = context->vsram[i] >> 8;
1847 }
1848 fwrite(tmp_buf, 2, VSRAM_SIZE, outfile);
1849 fseek(outfile, GST_VDP_MEM, SEEK_SET);
1850 fwrite(context->vdpmem, 1, VRAM_SIZE, outfile);
1851 }
1852