#include #include #include "defs.h" #include "cpu.h" #include "cpuregs.h" #include "hw.h" #include "regs.h" #include "lcd.h" #include "rtc.h" #include "mem.h" #include "sound.h" #ifdef IS_LITTLE_ENDIAN #define LIL(x) (x) #else #define LIL(x) ((x<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|(x>>24)) #endif #define I1(s, p) { 1, s, p } #define I2(s, p) { 2, s, p } #define I4(s, p) { 4, s, p } #define R(r) I1(#r, &R_##r) #define NOSAVE { -1, "\0\0\0\0", 0 } #define END { 0, "\0\0\0\0", 0 } struct svar { int len; char key[4]; void *ptr; }; static int ver; static int sramblock, iramblock, vramblock; static int hramofs, hiofs, palofs, oamofs, wavofs; struct svar svars[] = { I4("GbSs", &ver), I2("PC ", &PC), I2("SP ", &SP), I2("BC ", &BC), I2("DE ", &DE), I2("HL ", &HL), I2("AF ", &AF), I4("IME ", &cpu.ime), I4("ima ", &cpu.ima), I4("spd ", &cpu.speed), I4("halt", &cpu.halt), I4("div ", &cpu.div), I4("tim ", &cpu.tim), I4("lcdc", &cpu.lcdc), I4("snd ", &cpu.snd), I1("ints", &hw.ilines), I1("pad ", &hw.pad), I4("cgb ", &hw.cgb), I4("gba ", &hw.gba), I4("mbcm", &mbc.model), I4("romb", &mbc.rombank), I4("ramb", &mbc.rambank), I4("enab", &mbc.enableram), I4("batt", &mbc.batt), I4("rtcR", &rtc.sel), I4("rtcL", &rtc.latch), I4("rtcC", &rtc.carry), I4("rtcS", &rtc.stop), I4("rtcd", &rtc.d), I4("rtch", &rtc.h), I4("rtcm", &rtc.m), I4("rtcs", &rtc.s), I4("rtct", &rtc.t), I1("rtR8", &rtc.regs[0]), I1("rtR9", &rtc.regs[1]), I1("rtRA", &rtc.regs[2]), I1("rtRB", &rtc.regs[3]), I1("rtRC", &rtc.regs[4]), I4("S1on", &snd.ch[0].on), I4("S1p ", &snd.ch[0].pos), I4("S1c ", &snd.ch[0].cnt), I4("S1ec", &snd.ch[0].encnt), I4("S1sc", &snd.ch[0].swcnt), I4("S1sf", &snd.ch[0].swfreq), I4("S2on", &snd.ch[1].on), I4("S2p ", &snd.ch[1].pos), I4("S2c ", &snd.ch[1].cnt), I4("S2ec", &snd.ch[1].encnt), I4("S3on", &snd.ch[2].on), I4("S3p ", &snd.ch[2].pos), I4("S3c ", &snd.ch[2].cnt), I4("S4on", &snd.ch[3].on), I4("S4p ", &snd.ch[3].pos), I4("S4c ", &snd.ch[3].cnt), I4("S4ec", &snd.ch[3].encnt), I4("hdma", &hw.hdma), I4("sram", &sramblock), I4("iram", &iramblock), I4("vram", &vramblock), I4("hi ", &hiofs), I4("pal ", &palofs), I4("oam ", &oamofs), I4("wav ", &wavofs), /* NOSAVE is a special code to prevent the rest of the table * from being saved, used to support old stuff for backwards * compatibility... */ NOSAVE, /* the following are obsolete as of 0x104 */ I4("hram", &hramofs), R(P1), R(SB), R(SC), R(DIV), R(TIMA), R(TMA), R(TAC), R(IE), R(IF), R(LCDC), R(STAT), R(LY), R(LYC), R(SCX), R(SCY), R(WX), R(WY), R(BGP), R(OBP0), R(OBP1), R(DMA), R(VBK), R(SVBK), R(KEY1), R(BCPS), R(BCPD), R(OCPS), R(OCPD), R(NR10), R(NR11), R(NR12), R(NR13), R(NR14), R(NR21), R(NR22), R(NR23), R(NR24), R(NR30), R(NR31), R(NR32), R(NR33), R(NR34), R(NR41), R(NR42), R(NR43), R(NR44), R(NR50), R(NR51), R(NR52), I1("DMA1", &R_HDMA1), I1("DMA2", &R_HDMA2), I1("DMA3", &R_HDMA3), I1("DMA4", &R_HDMA4), I1("DMA5", &R_HDMA5), END }; void loadstate(FILE *f) { int i, j; byte buf[4096]; un32 (*header)[2] = (un32 (*)[2])buf; un32 d; int irl = hw.cgb ? 8 : 2; int vrl = hw.cgb ? 4 : 2; int srl = mbc.ramsize << 1; ver = hramofs = hiofs = palofs = oamofs = wavofs = 0; fseek(f, 0, SEEK_SET); fread(buf, 4096, 1, f); for (j = 0; header[j][0]; j++) { for (i = 0; svars[i].ptr; i++) { if (header[j][0] != *(un32 *)svars[i].key) continue; d = LIL(header[j][1]); switch (svars[i].len) { case 1: *(byte *)svars[i].ptr = d; break; case 2: *(un16 *)svars[i].ptr = d; break; case 4: *(un32 *)svars[i].ptr = d; break; } break; } } /* obsolete as of version 0x104 */ if (hramofs) memcpy(ram.hi+128, buf+hramofs, 127); if (hiofs) memcpy(ram.hi, buf+hiofs, sizeof ram.hi); if (palofs) memcpy(lcd.pal, buf+palofs, sizeof lcd.pal); if (oamofs) memcpy(lcd.oam.mem, buf+oamofs, sizeof lcd.oam); if (wavofs) memcpy(snd.wave, buf+wavofs, sizeof snd.wave); else memcpy(snd.wave, ram.hi+0x30, 16); /* patch data from older files */ fseek(f, iramblock<<12, SEEK_SET); fread(ram.ibank, 4096, irl, f); fseek(f, vramblock<<12, SEEK_SET); fread(lcd.vbank, 4096, vrl, f); fseek(f, sramblock<<12, SEEK_SET); fread(ram.sbank, 4096, srl, f); } void savestate(FILE *f) { int i; byte buf[4096]; un32 (*header)[2] = (un32 (*)[2])buf; un32 d = 0; int irl = hw.cgb ? 8 : 2; int vrl = hw.cgb ? 4 : 2; int srl = mbc.ramsize << 1; ver = 0x105; iramblock = 1; vramblock = 1+irl; sramblock = 1+irl+vrl; wavofs = 4096 - 784; hiofs = 4096 - 768; palofs = 4096 - 512; oamofs = 4096 - 256; memset(buf, 0, sizeof buf); for (i = 0; svars[i].len > 0; i++) { header[i][0] = *(un32 *)svars[i].key; switch (svars[i].len) { case 1: d = *(byte *)svars[i].ptr; break; case 2: d = *(un16 *)svars[i].ptr; break; case 4: d = *(un32 *)svars[i].ptr; break; } header[i][1] = LIL(d); } header[i][0] = header[i][1] = 0; memcpy(buf+hiofs, ram.hi, sizeof ram.hi); memcpy(buf+palofs, lcd.pal, sizeof lcd.pal); memcpy(buf+oamofs, lcd.oam.mem, sizeof lcd.oam); memcpy(buf+wavofs, snd.wave, sizeof snd.wave); fseek(f, 0, SEEK_SET); fwrite(buf, 4096, 1, f); fseek(f, iramblock<<12, SEEK_SET); fwrite(ram.ibank, 4096, irl, f); fseek(f, vramblock<<12, SEEK_SET); fwrite(lcd.vbank, 4096, vrl, f); fseek(f, sramblock<<12, SEEK_SET); fwrite(ram.sbank, 4096, srl, f); }