2 famicom ROM cartridge utility - unagi
3 iNES header/buffer control
9 #include "memory_manage.h"
18 NES_HEADER_SIZE = 0x10,
19 PROGRAM_ROM_MIN = 0x4000,
20 CHARCTER_ROM_MIN = 0x2000
22 static const uint8_t NES_HEADER_INIT[NES_HEADER_SIZE] = {
23 'N', 'E', 'S', 0x1a, 0, 0, 0, 0,
24 0, 0, 0, 0, 0, 0, 0, 0
30 void nesheader_set(const struct romimage *r, uint8_t *header)
32 memcpy(header, NES_HEADER_INIT, NES_HEADER_SIZE);
33 header[4] = r->cpu_rom.size / PROGRAM_ROM_MIN;
34 header[5] = r->ppu_rom.size / CHARCTER_ROM_MIN;
35 if(r->mirror == MIRROR_VERTICAL){
38 if((r->cpu_ram.size != 0) || (r->backupram == true)){
42 header[6] |= (r->mappernum & 0x0f) << 4;
43 header[7] |= r->mappernum & 0xf0;
50 static int mirroring_fix(const struct textcontrol *l, struct memory *m, long min)
52 long mirror_size = m->size / 2;
53 while(mirror_size >= min){
54 const uint8_t *halfbuf;
56 halfbuf += mirror_size;
57 if(memcmp(m->data, halfbuf, mirror_size) != 0){
58 const long ret = mirror_size * 2;
60 l->append(l->object, wgT("mirroring %s ROM fixed\n"), m->name);
71 memset(ffdata, 0xff, min);
72 if(memcmp(ffdata, m->data, min) == 0){
73 l->append(l->object, wgT("error: data is all 0xff\n"));
75 }else if(m->size != min){
76 l->append(l->object, wgT("mirroring %s ROM fixed\n"), m->name);
84 //hash ¤Ï sha1 ¤Ë¤·¤¿¤¤¤¬Â¾¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤¢¤ï¤»¤Æ crc32 ¤Ë¤·¤È¤¯
85 static void rominfo_print(const struct textcontrol *l, const struct memory *m)
88 const uint32_t crc = crc32_get(m->data, m->size);
89 l->append(l->object, wgT("%s ROM: size 0x%06x, crc32 0x%08x\n"), m->name, m->size, (const int) crc);
91 l->append(l->object, wgT("%s RAM\n"), m->name);
95 void nesfile_create(const struct textcontrol *l, struct romimage *r, const wgChar *romfilename)
98 //RAM adapter bios size 0x2000 ¤ÏÊѹ¹¤·¤Ê¤¤
99 if(r->cpu_rom.size >= PROGRAM_ROM_MIN){
100 error += mirroring_fix(l, &(r->cpu_rom), PROGRAM_ROM_MIN);
102 if(r->ppu_rom.size != 0){
103 error += mirroring_fix(l, &(r->ppu_rom), CHARCTER_ROM_MIN);
105 if((DEBUG == 0) && (error != 0)){
108 //½¤ÀµºÑ¤ß ROM ¾ðÊóɽ¼¨
109 l->append(l->object, wgT("%s, mapper %d\n"), romfilename, (int) r->mappernum);
110 rominfo_print(l, &(r->cpu_rom));
111 rominfo_print(l, &(r->ppu_rom));
114 uint8_t header[NES_HEADER_SIZE];
115 nesheader_set(r, header);
117 f = _wfopen(romfilename, L"wb");
119 f = fopen(romfilename, "wb");
121 fseek(f, 0, SEEK_SET);
122 //RAM adapter bios ¤Ë¤Ï NES ¥Ø¥Ã¥À¤òºî¤é¤Ê¤¤
123 if(r->cpu_rom.size >= PROGRAM_ROM_MIN){
124 fwrite(header, sizeof(uint8_t), NES_HEADER_SIZE, f);
126 fwrite(r->cpu_rom.data, sizeof(uint8_t), r->cpu_rom.size, f);
127 if(r->ppu_rom.size != 0){
128 fwrite(r->ppu_rom.data, sizeof(uint8_t), r->ppu_rom.size, f);
133 static inline void memory_malloc(struct memory *m)
137 m->data = Malloc(m->size);
141 bool nesbuffer_malloc(struct romimage *r, int mode)
145 memory_malloc(&(r->cpu_rom));
146 memory_malloc(&(r->ppu_rom));
149 memory_malloc(&(r->cpu_ram));
155 static inline void memory_free(struct memory *m)
162 void nesbuffer_free(struct romimage *r, int mode)
164 memory_free(&(r->cpu_rom));
165 memory_free(&(r->ppu_rom));
166 if(mode == MODE_RAM_READ){
167 memory_free(&(r->cpu_ram));
171 void backupram_create(const struct memory *r, const wgChar *ramfilename)
173 buf_save(r->data, ramfilename, r->size);
177 memory size ¤Ï 2¾è¤µ¤ì¤Æ¤¤¤¯Ãͤ¬Àµ¾ïÃÍ.
178 ¤¿¤À¤·¡¢region ¤ÎºÇ¾®Ãͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï test ÍѤȤ·¤ÆÀµ¾ï¤Ë¤¹¤ë
180 int memorysize_check(const long size, int region)
184 case MEMORY_AREA_CPU_ROM:
185 min = PROGRAM_ROM_MIN;
187 case MEMORY_AREA_CPU_RAM:
188 min = 0x800; //¤¤¤Þ¤Î¤È¤³¤í. taito ·Ï¤Ï¤â¤Ã¤È¾®¤µ¤¤¤è¤¦¤Êµ¤¤¬¤¹¤ë
190 case MEMORY_AREA_PPU:
191 min = CHARCTER_ROM_MIN;
200 case 0x004000: //128K bit
201 case 0x008000: //256K
202 case 0x010000: //512K
213 romimage ¤¬ bank ¤ÎÄêµÁÃͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï romarea ¤ÎËöÈø¤ËÄ¥¤ë¡£
214 Ʊ¤¸¥Ç¡¼¥¿¤ò memcpy ¤·¤¿¤Û¤¦¤¬°ÂÁ´¤À¤¬¡¢¤È¤ê¤¢¤¨¤º¤Ç¡£
216 static void nesfile_datapointer_set(const uint8_t *buf, struct memory *m, long size)
219 assert((size % CHARCTER_ROM_MIN) == 0);
220 assert((m->size % CHARCTER_ROM_MIN) == 0);
224 long fillsize = m->size - size;
225 assert(fillsize >= 0); //fillsize is minus
226 memset(data, 0xff, fillsize); //ROM ¤Î̤»ÈÍÑÎΰè¤Ï 0xff ¤¬´ðËÜ
230 memcpy(data, buf, size);
233 //flashmemory device capacity check ¤¬È´¤±¤Æ¤ë¤±¤É¤É¤³¤Ç¤ä¤ë¤«Ì¤Äê
234 bool nesfile_load(const struct textcontrol *l, const wgChar *file, struct romimage *r)
239 buf = buf_load_full(file, &imagesize);
240 if(buf == NULL || imagesize < (NES_HEADER_SIZE + PROGRAM_ROM_MIN)){
241 // printf("%s ROM image open error\n", errorprefix);
245 if(memcmp(buf, NES_HEADER_INIT, 4) != 0){
246 l->append(l->object, wgT("NES header identify error\n"));
251 if((buf[6] & 1) == 0){
252 r->mirror = MIRROR_HORIZONAL;
254 r->mirror = MIRROR_VERTICAL;
256 //mapper number check
258 long mapper = (buf[6] >> 4) & 0x0f;
259 mapper |= buf[7] & 0xf0;
260 r->mappernum = mapper;
262 //NES/CPU/PPU imagesize check
263 long cpusize, ppusize;
265 long offset = NES_HEADER_SIZE;
267 cpusize = ((long) buf[4]) * PROGRAM_ROM_MIN;
269 r->cpu_rom.size = cpusize;
271 ppusize = ((long) buf[5]) * CHARCTER_ROM_MIN;
273 r->ppu_rom.size = ppusize;
275 if(offset != imagesize){
276 l->append(l->object, wgT("NES header filesize error\n"));
282 image pointer set/ memcpy
287 d += NES_HEADER_SIZE;
288 nesfile_datapointer_set(d, &r->cpu_rom, cpusize);
291 nesfile_datapointer_set(d, &r->ppu_rom, ppusize);
293 r->ppu_rom.data = NULL;