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.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

398 lignes
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. }