2 famicom ROM cartridge utility - unagi
3 iNES header/buffer control
16 NES_HEADER_SIZE = 0x10,
17 PROGRAM_ROM_MIN = 0x4000,
18 CHARCTER_ROM_MIN = 0x2000
20 static const u8 NES_HEADER_INIT[NES_HEADER_SIZE] = {
21 'N', 'E', 'S', 0x1a, 0, 0, 0, 0,
22 0, 0, 0, 0, 0, 0, 0, 0
28 void nesheader_set(const struct romimage *r, u8 *header)
30 memcpy(header, NES_HEADER_INIT, NES_HEADER_SIZE);
31 header[4] = r->cpu_rom.size / PROGRAM_ROM_MIN;
32 header[5] = r->ppu_rom.size / CHARCTER_ROM_MIN;
33 if(r->mirror == MIRROR_VERTICAL){
36 if((r->cpu_ram.size != 0) || (r->backupram != 0)){
40 header[6] |= (r->mappernum & 0x0f) << 4;
41 header[7] |= r->mappernum & 0xf0;
48 static int mirroring_fix(struct memory *m, long min)
50 long mirror_size = m->size / 2;
51 while(mirror_size >= min){
54 halfbuf += mirror_size;
55 if(memcmp(m->data, halfbuf, mirror_size) != 0){
56 const long ret = mirror_size * 2;
58 printf("mirroring %s rom fixed\n", m->name);
69 memset(ffdata, 0xff, min);
70 if(memcmp(ffdata, m->data, min) == 0){
71 printf("error: data is all 0xff\n");
73 }else if(m->size != min){
74 printf("mirroring %s rom fixed\n", m->name);
82 //hash ¤Ï sha1 ¤Ë¤·¤¿¤¤¤¬Â¾¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤¢¤ï¤»¤Æ crc32 ¤Ë¤·¤È¤¯
83 static void rominfo_print(const struct memory *m)
86 const uint32_t crc = crc32_get(m->data, m->size);
87 printf("%s ROM size 0x%06x, crc32 0x%08x\n", m->name, m->size, (const int) crc);
89 printf("%s RAM\n", m->name);
93 void nesfile_create(struct romimage *r, const char *romfilename)
96 //RAM adapter bios size 0x2000 ¤ÏÊѹ¹¤·¤Ê¤¤
97 if(r->cpu_rom.size >= PROGRAM_ROM_MIN){
98 error += mirroring_fix(&(r->cpu_rom), PROGRAM_ROM_MIN);
100 if(r->ppu_rom.size != 0){
101 error += mirroring_fix(&(r->ppu_rom), CHARCTER_ROM_MIN);
103 if((DEBUG == 0) && (error != 0)){
106 //½¤ÀµºÑ¤ß ROM ¾ðÊóɽ¼¨
107 printf("mapper %d\n", (int) r->mappernum);
108 rominfo_print(&(r->cpu_rom));
109 rominfo_print(&(r->ppu_rom));
112 u8 header[NES_HEADER_SIZE];
113 nesheader_set(r, header);
114 f = fopen(romfilename, "wb");
115 fseek(f, 0, SEEK_SET);
116 //RAM adapter bios ¤Ë¤Ï NES ¥Ø¥Ã¥À¤òºî¤é¤Ê¤¤
117 if(r->cpu_rom.size >= PROGRAM_ROM_MIN){
118 fwrite(header, sizeof(u8), NES_HEADER_SIZE, f);
120 fwrite(r->cpu_rom.data, sizeof(u8), r->cpu_rom.size, f);
121 if(r->ppu_rom.size != 0){
122 fwrite(r->ppu_rom.data, sizeof(u8), r->ppu_rom.size, f);
127 static inline void memory_malloc(struct memory *m)
131 m->data = malloc(m->size);
135 int nesbuffer_malloc(struct romimage *r, int mode)
139 memory_malloc(&(r->cpu_rom));
140 memory_malloc(&(r->ppu_rom));
143 memory_malloc(&(r->cpu_ram));
149 static inline void memory_free(struct memory *m)
156 void nesbuffer_free(struct romimage *r, int mode)
158 memory_free(&(r->cpu_rom));
159 memory_free(&(r->ppu_rom));
160 if(mode == MODE_RAM_READ){
161 memory_free(&(r->cpu_ram));
165 void backupram_create(const struct memory *r, const char *ramfilename)
167 buf_save(r->data, ramfilename, r->size);
170 static int nesfile_size_check(const char *errorprefix, const struct memory *m, long size)
173 while(size == m->size){
175 printf("%s NES header %s romsize alignment error\n", errorprefix, m->name);
183 else if(size > m->size){
184 printf("%s NES header cpuromsize too large\n", errorprefix);
191 memory size ¤Ï 2¾è¤µ¤ì¤Æ¤¤¤¯Ãͤ¬Àµ¾ïÃÍ.
192 ¤¿¤À¤·¡¢region ¤ÎºÇ¾®Ãͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï test ÍѤȤ·¤ÆÀµ¾ï¤Ë¤¹¤ë
194 int memorysize_check(const long size, int region)
198 case MEMORY_AREA_CPU_ROM:
199 min = PROGRAM_ROM_MIN;
201 case MEMORY_AREA_CPU_RAM:
202 min = 0x800; //¤¤¤Þ¤Î¤È¤³¤í. taito ·Ï¤Ï¤â¤Ã¤È¾®¤µ¤¤¤è¤¦¤Êµ¤¤¬¤¹¤ë
204 case MEMORY_AREA_PPU:
205 min = CHARCTER_ROM_MIN;
214 case 0x004000: //128K bit
215 case 0x008000: //256K
216 case 0x010000: //512K
227 romimage ¤¬ bank ¤ÎÄêµÁÃͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï romarea ¤ÎËöÈø¤ËÄ¥¤ë¡£
228 Ʊ¤¸¥Ç¡¼¥¿¤ò memcpy ¤·¤¿¤Û¤¦¤¬°ÂÁ´¤À¤¬¡¢¤È¤ê¤¢¤¨¤º¤Ç¡£
230 static void nesfile_datapointer_set(const u8 *buf, struct memory *m, long size)
233 assert((size % CHARCTER_ROM_MIN) == 0);
234 assert((m->size % CHARCTER_ROM_MIN) == 0);
238 long fillsize = m->size - size;
239 assert(fillsize >= 0); //fillsize is minus
240 memset(data, 0xff, fillsize); //ROM ¤Î̤»ÈÍÑÎΰè¤Ï 0xff ¤¬´ðËÜ
244 memcpy(data, buf, size);
247 //flashmemory device capacity check ¤¬È´¤±¤Æ¤ë¤±¤É¤É¤³¤Ç¤ä¤ë¤«Ì¤Äê
248 int nesfile_load(const char *errorprefix, const char *file, struct romimage *r)
253 buf = buf_load_full(file, &imagesize);
254 if(buf == NULL || imagesize < (NES_HEADER_SIZE + PROGRAM_ROM_MIN)){
255 printf("%s ROM image open error\n", errorprefix);
259 if(memcmp(buf, NES_HEADER_INIT, 4) != 0){
260 printf("%s NES header identify error\n", errorprefix);
264 //mapper number check
266 long mapper = (buf[6] >> 4) & 0x0f;
267 mapper |= buf[7] & 0xf0;
268 if(r->mappernum != mapper){
269 printf("%s NES header mapper error\n", errorprefix);
274 //NES/CPU/PPU imagesize check
275 long cpusize, ppusize;
277 long offset = NES_HEADER_SIZE;
279 cpusize = ((long) buf[4]) * PROGRAM_ROM_MIN;
281 if(nesfile_size_check(errorprefix, &r->cpu_rom, cpusize) == NG){
286 ppusize = ((long) buf[5]) * CHARCTER_ROM_MIN;
289 if(nesfile_size_check(errorprefix, &r->ppu_rom, ppusize) == NG){
295 if(offset != imagesize){
296 printf("%s NES header filesize error\n", errorprefix);
302 image pointer set/ memcpy
307 d += NES_HEADER_SIZE;
308 nesfile_datapointer_set(d, &r->cpu_rom, cpusize);
311 nesfile_datapointer_set(d, &r->ppu_rom, ppusize);