Area.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Savestate handling for emulated Sega/Mega CD machine.
  2. // (c) Copyright 2007, Grazvydas "notaz" Ignotas
  3. #include "../PicoInt.h"
  4. // ym2612
  5. #include "../sound/ym2612.h"
  6. // sn76496
  7. extern int *sn76496_regs;
  8. void (*PicoStateProgressCB)(const char *str) = 0;
  9. typedef enum {
  10. CHUNK_M68K = 1,
  11. CHUNK_RAM,
  12. CHUNK_VRAM,
  13. CHUNK_ZRAM,
  14. CHUNK_CRAM, // 5
  15. CHUNK_VSRAM,
  16. CHUNK_MISC,
  17. CHUNK_VIDEO,
  18. CHUNK_Z80,
  19. CHUNK_PSG, // 10
  20. CHUNK_FM,
  21. // CD stuff
  22. CHUNK_S68K,
  23. CHUNK_PRG_RAM,
  24. CHUNK_WORD_RAM,
  25. CHUNK_PCM_RAM, // 15
  26. CHUNK_BRAM,
  27. CHUNK_GA_REGS,
  28. CHUNK_PCM,
  29. CHUNK_CDC,
  30. CHUNK_CDD, // 20
  31. CHUNK_SCD,
  32. CHUNK_RC,
  33. CHUNK_MISC_CD,
  34. } chunk_name_e;
  35. static char *chunk_names[] = {
  36. "Saving.. M68K state",
  37. "Saving.. RAM",
  38. "Saving.. VRAM",
  39. "Saving.. ZRAM",
  40. "Saving.. CRAM", // 5
  41. "Saving.. VSRAM",
  42. "Saving.. emu state",
  43. "Saving.. VIDEO",
  44. "Saving.. Z80 state",
  45. "Saving.. PSG", // 10
  46. "Saving.. FM",
  47. // CD stuff
  48. "Saving.. S68K state",
  49. "Saving.. PRG_RAM",
  50. "Saving.. WORD_RAM",
  51. "Saving.. PCM_RAM", // 15
  52. "Saving.. BRAM",
  53. "Saving.. GATE ARRAY regs",
  54. "Saving.. PCM state",
  55. "Saving.. CDC",
  56. "Saving.. CDD", // 20
  57. "Saving.. SCD",
  58. "Saving.. GFX chip",
  59. "Saving.. MCD state",
  60. };
  61. static int write_chunk(chunk_name_e name, int len, void *data, void *file)
  62. {
  63. size_t bwritten = 0;
  64. bwritten += areaWrite(&name, 1, 1, file);
  65. bwritten += areaWrite(&len, 1, 4, file);
  66. bwritten += areaWrite(data, 1, len, file);
  67. return (bwritten == len + 4 + 1);
  68. }
  69. #define CHECKED_WRITE(name,len,data) \
  70. if (PicoStateProgressCB) PicoStateProgressCB(chunk_names[name]); \
  71. if (!write_chunk(name, len, data, file)) return 1;
  72. #define CHECKED_WRITE_BUFF(name,buff) \
  73. if (PicoStateProgressCB) PicoStateProgressCB(chunk_names[name]); \
  74. if (!write_chunk(name, sizeof(buff), &buff, file)) return 1;
  75. PICO_INTERNAL int PicoCdSaveState(void *file)
  76. {
  77. unsigned char buff[0x60];
  78. void *ym2612_regs = YM2612GetRegs();
  79. areaWrite("PicoSMCD", 1, 8, file);
  80. areaWrite(&PicoVer, 1, 4, file);
  81. memset(buff, 0, sizeof(buff));
  82. PicoAreaPackCpu(buff, 0);
  83. CHECKED_WRITE_BUFF(CHUNK_M68K, buff);
  84. CHECKED_WRITE_BUFF(CHUNK_RAM, Pico.ram);
  85. CHECKED_WRITE_BUFF(CHUNK_VRAM, Pico.vram);
  86. CHECKED_WRITE_BUFF(CHUNK_ZRAM, Pico.zram);
  87. CHECKED_WRITE_BUFF(CHUNK_CRAM, Pico.cram);
  88. CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);
  89. CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);
  90. CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);
  91. if(PicoOpt&7) {
  92. memset(buff, 0, sizeof(buff));
  93. z80_pack(buff);
  94. CHECKED_WRITE_BUFF(CHUNK_Z80, buff);
  95. }
  96. if(PicoOpt&3)
  97. CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);
  98. if(PicoOpt&1)
  99. CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);
  100. if (PicoMCD & 1)
  101. {
  102. Pico_mcd->m.audio_offset = mp3_get_offset();
  103. memset(buff, 0, sizeof(buff));
  104. PicoAreaPackCpu(buff, 1);
  105. if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
  106. wram_1M_to_2M(Pico_mcd->word_ram2M);
  107. Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);
  108. CHECKED_WRITE_BUFF(CHUNK_S68K, buff);
  109. CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);
  110. CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format
  111. CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);
  112. CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);
  113. CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs
  114. CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);
  115. CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);
  116. CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);
  117. CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);
  118. CHECKED_WRITE_BUFF(CHUNK_RC, Pico_mcd->rot_comp);
  119. CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);
  120. if (Pico_mcd->s68k_regs[3]&4) // convert back
  121. wram_2M_to_1M(Pico_mcd->word_ram2M);
  122. }
  123. return 0;
  124. }
  125. static int g_read_offs = 0;
  126. #define R_ERROR_RETURN(error) \
  127. { \
  128. printf("PicoCdLoadState @ %x: " error "\n", g_read_offs); \
  129. return 1; \
  130. }
  131. // when is eof really set?
  132. #define CHECKED_READ(len,data) \
  133. if (areaRead(data, 1, len, file) != len) { \
  134. if (len == 1 && areaEof(file)) return 0; \
  135. R_ERROR_RETURN("areaRead: premature EOF\n"); \
  136. return 1; \
  137. } \
  138. g_read_offs += len;
  139. #define CHECKED_READ2(len2,data) \
  140. if (len2 != len) R_ERROR_RETURN("unexpected len, wanted " #len2); \
  141. CHECKED_READ(len2, data)
  142. #define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);
  143. PICO_INTERNAL int PicoCdLoadState(void *file)
  144. {
  145. unsigned char buff[0x60];
  146. int ver, len;
  147. void *ym2612_regs = YM2612GetRegs();
  148. g_read_offs = 0;
  149. CHECKED_READ(8, buff);
  150. if (strncmp((char *)buff, "PicoSMCD", 8)) R_ERROR_RETURN("bad header");
  151. CHECKED_READ(4, &ver);
  152. while (!areaEof(file))
  153. {
  154. CHECKED_READ(1, buff);
  155. CHECKED_READ(4, &len);
  156. if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
  157. if (buff[0] > CHUNK_FM && !(PicoMCD & 1)) R_ERROR_RETURN("cd chunk in non CD state?");
  158. switch (buff[0])
  159. {
  160. case CHUNK_M68K:
  161. CHECKED_READ_BUFF(buff);
  162. PicoAreaUnpackCpu(buff, 0);
  163. break;
  164. case CHUNK_Z80:
  165. CHECKED_READ_BUFF(buff);
  166. z80_unpack(buff);
  167. break;
  168. case CHUNK_RAM: CHECKED_READ_BUFF(Pico.ram); break;
  169. case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); break;
  170. case CHUNK_ZRAM: CHECKED_READ_BUFF(Pico.zram); break;
  171. case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); break;
  172. case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); break;
  173. case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;
  174. case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;
  175. case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;
  176. case CHUNK_FM:
  177. CHECKED_READ2(0x200+4, ym2612_regs);
  178. YM2612PicoStateLoad();
  179. break;
  180. // cd stuff
  181. case CHUNK_S68K:
  182. CHECKED_READ_BUFF(buff);
  183. PicoAreaUnpackCpu(buff, 1);
  184. break;
  185. case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;
  186. case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;
  187. case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;
  188. case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;
  189. case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;
  190. case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;
  191. case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;
  192. case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;
  193. case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;
  194. case CHUNK_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;
  195. case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;
  196. default:
  197. printf("PicoCdLoadState: skipping unknown chunk %i of size %i\n", buff[0], len);
  198. areaSeek(file, len, SEEK_CUR);
  199. break;
  200. }
  201. }
  202. /* after load events */
  203. if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
  204. wram_2M_to_1M(Pico_mcd->word_ram2M);
  205. #ifdef _ASM_CD_MEMORY_C
  206. PicoMemResetCD(Pico_mcd->s68k_regs[3]);
  207. if (Pico_mcd->s68k_regs[3]&4)
  208. PicoMemResetCDdecode(Pico_mcd->s68k_regs[3]);
  209. #endif
  210. if (Pico_mcd->m.audio_track > 0 && Pico_mcd->m.audio_track < Pico_mcd->TOC.Last_Track)
  211. mp3_start_play(Pico_mcd->TOC.Tracks[Pico_mcd->m.audio_track].F, Pico_mcd->m.audio_offset);
  212. // restore hint vector
  213. *(unsigned short *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;
  214. return 0;
  215. }
  216. int PicoCdLoadStateGfx(void *file)
  217. {
  218. int ver, len, found = 0;
  219. char buff[8];
  220. g_read_offs = 0;
  221. CHECKED_READ(8, buff);
  222. if (strncmp(buff, "PicoSMCD", 8)) R_ERROR_RETURN("bad header");
  223. CHECKED_READ(4, &ver);
  224. while (!areaEof(file) && found < 4)
  225. {
  226. CHECKED_READ(1, buff);
  227. CHECKED_READ(4, &len);
  228. if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
  229. if (buff[0] > CHUNK_FM && !(PicoMCD & 1)) R_ERROR_RETURN("cd chunk in non CD state?");
  230. switch (buff[0])
  231. {
  232. case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); found++; break;
  233. case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); found++; break;
  234. case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;
  235. case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;
  236. default:
  237. areaSeek(file, len, SEEK_CUR);
  238. break;
  239. }
  240. }
  241. return 0;
  242. }