OSDN Git Service

client 0.6.2 release
[unagi/old-svn-converted.git] / client / tag / 0.6.2 / header.c
diff --git a/client/tag/0.6.2/header.c b/client/tag/0.6.2/header.c
new file mode 100644 (file)
index 0000000..4025240
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+famicom ROM cartridge utility - unagi
+iNES header/buffer control
+*/
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "memory_manage.h"
+#include "type.h"
+#include "file.h"
+#include "crc32.h"
+#include "config.h"
+#include "header.h"
+
+enum{
+       NES_HEADER_SIZE = 0x10,
+       PROGRAM_ROM_MIN = 0x4000,
+       CHARCTER_ROM_MIN = 0x2000
+};
+static const u8 NES_HEADER_INIT[NES_HEADER_SIZE] = {
+       'N', 'E', 'S', 0x1a, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#ifndef HEADEROUT
+static 
+#endif
+void nesheader_set(const struct romimage *r, u8 *header)
+{
+       memcpy(header, NES_HEADER_INIT, NES_HEADER_SIZE);
+       header[4] = r->cpu_rom.size / PROGRAM_ROM_MIN;
+       header[5] = r->ppu_rom.size / CHARCTER_ROM_MIN;
+       if(r->mirror == MIRROR_VERTICAL){
+               header[6] |= 0x01;
+       }
+       if((r->cpu_ram.size != 0) || (r->backupram != 0)){
+               header[6] |= 0x02;
+       }
+       //4 screen ¤Ï̵»ë
+       header[6] |= (r->mappernum & 0x0f) << 4;
+       header[7] |= r->mappernum & 0xf0;
+}
+
+#ifndef HEADEROUT
+/*
+returnÃÍ: error count
+*/
+static int mirroring_fix(struct memory *m, long min)
+{
+       long mirror_size = m->size / 2;
+       while(mirror_size >= min){
+               const u8 *halfbuf;
+               halfbuf = m->data;
+               halfbuf += mirror_size;
+               if(memcmp(m->data, halfbuf, mirror_size) != 0){
+                       const long ret = mirror_size * 2;
+                       if(m->size != ret){
+                               printf("mirroring %s rom fixed\n", m->name);
+                               m->size = ret;
+                       }
+                       return 0;
+               }
+               mirror_size /= 2;
+       }
+       
+       u8 *ffdata;
+       int ret = 0;
+       ffdata = Malloc(min);
+       memset(ffdata, 0xff, min);
+       if(memcmp(ffdata, m->data, min) == 0){
+               printf("error: data is all 0xff\n");
+               ret = 1;
+       }else if(m->size != min){
+               printf("mirroring %s rom fixed\n", m->name);
+               m->size = min;
+       }
+       Free(ffdata);
+       
+       return ret;
+}
+
+//hash ¤Ï sha1 ¤Ë¤·¤¿¤¤¤¬Â¾¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤¢¤ï¤»¤Æ crc32 ¤Ë¤·¤È¤¯
+static void rominfo_print(const struct memory *m)
+{
+       if(m->size != 0){
+               const uint32_t crc = crc32_get(m->data, m->size);
+               printf("%s ROM: size 0x%06x, crc32 0x%08x\n", m->name, m->size, (const int) crc);
+       }else{
+               printf("%s RAM\n", m->name);
+       }
+}
+
+void nesfile_create(struct romimage *r, const char *romfilename)
+{
+       int error = 0;
+       //RAM adapter bios size 0x2000 ¤ÏÊѹ¹¤·¤Ê¤¤
+       if(r->cpu_rom.size >= PROGRAM_ROM_MIN){
+               error += mirroring_fix(&(r->cpu_rom), PROGRAM_ROM_MIN);
+       }
+       if(r->ppu_rom.size != 0){
+               error += mirroring_fix(&(r->ppu_rom), CHARCTER_ROM_MIN);
+       }
+       if((DEBUG == 0) && (error != 0)){
+               return;
+       }
+       //½¤ÀµºÑ¤ß ROM ¾ðÊóɽ¼¨
+       printf("mapper %d\n", (int) r->mappernum);
+       rominfo_print(&(r->cpu_rom));
+       rominfo_print(&(r->ppu_rom));
+
+       FILE *f;
+       u8 header[NES_HEADER_SIZE];
+       nesheader_set(r, header);
+       f = fopen(romfilename, "wb");
+       fseek(f, 0, SEEK_SET);
+       //RAM adapter bios ¤Ë¤Ï NES ¥Ø¥Ã¥À¤òºî¤é¤Ê¤¤
+       if(r->cpu_rom.size >= PROGRAM_ROM_MIN){ 
+               fwrite(header, sizeof(u8), NES_HEADER_SIZE, f);
+       }
+       fwrite(r->cpu_rom.data, sizeof(u8), r->cpu_rom.size, f);
+       if(r->ppu_rom.size != 0){
+               fwrite(r->ppu_rom.data, sizeof(u8), r->ppu_rom.size, f);
+       }
+       fclose(f);
+}
+
+static inline void memory_malloc(struct memory *m)
+{
+       m->data = NULL;
+       if(m->size != 0){
+               m->data = Malloc(m->size);
+       }
+}
+
+bool nesbuffer_malloc(struct romimage *r, int mode)
+{
+       switch(mode){
+       case MODE_ROM_DUMP:
+               memory_malloc(&(r->cpu_rom));
+               memory_malloc(&(r->ppu_rom));
+               break;
+       case MODE_RAM_READ:
+               memory_malloc(&(r->cpu_ram));
+               break;
+       }
+       return true;
+}
+
+static inline void memory_free(struct memory *m)
+{
+       if(m->data != NULL){
+               Free(m->data);
+               m->data = NULL;
+       }
+}
+void nesbuffer_free(struct romimage *r, int mode)
+{
+       memory_free(&(r->cpu_rom));
+       memory_free(&(r->ppu_rom));
+       if(mode == MODE_RAM_READ){
+               memory_free(&(r->cpu_ram));
+       }
+}
+
+void backupram_create(const struct memory *r, const char *ramfilename)
+{
+       buf_save(r->data, ramfilename, r->size);
+}
+
+/*
+memory size ¤Ï 2¾è¤µ¤ì¤Æ¤¤¤¯Ãͤ¬Àµ¾ïÃÍ.
+¤¿¤À¤·¡¢region ¤ÎºÇ¾®Ãͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï test ÍѤȤ·¤ÆÀµ¾ï¤Ë¤¹¤ë
+*/
+int memorysize_check(const long size, int region)
+{
+       long min = 0;
+       switch(region){
+       case MEMORY_AREA_CPU_ROM:
+               min = PROGRAM_ROM_MIN;
+               break;
+       case MEMORY_AREA_CPU_RAM:
+               min = 0x800; //¤¤¤Þ¤Î¤È¤³¤í. taito ·Ï¤Ï¤â¤Ã¤È¾®¤µ¤¤¤è¤¦¤Êµ¤¤¬¤¹¤ë
+               break;
+       case MEMORY_AREA_PPU:
+               min = CHARCTER_ROM_MIN;
+               break;
+       default:
+               assert(0);
+       }
+       if(size <= min){
+               return OK;
+       }
+       switch(size){
+       case 0x004000: //128K bit
+       case 0x008000: //256K
+       case 0x010000: //512K
+       case 0x020000: //1M
+       case 0x040000: //2M
+       case 0x080000: //4M
+       case 0x100000: //8M
+               return OK;
+       }
+       return NG;
+}
+
+/*
+romimage ¤¬ bank ¤ÎÄêµÁÃͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï romarea ¤ÎËöÈø¤ËÄ¥¤ë¡£ 
+Ʊ¤¸¥Ç¡¼¥¿¤ò memcpy ¤·¤¿¤Û¤¦¤¬°ÂÁ´¤À¤¬¡¢¤È¤ê¤¢¤¨¤º¤Ç¡£
+*/
+static void nesfile_datapointer_set(const u8 *buf, struct memory *m, long size)
+{
+       u8 *data;
+       assert((size % CHARCTER_ROM_MIN) == 0);
+       assert((m->size % CHARCTER_ROM_MIN) == 0);
+       data = Malloc(size);
+       m->data = data;
+       if(size < m->size){
+               long fillsize = m->size - size;
+               assert(fillsize >= 0); //fillsize is minus
+               memset(data, 0xff, fillsize); //ROM ¤Î̤»ÈÍÑÎΰè¤Ï 0xff ¤¬´ðËÜ
+               data += fillsize;
+               size -= fillsize;
+       }
+       memcpy(data, buf, size);
+}
+
+//flashmemory device capacity check ¤¬È´¤±¤Æ¤ë¤±¤É¤É¤³¤Ç¤ä¤ë¤«Ì¤Äê
+bool nesfile_load(const char *errorprefix, const char *file, struct romimage *r)
+{
+       int imagesize;
+       u8 *buf;
+       
+       buf = buf_load_full(file, &imagesize);
+       if(buf == NULL || imagesize < (NES_HEADER_SIZE + PROGRAM_ROM_MIN)){
+               printf("%s ROM image open error\n", errorprefix);
+               return false;
+       }
+       //nes header check
+       if(memcmp(buf, NES_HEADER_INIT, 4) != 0){
+               printf("%s NES header identify error\n", errorprefix);
+               Free(buf);
+               return false;
+       }
+       //vram mirroring set
+       if((buf[6] & 1) == 0){
+               r->mirror = MIRROR_HORIZONAL;
+       }else{
+               r->mirror = MIRROR_VERTICAL;
+       }
+       //mapper number check
+       {
+               long mapper = (buf[6] >> 4) & 0x0f;
+               mapper |= buf[7] & 0xf0;
+#if ANAGO == 1
+               r->mappernum = mapper;
+#else
+               if(r->mappernum != mapper){
+                       printf("%s NES header mapper error\n", errorprefix);
+                       Free(buf);
+                       return false;
+               }
+#endif
+       }
+       //NES/CPU/PPU imagesize check
+       long cpusize, ppusize;
+       {
+               long offset = NES_HEADER_SIZE;
+               //CPU
+               cpusize = ((long) buf[4]) * PROGRAM_ROM_MIN;
+               offset += cpusize;
+               r->cpu_rom.size = cpusize;
+               //PPU
+               ppusize = ((long) buf[5]) * CHARCTER_ROM_MIN;
+               offset += ppusize;
+               r->ppu_rom.size = ppusize;
+               //NESfilesize
+               if(offset != imagesize){
+                       printf("%s NES header filesize error\n", errorprefix);
+                       Free(buf);
+                       return false;
+               }
+       }
+       /*
+       image pointer set/ memcpy
+       */
+       {
+               u8 *d;
+               d = buf;
+               d += NES_HEADER_SIZE;
+               nesfile_datapointer_set(d, &r->cpu_rom, cpusize);
+               d += cpusize;
+               if(ppusize != 0){
+                       nesfile_datapointer_set(d, &r->ppu_rom, ppusize);
+               }else{
+                       r->ppu_rom.data = NULL;
+                       r->ppu_rom.size = 0;
+               }
+       }
+
+       Free(buf);
+       return true;
+}
+#endif