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.

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