Mercurial > repos > blastem
comparison blastem.c @ 424:7e8e179116af
Add support for loading GST format savestates
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 29 Jun 2013 17:15:08 -0700 |
parents | 642b2f8aee32 |
children | 8b3ae850d1c4 |
comparison
equal
deleted
inserted
replaced
423:8e136187c0e0 | 424:7e8e179116af |
---|---|
1461 } | 1461 } |
1462 } | 1462 } |
1463 return context; | 1463 return context; |
1464 } | 1464 } |
1465 | 1465 |
1466 #define GST_68K_REGS 0x80 | |
1467 #define GST_68K_REG_SIZE (0xDA-GST_68K_REGS) | |
1468 #define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS) | |
1469 #define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS) | |
1470 #define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS) | |
1471 #define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS) | |
1472 #define GST_68K_RAM 0x2478 | |
1473 #define GST_Z80_REGS 0x404 | |
1474 #define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS) | |
1475 #define GST_Z80_RAM 0x474 | |
1476 | |
1477 uint32_t read_le_32(uint8_t * data) | |
1478 { | |
1479 return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]; | |
1480 } | |
1481 | |
1482 uint16_t read_le_16(uint8_t * data) | |
1483 { | |
1484 return data[1] << 8 | data[0]; | |
1485 } | |
1486 | |
1487 uint16_t read_be_16(uint8_t * data) | |
1488 { | |
1489 return data[0] << 8 | data[1]; | |
1490 } | |
1491 | |
1492 uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile) | |
1493 { | |
1494 uint8_t buffer[4096]; | |
1495 fseek(gstfile, GST_68K_REGS, SEEK_SET); | |
1496 if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) { | |
1497 fputs("Failed to read 68K registers from savestate\n", stderr); | |
1498 return 0; | |
1499 } | |
1500 uint8_t * curpos = buffer; | |
1501 for (int i = 0; i < 8; i++) { | |
1502 context->dregs[i] = read_le_32(curpos); | |
1503 curpos += sizeof(uint32_t); | |
1504 } | |
1505 for (int i = 0; i < 8; i++) { | |
1506 context->aregs[i] = read_le_32(curpos); | |
1507 curpos += sizeof(uint32_t); | |
1508 } | |
1509 uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET); | |
1510 uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET); | |
1511 context->status = sr >> 8; | |
1512 for (int flag = 4; flag >= 0; flag--) { | |
1513 context->flags[flag] = sr & 1; | |
1514 sr >>= 1; | |
1515 } | |
1516 if (context->status & (1 << 5)) { | |
1517 context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET); | |
1518 } else { | |
1519 context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET); | |
1520 } | |
1521 fseek(gstfile, GST_68K_RAM, SEEK_SET); | |
1522 for (int i = 0; i < (32*1024);) { | |
1523 if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) { | |
1524 fputs("Failed to read 68K RAM from savestate\n", stderr); | |
1525 return 0; | |
1526 } | |
1527 for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { | |
1528 context->mem_pointers[1][i++] = read_be_16(curpos); | |
1529 } | |
1530 } | |
1531 return pc; | |
1532 } | |
1533 | |
1534 uint8_t z80_load_gst(z80_context * context, FILE * gstfile) | |
1535 { | |
1536 uint8_t regdata[GST_Z80_REG_SIZE]; | |
1537 fseek(gstfile, GST_Z80_REGS, SEEK_SET); | |
1538 if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { | |
1539 fputs("Failed to read Z80 registers from savestate\n", stderr); | |
1540 return 0; | |
1541 } | |
1542 uint8_t * curpos = regdata; | |
1543 uint8_t f = *(curpos++); | |
1544 context->flags[ZF_C] = f & 1; | |
1545 f >>= 1; | |
1546 context->flags[ZF_N] = f & 1; | |
1547 f >>= 1; | |
1548 context->flags[ZF_PV] = f & 1; | |
1549 f >>= 2; | |
1550 context->flags[ZF_H] = f & 1; | |
1551 f >>= 2; | |
1552 context->flags[ZF_Z] = f & 1; | |
1553 f >>= 1; | |
1554 context->flags[ZF_S] = f; | |
1555 | |
1556 context->regs[Z80_A] = *curpos; | |
1557 curpos += 3; | |
1558 for (int reg = Z80_C; reg <= Z80_IYH; reg++) { | |
1559 context->regs[reg++] = *(curpos++); | |
1560 context->regs[reg] = *curpos; | |
1561 curpos += 3; | |
1562 } | |
1563 uint16_t pc = read_le_16(curpos); | |
1564 curpos += 4; | |
1565 context->sp = read_le_16(curpos); | |
1566 curpos += 4; | |
1567 f = *(curpos++); | |
1568 context->alt_flags[ZF_C] = f & 1; | |
1569 f >>= 1; | |
1570 context->alt_flags[ZF_N] = f & 1; | |
1571 f >>= 1; | |
1572 context->alt_flags[ZF_PV] = f & 1; | |
1573 f >>= 2; | |
1574 context->alt_flags[ZF_H] = f & 1; | |
1575 f >>= 2; | |
1576 context->alt_flags[ZF_Z] = f & 1; | |
1577 f >>= 1; | |
1578 context->alt_flags[ZF_S] = f; | |
1579 context->alt_regs[Z80_A] = *curpos; | |
1580 curpos += 3; | |
1581 for (int reg = Z80_C; reg <= Z80_H; reg++) { | |
1582 context->alt_regs[reg++] = *(curpos++); | |
1583 context->alt_regs[reg] = *curpos; | |
1584 curpos += 3; | |
1585 } | |
1586 context->regs[Z80_I] = *curpos; | |
1587 curpos += 2; | |
1588 context->iff1 = context->iff2 = *curpos; | |
1589 curpos += 2; | |
1590 reset = !*(curpos++); | |
1591 busreq = *curpos; | |
1592 curpos += 3; | |
1593 uint32_t bank = read_le_32(curpos); | |
1594 if (bank < 0x400000) { | |
1595 context->mem_pointers[1] = context->mem_pointers[2] + bank; | |
1596 } else { | |
1597 context->mem_pointers[1] = NULL; | |
1598 } | |
1599 context->bank_reg = bank >> 15; | |
1600 fseek(gstfile, GST_Z80_RAM, SEEK_SET); | |
1601 if(fread(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) { | |
1602 fputs("Failed to read Z80 RAM from savestate\n", stderr); | |
1603 return 0; | |
1604 } | |
1605 context->native_pc = z80_get_native_address_trans(context, pc); | |
1606 return 1; | |
1607 } | |
1608 | |
1609 uint32_t load_gst(genesis_context * gen, char * fname) | |
1610 { | |
1611 FILE * gstfile = fopen(fname, "rb"); | |
1612 if (!gstfile) { | |
1613 fprintf(stderr, "Could not open file %s for reading\n", fname); | |
1614 goto error; | |
1615 } | |
1616 char ident[5]; | |
1617 if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) { | |
1618 fprintf(stderr, "Could not read ident code from %s\n", fname); | |
1619 goto error_close; | |
1620 } | |
1621 if (memcmp(ident, "GST\xE0\x40", 3) != 0) { | |
1622 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]); | |
1623 goto error_close; | |
1624 } | |
1625 uint32_t pc = m68k_load_gst(gen->m68k, gstfile); | |
1626 if (!pc) { | |
1627 goto error_close; | |
1628 } | |
1629 if (!vdp_load_gst(gen->vdp, gstfile)) { | |
1630 goto error_close; | |
1631 } | |
1632 if (!ym_load_gst(gen->ym, gstfile)) { | |
1633 goto error_close; | |
1634 } | |
1635 if (!z80_load_gst(gen->z80, gstfile)) { | |
1636 goto error_close; | |
1637 } | |
1638 gen->ports[0].control = 0x40; | |
1639 gen->ports[1].control = 0x40; | |
1640 adjust_int_cycle(gen->m68k, gen->vdp); | |
1641 fclose(gstfile); | |
1642 return pc; | |
1643 | |
1644 error_close: | |
1645 fclose(gstfile); | |
1646 error: | |
1647 return 0; | |
1648 } | |
1649 | |
1466 #define ROM_END 0x1A4 | 1650 #define ROM_END 0x1A4 |
1467 #define RAM_ID 0x1B0 | 1651 #define RAM_ID 0x1B0 |
1468 #define RAM_FLAGS 0x1B2 | 1652 #define RAM_FLAGS 0x1B2 |
1469 #define RAM_START 0x1B4 | 1653 #define RAM_START 0x1B4 |
1470 #define RAM_END 0x1B8 | 1654 #define RAM_END 0x1B8 |
1500 fwrite(genesis->save_ram, 1, size, f); | 1684 fwrite(genesis->save_ram, 1, size, f); |
1501 fclose(f); | 1685 fclose(f); |
1502 printf("Saved SRAM to %s\n", sram_filename); | 1686 printf("Saved SRAM to %s\n", sram_filename); |
1503 } | 1687 } |
1504 | 1688 |
1505 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) | 1689 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * statefile) |
1506 { | 1690 { |
1507 m68k_context context; | 1691 m68k_context context; |
1508 x86_68k_options opts; | 1692 x86_68k_options opts; |
1509 gen->m68k = &context; | 1693 gen->m68k = &context; |
1510 memmap_chunk memmap[MAX_MAP_CHUNKS]; | 1694 memmap_chunk memmap[MAX_MAP_CHUNKS]; |
1614 context.mem_pointers[2] = initial_mapped; | 1798 context.mem_pointers[2] = initial_mapped; |
1615 context.mem_pointers[3] = (uint16_t *)gen->save_ram; | 1799 context.mem_pointers[3] = (uint16_t *)gen->save_ram; |
1616 uint32_t address; | 1800 uint32_t address; |
1617 address = cart[2] << 16 | cart[3]; | 1801 address = cart[2] << 16 | cart[3]; |
1618 translate_m68k_stream(address, &context); | 1802 translate_m68k_stream(address, &context); |
1619 if (debug) { | 1803 if (statefile) { |
1620 insert_breakpoint(&context, address, (uint8_t *)debugger); | 1804 uint32_t pc = load_gst(gen, statefile); |
1621 } | 1805 if (!pc) { |
1622 m68k_reset(&context); | 1806 exit(1); |
1807 } | |
1808 if (debug) { | |
1809 insert_breakpoint(&context, pc, (uint8_t *)debugger); | |
1810 } | |
1811 start_68k_context(&context, pc); | |
1812 } else { | |
1813 if (debug) { | |
1814 insert_breakpoint(&context, address, (uint8_t *)debugger); | |
1815 } | |
1816 m68k_reset(&context); | |
1817 } | |
1623 } | 1818 } |
1624 | 1819 |
1625 char title[64]; | 1820 char title[64]; |
1626 | 1821 |
1627 #define TITLE_START 0x150 | 1822 #define TITLE_START 0x150 |
1687 int width = -1; | 1882 int width = -1; |
1688 int height = -1; | 1883 int height = -1; |
1689 int debug = 0; | 1884 int debug = 0; |
1690 int ym_log = 0; | 1885 int ym_log = 0; |
1691 FILE *address_log = NULL; | 1886 FILE *address_log = NULL; |
1887 char * statefile; | |
1692 for (int i = 2; i < argc; i++) { | 1888 for (int i = 2; i < argc; i++) { |
1693 if (argv[i][0] == '-') { | 1889 if (argv[i][0] == '-') { |
1694 switch(argv[i][1]) { | 1890 switch(argv[i][1]) { |
1695 case 'd': | 1891 case 'd': |
1696 debug = 1; | 1892 debug = 1; |
1729 break; | 1925 break; |
1730 default: | 1926 default: |
1731 fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); | 1927 fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); |
1732 return 1; | 1928 return 1; |
1733 } | 1929 } |
1930 break; | |
1931 case 's': | |
1932 i++; | |
1933 if (i >= argc) { | |
1934 fputs("-s must be followed by a savestate filename\n", stderr); | |
1935 return 1; | |
1936 } | |
1937 statefile = argv[i]; | |
1734 break; | 1938 break; |
1735 case 'y': | 1939 case 'y': |
1736 ym_log = 1; | 1940 ym_log = 1; |
1737 break; | 1941 break; |
1738 default: | 1942 default: |
1799 if (i < 0) { | 2003 if (i < 0) { |
1800 strcpy(sram_filename + fname_size, ".sram"); | 2004 strcpy(sram_filename + fname_size, ".sram"); |
1801 } | 2005 } |
1802 set_keybindings(); | 2006 set_keybindings(); |
1803 | 2007 |
1804 init_run_cpu(&gen, debug, address_log); | 2008 init_run_cpu(&gen, debug, address_log, statefile); |
1805 return 0; | 2009 return 0; |
1806 } | 2010 } |