NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
11KB

  1. #include <inttypes.h>
  2. #include <string.h>
  3. #include "save.h"
  4. #include "file.h"
  5. #include "mapper.h"
  6. #include "filemap.h"
  7. /* SRAM */
  8. static int make_sram_filename(char* sram_filename, int max_len,
  9. const char* cart_filename) {
  10. return make_filename( sram_filename, max_len,
  11. basename(cart_filename),
  12. "sram", "sram");
  13. }
  14. int load_sram(nes_cart* cart, const char* cart_filename) {
  15. int status = -1;
  16. int sram_size = cart->mapper->sram_size ?
  17. cart->mapper->sram_size(cart->map_data) : 0;
  18. void* sram = cart->mapper->sram ?
  19. cart->mapper->sram(cart->map_data) : NULL;
  20. if (sram_size > 0 && NULL != sram) {
  21. char sram_filename[FILENAME_MAX] = {0};
  22. make_sram_filename(sram_filename, FILENAME_MAX - 1,
  23. cart_filename);
  24. status = read_file(sram_filename, sram, sram_size);
  25. }
  26. return status;
  27. }
  28. int save_sram(const nes_cart* cart, const char* cart_filename) {
  29. int status = -1;
  30. if (NULL != cart->mapper) {
  31. int sram_size = cart->mapper->sram_size ?
  32. cart->mapper->sram_size(cart->map_data) : 0;
  33. const void* sram = cart->mapper->sram ?
  34. cart->mapper->sram(cart->map_data) : NULL;
  35. if (sram_size > 0 && NULL != sram) {
  36. char sram_filename[FILENAME_MAX] = {0};
  37. make_sram_filename(sram_filename, FILENAME_MAX - 1,
  38. cart_filename);
  39. status = write_file(sram_filename, sram, sram_size);
  40. }
  41. }
  42. return status;
  43. }
  44. /* System State */
  45. static int make_state_filename(char* sram_filename, int max_len,
  46. const char* cart_filename) {
  47. return make_filename( sram_filename, max_len,
  48. basename(cart_filename),
  49. "save", "nese");
  50. }
  51. int load_state(nes* sys, const char* cart_filename) {
  52. int size = -1;
  53. char state_filename[FILENAME_MAX] = {0};
  54. make_state_filename(state_filename, FILENAME_MAX - 1,
  55. cart_filename);
  56. FILE* file = fopen(state_filename, "rb");
  57. if (NULL != file) {
  58. int file_size = state_size(sys);
  59. void* mem = map_file(file, file_size, Filemap_Mode_Read);
  60. if (NULL != mem) {
  61. size = state_read(sys, mem, file_size);
  62. unmap_file(mem, file_size);
  63. }
  64. fclose(file);
  65. }
  66. return size;
  67. }
  68. int save_state(const nes* sys, const char* cart_filename) {
  69. int size = -1;
  70. char state_filename[FILENAME_MAX] = {0};
  71. make_state_filename(state_filename, FILENAME_MAX - 1,
  72. cart_filename);
  73. FILE* file = fopen(state_filename, "w+b");
  74. if (NULL != file) {
  75. int file_size = state_size(sys);
  76. fseek(file, file_size - 1, SEEK_SET);
  77. fwrite("", 1, 1, file);
  78. fflush(file);
  79. void* mem = map_file(file, file_size, Filemap_Mode_Write);
  80. if (NULL != mem) {
  81. size = state_write(sys, mem, file_size);
  82. unmap_file(mem, file_size);
  83. }
  84. fclose(file);
  85. }
  86. return size;
  87. }
  88. #define tag_def(X) ( \
  89. X[0] | (X[1] << 8) | (X[2] << 16) | (X[3] << 24) \
  90. )
  91. #define tag_NESE tag_def("NESE")
  92. #define tag_cpu tag_def("tCPU")
  93. #define tag_ppu tag_def("tPPU")
  94. #define tag_apu tag_def("tAPU")
  95. #define tag_ram tag_def("WRAM")
  96. #define tag_mapper tag_def("MAPP")
  97. #define szChunkTag sizeof(uint32_t)
  98. #define szChunkHeader (szChunkTag + sizeof(uint32_t))
  99. static int cpu_state_size(const e6502_Core* core) {
  100. return (sizeof(core->registers) + sizeof(core->pins));
  101. }
  102. static int cpu_state_read(e6502_Core* core, const void* mem) {
  103. memcpy(&core->registers, mem, sizeof(core->registers));
  104. memcpy(&core->pins, mem + sizeof(core->registers),
  105. sizeof(core->pins));
  106. return (sizeof(core->registers) + sizeof(core->pins));
  107. }
  108. static int cpu_state_write(const e6502_Core* core, void* mem) {
  109. memcpy(mem, &core->registers, sizeof(core->registers));
  110. memcpy(mem + sizeof(core->registers), &core->pins,
  111. sizeof(core->pins));
  112. return (sizeof(core->registers) + sizeof(core->pins));
  113. }
  114. static int ppu_state_size(const nes_ppu* ppu) {
  115. return ((void*)&(ppu->mapper) - (void*)ppu);
  116. }
  117. static int ppu_state_read(nes_ppu* ppu, const void* mem) {
  118. int size = ppu_state_size(ppu);
  119. memcpy(ppu, mem, size);
  120. return size;
  121. }
  122. static int ppu_state_write(const nes_ppu* ppu, void* mem) {
  123. int size = ppu_state_size(ppu);
  124. memcpy(mem, ppu, size);
  125. return size;
  126. }
  127. static int apu_state_size(const nes_apu* apu) {
  128. return ( ((void*)(apu->channels) - (void*)apu) +
  129. (5 * ( (void*)&(apu->channels->write) -
  130. (void*)(apu->channels)
  131. ) )
  132. );
  133. }
  134. static int apu_state_read(nes_apu* apu, const void* mem) {
  135. int size = ((void*)(apu->channels) - (void*)apu);
  136. memcpy(apu, mem, size);
  137. const void* ptr = (mem + size);
  138. size = ( (void*)&(apu->channels->write) -
  139. (void*)(apu->channels));
  140. for (int chan = 0; chan < nes_apu_chan_count; ++chan) {
  141. memcpy(&apu->channels[chan], ptr, size);
  142. ptr += size;
  143. }
  144. return (ptr - mem);
  145. }
  146. static int apu_state_write(const nes_apu* apu, void* mem) {
  147. int size = ((void*)(apu->channels) - (void*)apu);
  148. memcpy(mem, apu, size);
  149. void* ptr = (mem + size);
  150. size = ( (void*)&(apu->channels->write) -
  151. (void*)(apu->channels));
  152. for (int chan = 0; chan < nes_apu_chan_count; ++chan) {
  153. memcpy(ptr, &apu->channels[chan], size);
  154. ptr += size;
  155. }
  156. return (ptr - mem);
  157. }
  158. static int ram_state_size(const nes* sys) {
  159. return sizeof(sys->ram);
  160. }
  161. static int ram_state_read(nes* sys, const void* mem) {
  162. memcpy(sys->ram, mem, sizeof(sys->ram));
  163. return sizeof(sys->ram);
  164. }
  165. static int ram_state_write(const nes* sys, void* mem) {
  166. memcpy(mem, sys->ram, sizeof(sys->ram));
  167. return sizeof(sys->ram);
  168. }
  169. int state_size(const nes* sys) {
  170. int size = szChunkHeader;
  171. size += szChunkHeader + cpu_state_size(&sys->cpu);
  172. size += szChunkHeader + ppu_state_size(&sys->ppu);
  173. size += szChunkHeader + apu_state_size(&sys->apu);
  174. // Ignoring input
  175. size += szChunkHeader + ram_state_size(sys);
  176. // Cart should already be loaded
  177. size += szChunkHeader +
  178. sys->cart.mapper->state_size(sys->cart.map_data);
  179. return size;
  180. }
  181. static inline void* write_header(void* mem,
  182. uint32_t tag,
  183. uint32_t size) {
  184. memcpy(mem, &tag, szChunkTag);
  185. mem += szChunkTag;
  186. memcpy(mem, &size, sizeof(size));
  187. mem += sizeof(size);
  188. return mem;
  189. }
  190. static inline const void* read_header(const void* mem,
  191. uint32_t* tag,
  192. uint32_t* size) {
  193. memcpy(tag, mem, szChunkTag);
  194. mem += szChunkTag;
  195. memcpy(size, mem, sizeof(size[0]));
  196. mem += sizeof(size[0]);
  197. return mem;
  198. }
  199. int state_write(const nes* sys, void* mem, int size) {
  200. void* ptr = mem;
  201. ptr = write_header(ptr, tag_NESE, state_size(sys));
  202. ptr = write_header(ptr, tag_cpu, cpu_state_size(&sys->cpu));
  203. ptr += cpu_state_write(&sys->cpu, ptr);
  204. ptr = write_header(ptr, tag_ppu, ppu_state_size(&sys->ppu));
  205. ptr += ppu_state_write(&sys->ppu, ptr);
  206. ptr = write_header(ptr, tag_apu, apu_state_size(&sys->apu));
  207. ptr += apu_state_write(&sys->apu, ptr);
  208. ptr = write_header(ptr, tag_ram, ram_state_size(sys));
  209. ptr += ram_state_write(sys, ptr);
  210. const nes_mapper* mapper = sys->cart.mapper;
  211. const void* map_data = sys->cart.map_data;
  212. ptr = write_header(ptr, tag_mapper,
  213. mapper->state_size(map_data));
  214. ptr += mapper->state_write(map_data, ptr);
  215. return (ptr - mem);
  216. }
  217. typedef enum {
  218. Component_CPU = 0b00000001,
  219. Component_PPU = 0b00000010,
  220. Component_APU = 0b00000100,
  221. Component_RAM = 0b00001000,
  222. Component_Mapper = 0b00010000,
  223. } nes_Component;
  224. int state_read(nes* sys, const void* mem, int mem_size) {
  225. int result = 0;
  226. nes_Component loaded = 0;
  227. const void* ptr = mem;
  228. const void* end = (mem + mem_size);
  229. uint32_t tag = 0;
  230. uint32_t size = 0;
  231. ptr = read_header(mem, &tag, &size);
  232. if (tag_NESE != tag) {
  233. result = -1;
  234. fprintf(stderr,
  235. "Bad save state magic: %.4s\n",
  236. (char*)&tag);
  237. }
  238. while (0 == result && ptr < end) {
  239. ptr = read_header(ptr, &tag, &size);
  240. if ((ptr + size) > end) {
  241. result = -1;
  242. fprintf(stderr,
  243. "Unusually large chunk: %.4s: +%"PRIu64"\n",
  244. (char*)&tag,
  245. ((ptr + size) - end));
  246. break;
  247. }
  248. int n_read = 0;
  249. if (tag_cpu == tag) {
  250. n_read = cpu_state_read(&sys->cpu, ptr);
  251. loaded |= Component_CPU;
  252. } else if (tag_ppu == tag) {
  253. n_read = ppu_state_read(&sys->ppu, ptr);
  254. loaded |= Component_PPU;
  255. } else if (tag_apu == tag) {
  256. n_read = apu_state_read(&sys->apu, ptr);
  257. loaded |= Component_APU;
  258. } else if (tag_ram == tag) {
  259. n_read = ram_state_read(sys, ptr);
  260. loaded |= Component_RAM;
  261. } else if (tag_mapper == tag) {
  262. n_read = sys->cart.mapper->state_read(
  263. sys->cart.map_data, ptr
  264. );
  265. loaded |= Component_Mapper;
  266. } else {
  267. fprintf(stderr,
  268. "Strange chunk: %.4s\n",
  269. (char*)&tag);
  270. }
  271. if (n_read != size) {
  272. result = -1;
  273. fprintf(stderr,
  274. "Chunk %.4s: read %d, expected %d\n",
  275. (char*)&tag, n_read, size);
  276. }
  277. ptr += size;
  278. }
  279. if (0 == result) {
  280. if (!(loaded | Component_CPU)) {
  281. result = -1;
  282. fprintf(stderr, "Missing %s state\n", "CPU");
  283. }
  284. if (!(loaded | Component_PPU)) {
  285. result = -1;
  286. fprintf(stderr, "Missing %s state\n", "PPU");
  287. }
  288. if (!(loaded | Component_APU)) {
  289. result = -1;
  290. fprintf(stderr, "Missing %s state\n", "APU");
  291. }
  292. if (!(loaded | Component_RAM)) {
  293. result = -1;
  294. fprintf(stderr, "Missing %s state\n", "RAM");
  295. }
  296. if (!(loaded | Component_Mapper)) {
  297. result = -1;
  298. fprintf(stderr, "Missing %s state\n", "Mapper");
  299. }
  300. }
  301. if (0 == result) {
  302. result = (ptr - mem);
  303. }
  304. return result;
  305. }