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.

430 lines
12KB

  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 expected_size = state_size(sys);
  61. fseek(file, 0L, SEEK_END);
  62. int file_size = ftell(file);
  63. // rewind(file);
  64. // if (max_size < size) size = max_size;
  65. void* mem = map_file(file, file_size, Filemap_Mode_Read);
  66. if (NULL != mem) {
  67. size = state_read(sys, mem, file_size);
  68. unmap_file(mem, file_size);
  69. }
  70. fclose(file);
  71. }
  72. return size;
  73. }
  74. int save_state(const nes* sys, const char* cart_filename) {
  75. int size = -1;
  76. mkdir("save");
  77. char state_filename[FILENAME_MAX] = {0};
  78. make_state_filename(state_filename, FILENAME_MAX - 1,
  79. cart_filename);
  80. FILE* file = fopen(state_filename, "w+b");
  81. if (NULL != file) {
  82. int file_size = state_size(sys);
  83. fseek(file, file_size - 1, SEEK_SET);
  84. fwrite("", 1, 1, file);
  85. fflush(file);
  86. void* mem = map_file(file, file_size, Filemap_Mode_Write);
  87. if (NULL != mem) {
  88. size = state_write(sys, mem, file_size);
  89. unmap_file(mem, file_size);
  90. }
  91. fclose(file);
  92. }
  93. return size;
  94. }
  95. #define tag_def(X) ( \
  96. X[0] | (X[1] << 8) | (X[2] << 16) | (X[3] << 24) \
  97. )
  98. #define tag_NESE tag_def("NESE")
  99. #define tag_cpu tag_def("tCPU")
  100. #define tag_ppu tag_def("tPPU")
  101. #define tag_apu tag_def("tAPU")
  102. #define tag_ram tag_def("WRAM")
  103. #define tag_mapper tag_def("MAPP")
  104. #define szChunkTag sizeof(uint32_t)
  105. #define szChunkHeader (szChunkTag + sizeof(uint32_t))
  106. static int cpu_state_size(const e6502_Core* core) {
  107. return (sizeof(core->registers) + sizeof(core->pins));
  108. }
  109. static int cpu_state_read(e6502_Core* core, const void* mem) {
  110. memcpy(&core->registers, mem, sizeof(core->registers));
  111. memcpy(&core->pins, mem + sizeof(core->registers),
  112. sizeof(core->pins));
  113. return (sizeof(core->registers) + sizeof(core->pins));
  114. }
  115. static int cpu_state_write(const e6502_Core* core, void* mem) {
  116. memcpy(mem, &core->registers, sizeof(core->registers));
  117. memcpy(mem + sizeof(core->registers), &core->pins,
  118. sizeof(core->pins));
  119. return (sizeof(core->registers) + sizeof(core->pins));
  120. }
  121. static int ppu_state_size(const nes_ppu* ppu) {
  122. return ((void*)&(ppu->mapper) - (void*)ppu);
  123. }
  124. static int ppu_state_read(nes_ppu* ppu, const void* mem) {
  125. int size = ppu_state_size(ppu);
  126. memcpy(ppu, mem, size);
  127. return size;
  128. }
  129. static int ppu_state_write(const nes_ppu* ppu, void* mem) {
  130. int size = ppu_state_size(ppu);
  131. memcpy(mem, ppu, size);
  132. return size;
  133. }
  134. static int apu_state_size(const nes_apu* apu) {
  135. return ( ((void*)(apu->channels) - (void*)apu) +
  136. (5 * ( (void*)&(apu->channels->write) -
  137. (void*)(apu->channels)
  138. ) )
  139. );
  140. }
  141. static int apu_state_read(nes_apu* apu, const void* mem) {
  142. int size = ((void*)(apu->channels) - (void*)apu);
  143. memcpy(apu, mem, size);
  144. const void* ptr = (mem + size);
  145. size = ( (void*)&(apu->channels->write) -
  146. (void*)(apu->channels));
  147. for (int chan = 0; chan < nes_apu_chan_count; ++chan) {
  148. memcpy(&apu->channels[chan], ptr, size);
  149. ptr += size;
  150. }
  151. return (ptr - mem);
  152. }
  153. static int apu_state_write(const nes_apu* apu, void* mem) {
  154. int size = ((void*)(apu->channels) - (void*)apu);
  155. memcpy(mem, apu, size);
  156. void* ptr = (mem + size);
  157. size = ( (void*)&(apu->channels->write) -
  158. (void*)(apu->channels));
  159. for (int chan = 0; chan < nes_apu_chan_count; ++chan) {
  160. memcpy(ptr, &apu->channels[chan], size);
  161. ptr += size;
  162. }
  163. return (ptr - mem);
  164. }
  165. static int ram_state_size(const nes* sys) {
  166. return sizeof(sys->ram);
  167. }
  168. static int ram_state_read(nes* sys, const void* mem) {
  169. memcpy(sys->ram, mem, sizeof(sys->ram));
  170. return sizeof(sys->ram);
  171. }
  172. static int ram_state_write(const nes* sys, void* mem) {
  173. memcpy(mem, sys->ram, sizeof(sys->ram));
  174. return sizeof(sys->ram);
  175. }
  176. int state_size(const nes* sys) {
  177. int size = szChunkHeader;
  178. size += szChunkHeader + cpu_state_size(&sys->cpu);
  179. size += szChunkHeader + ppu_state_size(&sys->ppu);
  180. size += szChunkHeader + apu_state_size(&sys->apu);
  181. // Ignoring input
  182. size += szChunkHeader + ram_state_size(sys);
  183. // Cart should already be loaded
  184. size += szChunkHeader +
  185. sys->cart.mapper->state_size(sys->cart.map_data);
  186. return size;
  187. }
  188. static inline void* write_header(void* mem,
  189. uint32_t tag,
  190. uint32_t size) {
  191. memcpy(mem, &tag, szChunkTag);
  192. mem += szChunkTag;
  193. memcpy(mem, &size, sizeof(size));
  194. mem += sizeof(size);
  195. return mem;
  196. }
  197. static inline const void* read_header(const void* mem,
  198. uint32_t* tag,
  199. uint32_t* size) {
  200. memcpy(tag, mem, szChunkTag);
  201. mem += szChunkTag;
  202. memcpy(size, mem, sizeof(size[0]));
  203. mem += sizeof(size[0]);
  204. return mem;
  205. }
  206. int state_write(const nes* sys, void* mem, int size) {
  207. void* ptr = mem;
  208. ptr = write_header(ptr, tag_NESE, state_size(sys));
  209. ptr = write_header(ptr, tag_cpu, cpu_state_size(&sys->cpu));
  210. ptr += cpu_state_write(&sys->cpu, ptr);
  211. ptr = write_header(ptr, tag_ppu, ppu_state_size(&sys->ppu));
  212. ptr += ppu_state_write(&sys->ppu, ptr);
  213. ptr = write_header(ptr, tag_apu, apu_state_size(&sys->apu));
  214. ptr += apu_state_write(&sys->apu, ptr);
  215. ptr = write_header(ptr, tag_ram, ram_state_size(sys));
  216. ptr += ram_state_write(sys, ptr);
  217. const nes_mapper* mapper = sys->cart.mapper;
  218. const void* map_data = sys->cart.map_data;
  219. int state_size = mapper->state_size(map_data);
  220. ptr = write_header(ptr, tag_mapper, state_size);
  221. ptr += mapper->state_write(map_data, ptr, state_size);
  222. return (ptr - mem);
  223. }
  224. typedef enum {
  225. Component_CPU = 0b00000001,
  226. Component_PPU = 0b00000010,
  227. Component_APU = 0b00000100,
  228. Component_RAM = 0b00001000,
  229. Component_Mapper = 0b00010000,
  230. } nes_Component;
  231. int state_read(nes* sys, const void* mem, int mem_size) {
  232. int result = 0;
  233. nes_Component loaded = 0;
  234. const void* ptr = mem;
  235. const void* end = (mem + mem_size);
  236. uint32_t tag = 0;
  237. uint32_t size = 0;
  238. ptr = read_header(mem, &tag, &size);
  239. if (tag_NESE != tag) {
  240. result = -1;
  241. fprintf(stderr,
  242. "Bad save state magic: %.4s\n",
  243. (char*)&tag);
  244. }
  245. while (0 == result && ptr < end) {
  246. ptr = read_header(ptr, &tag, &size);
  247. if ((ptr + size) > end) {
  248. result = -1;
  249. fprintf(stderr,
  250. "Unusually large chunk: %.4s: +%d\n",
  251. (char*)&tag,
  252. (int)((ptr + size) - end));
  253. break;
  254. }
  255. int n_read = 0;
  256. if (tag_cpu == tag) {
  257. n_read = cpu_state_read(&sys->cpu, ptr);
  258. loaded |= Component_CPU;
  259. } else if (tag_ppu == tag) {
  260. n_read = ppu_state_read(&sys->ppu, ptr);
  261. loaded |= Component_PPU;
  262. } else if (tag_apu == tag) {
  263. n_read = apu_state_read(&sys->apu, ptr);
  264. loaded |= Component_APU;
  265. } else if (tag_ram == tag) {
  266. n_read = ram_state_read(sys, ptr);
  267. loaded |= Component_RAM;
  268. } else if (tag_mapper == tag) {
  269. n_read = sys->cart.mapper->state_read(
  270. sys->cart.map_data, ptr, size
  271. );
  272. loaded |= Component_Mapper;
  273. } else {
  274. fprintf(stderr,
  275. "Strange chunk: %.4s\n",
  276. (char*)&tag);
  277. }
  278. if (n_read != size) {
  279. result = -1;
  280. fprintf(stderr,
  281. "Chunk %.4s: read %d, expected %d\n",
  282. (char*)&tag, n_read, size);
  283. }
  284. ptr += size;
  285. }
  286. if (0 == result) {
  287. if (!(loaded & Component_CPU)) {
  288. result = -1;
  289. fprintf(stderr, "Missing %s state\n", "CPU");
  290. }
  291. if (!(loaded & Component_PPU)) {
  292. result = -1;
  293. fprintf(stderr, "Missing %s state\n", "PPU");
  294. }
  295. if (!(loaded & Component_APU)) {
  296. result = -1;
  297. fprintf(stderr, "Missing %s state\n", "APU");
  298. }
  299. if (!(loaded & Component_RAM)) {
  300. result = -1;
  301. fprintf(stderr, "Missing %s state\n", "RAM");
  302. }
  303. if (!(loaded & Component_Mapper)) {
  304. result = -1;
  305. fprintf(stderr, "Missing %s state\n", "Mapper");
  306. }
  307. }
  308. if (0 == result) {
  309. result = (ptr - mem);
  310. }
  311. return result;
  312. }
  313. /*
  314. // Chunking
  315. int write_chunks(void* dst, int dst_len, const void* src,
  316. const nese_io_chunk* chunks, int n_chunks) {
  317. void* ptr = dst;
  318. for ( void* end = dst + dst_len;
  319. n_chunks > 0 && ptr < end;
  320. ptr += chunks->size, --n_chunks, ++chunks) {
  321. memcpy(ptr, src + chunks->offset, chunks->size);
  322. }
  323. return (ptr - dst);
  324. }
  325. int read_chunks(const void* src, int src_len, void* dst,
  326. const nese_io_chunk* chunks, int n_chunks) {
  327. const void* ptr = src;
  328. for ( const void* end = src + src_len;
  329. n_chunks > 0 && ptr < end;
  330. ptr += chunks->size, --n_chunks, ++chunks) {
  331. memcpy(dst + chunks->offset, ptr, chunks->size);
  332. }
  333. return (ptr - dst);
  334. }
  335. */