comparison blastem.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 e730fc040169
children 608815ab4ff2
comparison
equal deleted inserted replaced
448:e85a107e6ec0 451:b7c3b2d22858
3 #include "z80_to_x86.h" 3 #include "z80_to_x86.h"
4 #include "mem.h" 4 #include "mem.h"
5 #include "vdp.h" 5 #include "vdp.h"
6 #include "render.h" 6 #include "render.h"
7 #include "blastem.h" 7 #include "blastem.h"
8 #include "gst.h"
8 #include <stdio.h> 9 #include <stdio.h>
9 #include <stdlib.h> 10 #include <stdlib.h>
10 #include <string.h> 11 #include <string.h>
11 12
12 #define CARTRIDGE_WORDS 0x200000 13 #define CARTRIDGE_WORDS 0x200000
150 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), 151 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7),
151 v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/ 152 v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/
152 } 153 }
153 154
154 int break_on_sync = 0; 155 int break_on_sync = 0;
156 int save_state = 0;
155 157
156 uint8_t reset = 1; 158 uint8_t reset = 1;
157 uint8_t need_reset = 0; 159 uint8_t need_reset = 0;
158 uint8_t busreq = 0; 160 uint8_t busreq = 0;
159 uint8_t busack = 0; 161 uint8_t busack = 0;
256 if (context->int_ack) { 258 if (context->int_ack) {
257 vdp_int_ack(v_context, context->int_ack); 259 vdp_int_ack(v_context, context->int_ack);
258 context->int_ack = 0; 260 context->int_ack = 0;
259 } 261 }
260 adjust_int_cycle(context, v_context); 262 adjust_int_cycle(context, v_context);
261 if (break_on_sync && address) { 263 if (address) {
262 break_on_sync = 0; 264 if (break_on_sync) {
263 debugger(context, address); 265 break_on_sync = 0;
266 debugger(context, address);
267 }
268 if (save_state) {
269 save_state = 0;
270 while (!z_context->pc)
271 {
272 sync_z80(z_context, z_context->current_cycle * MCLKS_PER_Z80 + MCLKS_PER_Z80);
273 }
274 save_gst(gen, "savestate.gst", address);
275 }
264 } 276 }
265 return context; 277 return context;
266 } 278 }
267 279
268 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) 280 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
1463 } 1475 }
1464 } 1476 }
1465 return context; 1477 return context;
1466 } 1478 }
1467 1479
1468 #define GST_68K_REGS 0x80
1469 #define GST_68K_REG_SIZE (0xDA-GST_68K_REGS)
1470 #define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS)
1471 #define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS)
1472 #define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS)
1473 #define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS)
1474 #define GST_68K_RAM 0x2478
1475 #define GST_Z80_REGS 0x404
1476 #define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS)
1477 #define GST_Z80_RAM 0x474
1478
1479 uint32_t read_le_32(uint8_t * data)
1480 {
1481 return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
1482 }
1483
1484 uint16_t read_le_16(uint8_t * data)
1485 {
1486 return data[1] << 8 | data[0];
1487 }
1488
1489 uint16_t read_be_16(uint8_t * data)
1490 {
1491 return data[0] << 8 | data[1];
1492 }
1493
1494 uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile)
1495 {
1496 uint8_t buffer[4096];
1497 fseek(gstfile, GST_68K_REGS, SEEK_SET);
1498 if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
1499 fputs("Failed to read 68K registers from savestate\n", stderr);
1500 return 0;
1501 }
1502 uint8_t * curpos = buffer;
1503 for (int i = 0; i < 8; i++) {
1504 context->dregs[i] = read_le_32(curpos);
1505 curpos += sizeof(uint32_t);
1506 }
1507 for (int i = 0; i < 8; i++) {
1508 context->aregs[i] = read_le_32(curpos);
1509 curpos += sizeof(uint32_t);
1510 }
1511 uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET);
1512 uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET);
1513 context->status = sr >> 8;
1514 for (int flag = 4; flag >= 0; flag--) {
1515 context->flags[flag] = sr & 1;
1516 sr >>= 1;
1517 }
1518 if (context->status & (1 << 5)) {
1519 context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET);
1520 } else {
1521 context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET);
1522 }
1523 fseek(gstfile, GST_68K_RAM, SEEK_SET);
1524 for (int i = 0; i < (32*1024);) {
1525 if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
1526 fputs("Failed to read 68K RAM from savestate\n", stderr);
1527 return 0;
1528 }
1529 for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
1530 context->mem_pointers[1][i++] = read_be_16(curpos);
1531 }
1532 }
1533 return pc;
1534 }
1535
1536 uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
1537 {
1538 uint8_t regdata[GST_Z80_REG_SIZE];
1539 fseek(gstfile, GST_Z80_REGS, SEEK_SET);
1540 if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
1541 fputs("Failed to read Z80 registers from savestate\n", stderr);
1542 return 0;
1543 }
1544 uint8_t * curpos = regdata;
1545 uint8_t f = *(curpos++);
1546 context->flags[ZF_C] = f & 1;
1547 f >>= 1;
1548 context->flags[ZF_N] = f & 1;
1549 f >>= 1;
1550 context->flags[ZF_PV] = f & 1;
1551 f >>= 2;
1552 context->flags[ZF_H] = f & 1;
1553 f >>= 2;
1554 context->flags[ZF_Z] = f & 1;
1555 f >>= 1;
1556 context->flags[ZF_S] = f;
1557
1558 context->regs[Z80_A] = *curpos;
1559 curpos += 3;
1560 for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
1561 context->regs[reg++] = *(curpos++);
1562 context->regs[reg] = *curpos;
1563 curpos += 3;
1564 }
1565 uint16_t pc = read_le_16(curpos);
1566 curpos += 4;
1567 context->sp = read_le_16(curpos);
1568 curpos += 4;
1569 f = *(curpos++);
1570 context->alt_flags[ZF_C] = f & 1;
1571 f >>= 1;
1572 context->alt_flags[ZF_N] = f & 1;
1573 f >>= 1;
1574 context->alt_flags[ZF_PV] = f & 1;
1575 f >>= 2;
1576 context->alt_flags[ZF_H] = f & 1;
1577 f >>= 2;
1578 context->alt_flags[ZF_Z] = f & 1;
1579 f >>= 1;
1580 context->alt_flags[ZF_S] = f;
1581 context->alt_regs[Z80_A] = *curpos;
1582 curpos += 3;
1583 for (int reg = Z80_C; reg <= Z80_H; reg++) {
1584 context->alt_regs[reg++] = *(curpos++);
1585 context->alt_regs[reg] = *curpos;
1586 curpos += 3;
1587 }
1588 context->regs[Z80_I] = *curpos;
1589 curpos += 2;
1590 context->iff1 = context->iff2 = *curpos;
1591 curpos += 2;
1592 reset = !*(curpos++);
1593 busreq = *curpos;
1594 curpos += 3;
1595 uint32_t bank = read_le_32(curpos);
1596 if (bank < 0x400000) {
1597 context->mem_pointers[1] = context->mem_pointers[2] + bank;
1598 } else {
1599 context->mem_pointers[1] = NULL;
1600 }
1601 context->bank_reg = bank >> 15;
1602 fseek(gstfile, GST_Z80_RAM, SEEK_SET);
1603 if(fread(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) {
1604 fputs("Failed to read Z80 RAM from savestate\n", stderr);
1605 return 0;
1606 }
1607 context->native_pc = z80_get_native_address_trans(context, pc);
1608 return 1;
1609 }
1610
1611 uint32_t load_gst(genesis_context * gen, char * fname)
1612 {
1613 FILE * gstfile = fopen(fname, "rb");
1614 if (!gstfile) {
1615 fprintf(stderr, "Could not open file %s for reading\n", fname);
1616 goto error;
1617 }
1618 char ident[5];
1619 if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) {
1620 fprintf(stderr, "Could not read ident code from %s\n", fname);
1621 goto error_close;
1622 }
1623 if (memcmp(ident, "GST\xE0\x40", 3) != 0) {
1624 fprintf(stderr, "%s doesn't appear to be a GST savestate. The ident code is %c%c%c\\x%X\\x%X instead of GST\\xE0\\x40.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]);
1625 goto error_close;
1626 }
1627 uint32_t pc = m68k_load_gst(gen->m68k, gstfile);
1628 if (!pc) {
1629 goto error_close;
1630 }
1631 if (!vdp_load_gst(gen->vdp, gstfile)) {
1632 goto error_close;
1633 }
1634 if (!ym_load_gst(gen->ym, gstfile)) {
1635 goto error_close;
1636 }
1637 if (!z80_load_gst(gen->z80, gstfile)) {
1638 goto error_close;
1639 }
1640 gen->ports[0].control = 0x40;
1641 gen->ports[1].control = 0x40;
1642 adjust_int_cycle(gen->m68k, gen->vdp);
1643 fclose(gstfile);
1644 return pc;
1645
1646 error_close:
1647 fclose(gstfile);
1648 error:
1649 return 0;
1650 }
1651
1652 #define ROM_END 0x1A4 1480 #define ROM_END 0x1A4
1653 #define RAM_ID 0x1B0 1481 #define RAM_ID 0x1B0
1654 #define RAM_FLAGS 0x1B2 1482 #define RAM_FLAGS 0x1B2
1655 #define RAM_START 0x1B4 1483 #define RAM_START 0x1B4
1656 #define RAM_END 0x1B8 1484 #define RAM_END 0x1B8
1803 address = cart[2] << 16 | cart[3]; 1631 address = cart[2] << 16 | cart[3];
1804 translate_m68k_stream(address, &context); 1632 translate_m68k_stream(address, &context);
1805 if (statefile) { 1633 if (statefile) {
1806 uint32_t pc = load_gst(gen, statefile); 1634 uint32_t pc = load_gst(gen, statefile);
1807 if (!pc) { 1635 if (!pc) {
1636 fprintf(stderr, "Failed to load save state %s\n", statefile);
1808 exit(1); 1637 exit(1);
1809 } 1638 }
1639 printf("Loaded %s\n", statefile);
1810 if (debug) { 1640 if (debug) {
1811 insert_breakpoint(&context, pc, (uint8_t *)debugger); 1641 insert_breakpoint(&context, pc, (uint8_t *)debugger);
1812 } 1642 }
1643 adjust_int_cycle(gen->m68k, gen->vdp);
1644 gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc);
1813 start_68k_context(&context, pc); 1645 start_68k_context(&context, pc);
1814 } else { 1646 } else {
1815 if (debug) { 1647 if (debug) {
1816 insert_breakpoint(&context, address, (uint8_t *)debugger); 1648 insert_breakpoint(&context, address, (uint8_t *)debugger);
1817 } 1649 }