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.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

430 Zeilen
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. */