Mercurial > repos > blastem
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 } |