OSDN Git Service

68786353020b5d3c7d4cec53d624dbb391acc670
[unagi/old-svn-converted.git] / client / trunk / header.c
1 /*
2 famicom ROM cartridge utility - unagi
3 iNES header/buffer control
4 */
5 #include <assert.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include "type.h"
10 #include "file.h"
11 #include "crc32.h"
12 #include "config.h"
13 #include "header.h"
14
15 enum{
16         NES_HEADER_SIZE = 0x10,
17         PROGRAM_ROM_MIN = 0x4000,
18         CHARCTER_ROM_MIN = 0x2000
19 };
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
23 };
24
25 #ifndef HEADEROUT
26 static 
27 #endif
28 void nesheader_set(const struct romimage *r, u8 *header)
29 {
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){
34                 header[6] |= 0x01;
35         }
36         if((r->cpu_ram.size != 0) || (r->backupram != 0)){
37                 header[6] |= 0x02;
38         }
39         //4 screen ¤Ï̵»ë
40         header[6] |= (r->mappernum & 0x0f) << 4;
41         header[7] |= r->mappernum & 0xf0;
42 }
43
44 #ifndef HEADEROUT
45 /*
46 returnÃÍ: error count
47 */
48 static int mirroring_fix(struct memory *m, long min)
49 {
50         long mirror_size = m->size / 2;
51         while(mirror_size >= min){
52                 const u8 *halfbuf;
53                 halfbuf = m->data;
54                 halfbuf += mirror_size;
55                 if(memcmp(m->data, halfbuf, mirror_size) != 0){
56                         const long ret = mirror_size * 2;
57                         if(m->size != ret){
58                                 printf("mirroring %s rom fixed\n", m->name);
59                                 m->size = ret;
60                         }
61                         return 0;
62                 }
63                 mirror_size /= 2;
64         }
65         
66         u8 *ffdata;
67         int ret = 0;
68         ffdata = malloc(min);
69         memset(ffdata, 0xff, min);
70         if(memcmp(ffdata, m->data, min) == 0){
71                 printf("error: data is all 0xff\n");
72                 ret = 1;
73         }else if(m->size != min){
74                 printf("mirroring %s rom fixed\n", m->name);
75                 m->size = min;
76         }
77         free(ffdata);
78         
79         return ret;
80 }
81
82 //hash ¤Ï sha1 ¤Ë¤·¤¿¤¤¤¬Â¾¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤¢¤ï¤»¤Æ crc32 ¤Ë¤·¤È¤¯
83 static void rominfo_print(const struct memory *m)
84 {
85         if(m->size != 0){
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);
88         }else{
89                 printf("%s RAM\n", m->name);
90         }
91 }
92
93 void nesfile_create(struct romimage *r, const char *romfilename)
94 {
95         int error = 0;
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);
99         }
100         if(r->ppu_rom.size != 0){
101                 error += mirroring_fix(&(r->ppu_rom), CHARCTER_ROM_MIN);
102         }
103         if((DEBUG == 0) && (error != 0)){
104                 return;
105         }
106         //½¤ÀµºÑ¤ß ROM ¾ðÊóɽ¼¨
107         printf("mapper %d\n", (int) r->mappernum);
108         rominfo_print(&(r->cpu_rom));
109         rominfo_print(&(r->ppu_rom));
110
111         FILE *f;
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);
119         }
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);
123         }
124         fclose(f);
125 }
126
127 static inline void memory_malloc(struct memory *m)
128 {
129         m->data = NULL;
130         if(m->size != 0){
131                 m->data = malloc(m->size);
132         }
133 }
134
135 int nesbuffer_malloc(struct romimage *r, int mode)
136 {
137         switch(mode){
138         case MODE_ROM_DUMP:
139                 memory_malloc(&(r->cpu_rom));
140                 memory_malloc(&(r->ppu_rom));
141                 break;
142         case MODE_RAM_READ:
143                 memory_malloc(&(r->cpu_ram));
144                 break;
145         }
146         return OK;
147 }
148
149 static inline void memory_free(struct memory *m)
150 {
151         if(m->size != 0){
152                 free(m->data);
153                 m->data = NULL;
154         }
155 }
156 void nesbuffer_free(struct romimage *r, int mode)
157 {
158         memory_free(&(r->cpu_rom));
159         memory_free(&(r->ppu_rom));
160         if(mode == MODE_RAM_READ){
161                 memory_free(&(r->cpu_ram));
162         }
163 }
164
165 void backupram_create(const struct memory *r, const char *ramfilename)
166 {
167         buf_save(r->data, ramfilename, r->size);
168 }
169
170 static int nesfile_size_check(const char *errorprefix, const struct memory *m, long size)
171 {
172         if(size < m->size){
173                 while(size == m->size){
174                         if(size < 0){
175                                 printf("%s NES header %s romsize alignment error\n", errorprefix, m->name);
176                                 return NG;
177                         }
178                         size -= m->size;
179                 }
180                 return NG;
181         }
182         //
183         else if(size > m->size){
184                 printf("%s NES header cpuromsize too large\n", errorprefix);
185                 return NG;
186         }
187         return OK;
188 }
189
190 /*
191 memory size ¤Ï 2¾è¤µ¤ì¤Æ¤¤¤¯Ãͤ¬Àµ¾ïÃÍ.
192 ¤¿¤À¤·¡¢region ¤ÎºÇ¾®Ãͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï test ÍѤȤ·¤ÆÀµ¾ï¤Ë¤¹¤ë
193 */
194 int memorysize_check(const long size, int region)
195 {
196         long min = 0;
197         switch(region){
198         case MEMORY_AREA_CPU_ROM:
199                 min = PROGRAM_ROM_MIN;
200                 break;
201         case MEMORY_AREA_CPU_RAM:
202                 min = 0x800; //¤¤¤Þ¤Î¤È¤³¤í. taito ·Ï¤Ï¤â¤Ã¤È¾®¤µ¤¤¤è¤¦¤Êµ¤¤¬¤¹¤ë
203                 break;
204         case MEMORY_AREA_PPU:
205                 min = CHARCTER_ROM_MIN;
206                 break;
207         default:
208                 assert(0);
209         }
210         if(size <= min){
211                 return OK;
212         }
213         switch(size){
214         case 0x004000: //128K bit
215         case 0x008000: //256K
216         case 0x010000: //512K
217         case 0x020000: //1M
218         case 0x040000: //2M
219         case 0x080000: //4M
220         case 0x100000: //8M
221                 return OK;
222         }
223         return NG;
224 }
225
226 /*
227 romimage ¤¬ bank ¤ÎÄêµÁÃͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï romarea ¤ÎËöÈø¤ËÄ¥¤ë¡£ 
228 Ʊ¤¸¥Ç¡¼¥¿¤ò memcpy ¤·¤¿¤Û¤¦¤¬°ÂÁ´¤À¤¬¡¢¤È¤ê¤¢¤¨¤º¤Ç¡£
229 */
230 static void nesfile_datapointer_set(const u8 *buf, struct memory *m, long size)
231 {
232         u8 *data;
233         assert((size % CHARCTER_ROM_MIN) == 0);
234         assert((m->size % CHARCTER_ROM_MIN) == 0);
235         data = malloc(size);
236         m->data = data;
237         if(size < m->size){
238                 long fillsize = m->size - size;
239                 assert(fillsize >= 0); //fillsize is minus
240                 memset(data, 0xff, fillsize); //ROM ¤Î̤»ÈÍÑÎΰè¤Ï 0xff ¤¬´ðËÜ
241                 data += fillsize;
242                 size -= fillsize;
243         }
244         memcpy(data, buf, size);
245 }
246
247 //flashmemory device capacity check ¤¬È´¤±¤Æ¤ë¤±¤É¤É¤³¤Ç¤ä¤ë¤«Ì¤Äê
248 int nesfile_load(const char *errorprefix, const char *file, struct romimage *r)
249 {
250         int imagesize;
251         u8 *buf;
252         
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);
256                 return NG;
257         }
258         //nes header check
259         if(memcmp(buf, NES_HEADER_INIT, 4) != 0){
260                 printf("%s NES header identify error\n", errorprefix);
261                 free(buf);
262                 return NG;
263         }
264         //mapper number check
265         {
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);
270                         free(buf);
271                         return NG;
272                 }
273         }
274         //NES/CPU/PPU imagesize check
275         long cpusize, ppusize;
276         {
277                 long offset = NES_HEADER_SIZE;
278                 //CPU
279                 cpusize = ((long) buf[4]) * PROGRAM_ROM_MIN;
280                 offset += cpusize;
281                 if(nesfile_size_check(errorprefix, &r->cpu_rom, cpusize) == NG){
282                         free(buf);
283                         return NG;
284                 }
285                 //PPU
286                 ppusize = ((long) buf[5]) * CHARCTER_ROM_MIN;
287                 offset += ppusize;
288                 if(ppusize != 0){
289                         if(nesfile_size_check(errorprefix, &r->ppu_rom, ppusize) == NG){
290                                 free(buf);
291                                 return NG;
292                         }
293                 }
294                 //NESfilesize
295                 if(offset != imagesize){
296                         printf("%s NES header filesize error\n", errorprefix);
297                         free(buf);
298                         return NG;
299                 }
300         }
301         /*
302         image pointer set/ memcpy
303         */
304         {
305                 u8 *d;
306                 d = buf;
307                 d += NES_HEADER_SIZE;
308                 nesfile_datapointer_set(d, &r->cpu_rom, cpusize);
309                 d += cpusize;
310                 if(ppusize != 0){
311                         nesfile_datapointer_set(d, &r->ppu_rom, ppusize);
312                 }
313         }
314
315         free(buf);
316         return OK;
317 }
318 #endif