--- /dev/null
+OBJ_HK = giveio.o reader_hongkongfc.o
+OBJ_HD = head/nesheader.o head/header.o file.o
+SOURCE_UNAGI = \
+ *.c *.h *.mak Makefile COPYING \
+ debug/debug.mak profile/profile.mak release/release.mak \
+ unagi.rc unagi.ico
+SOURCE_ANAGO = \
+ Makefile.windows Makefile.unix \
+ anago.c flash_device.c progress.c reader_dummy.c \
+ script_common.c script_dump.c script_flash.c squirrel_wrap.c \
+ flash_device.h progress.h reader_dummy.h script_common.h script_dump.h script_flash.h squirrel_wrap.h \
+ flashcore.nut flashdevice.nut \
+ anago_en.txt anago_ja.txt porting.txt
+ARCHIVE_GZ = unagi_client_source.0.6.x.tar.gz
+ARCHIVE_ZIP = unagi_client_windows_06x.zip
+TARGET_DIR = debug
+TARGET_MAK = debug.mak
+ifeq ($(PROFILE),1)
+ TARGET_DIR = profile
+ TARGET_MAK = profile.mak
+endif
+ifeq ($(RELEASE),1)
+ TARGET_DIR = release
+ TARGET_MAK = release.mak
+endif
+
+all:
+ cd $(TARGET_DIR); make -f $(TARGET_MAK)
+ cp $(TARGET_DIR)/unagi.exe .
+clean:
+ rm -f unagi.exe \
+ debug/*.o debug/*.exe debug/*.d \
+ profile/*.o profile/*.exe profile/*.d \
+ release/*.o release/*.exe release/*.d
+
+head/nesheader.o: nesheader.c
+ $(CC) $(CFLAGS) -DHEADEROUT -I. -c -o $@ $<
+head/header.o: header.c
+ $(CC) $(CFLAGS) -DHEADEROUT -I. -c -o $@ $<
+hk.exe: $(OBJ_HK)
+ $(CC) -o $@ $(OBJ_HK)
+iodel.exe: iodel.o giveio.o
+ $(CC) -o $@ iodel.o giveio.o
+nesheader.exe: $(OBJ_HD)
+ $(CC) -o $@ $(OBJ_HD)
+gz:
+ cd ..; \
+ tar cfz $(ARCHIVE_GZ) $(addprefix client/,$(SOURCE_UNAGI)) $(addprefix client/anago/,$(SOURCE_ANAGO))
+zip:
+ 7za a $(ARCHIVE_ZIP) \
+ unagi.exe unagi.txt iodel.exe iodel.txt COPYING ../script/syntax.txt \
+ $(addprefix anago/,anago.exe *.ad *.af anago_en.txt anago_ja.txt flashcore.nut flashdevice.nut dumpcore.nut)
+ cd release; 7za a ../$(ARCHIVE_ZIP) unagi.cfg
+ mv $(ARCHIVE_ZIP) ..
--- /dev/null
+TARGET = anago\r
+LIBUSB = \r
+SQUIRREL = ../SQUIRREL2\r
+KAZZO = ../../kazzo/firmware\r
+\r
+include anago.mk\r
--- /dev/null
+TARGET = anago.exe\r
+LIBUSB = d:/dev/LibUSB-Win32\r
+SQUIRREL = ../SQUIRREL2\r
+KAZZO = ../../kazzo/firmware\r
+\r
+include anago.mk\r
--- /dev/null
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h> //atoi()
+#include "memory_manage.h"
+#include "type.h"
+#include "flash_device.h"
+#include "header.h"
+#include "reader_master.h"
+#include "reader_kazzo.h"
+#include "reader_dummy.h"
+#include "script_flash.h"
+#include "script_dump.h"
+
+static bool transtype_flash_set(char mode, struct memory *t)
+{
+ switch(mode){
+ case 't':
+ t->transtype = TRANSTYPE_TOP;
+ break;
+ case 'e':
+ t->transtype = TRANSTYPE_EMPTY;
+ break;
+ case 'b':
+ t->transtype = TRANSTYPE_BOTTOM;
+ break;
+ case 'f':
+ t->transtype = TRANSTYPE_FULL;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+static bool transtype_set(const char *mode, struct romimage *t)
+{
+ switch(mode[0]){
+ case 'a': case 'f': case 'F':
+ if(mode[1] == '\0'){
+ t->cpu_rom.transtype = TRANSTYPE_FULL;
+ t->ppu_rom.transtype = TRANSTYPE_FULL;
+ return true;
+ }
+ if(transtype_flash_set(mode[1], &t->cpu_rom) == false){
+ return false;
+ }
+ if(mode[2] == '\0'){
+ t->ppu_rom.transtype = TRANSTYPE_FULL;
+ return true;
+ }
+ if(transtype_flash_set(mode[2], &t->ppu_rom) == false){
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+static bool config_parse(const char *romimage, const char *device_cpu, const char *device_ppu, struct config_flash *c)
+{
+ c->target = romimage;
+ if(nesfile_load(__FUNCTION__, romimage, &c->rom) == false){
+ return false;
+ }
+ c->rom.cpu_rom.offset = 0;
+ c->rom.ppu_rom.offset = 0;
+ if(flash_device_get(device_cpu, &c->flash_cpu) == false){
+ printf("unkown flash memory device %s\n", device_cpu);
+ return false;
+ }
+ if(flash_device_get(device_ppu, &c->flash_ppu) == false){
+ printf("unkown flash memory device %s\n", device_ppu);
+ return false;
+ }
+ if(c->flash_cpu.id_device == FLASH_ID_DEVICE_DUMMY){
+ c->rom.cpu_rom.transtype = TRANSTYPE_EMPTY;
+ }else if(c->flash_cpu.capacity < c->rom.cpu_rom.size){
+ puts("cpu area ROM image size is larger than target device");
+ return false;
+ }
+ if(
+ (c->flash_ppu.id_device == FLASH_ID_DEVICE_DUMMY) ||
+ (c->rom.ppu_rom.size == 0)
+ ){
+ c->rom.ppu_rom.transtype = TRANSTYPE_EMPTY;
+ }else if(c->flash_ppu.capacity < c->rom.ppu_rom.size){
+ puts("ppu area ROM image size is larger than target device");
+ return false;
+ }
+ return true;
+}
+static void program(int c, char **v)
+{
+ struct config_flash config;
+ config.rom.cpu_rom.data = NULL;
+ config.rom.ppu_rom.data = NULL;
+ config.script = v[2];
+ config.reader = &DRIVER_KAZZO;
+ config.compare = false;
+ config.testrun = false;
+ switch(v[1][0]){
+ case 'a':
+ config.reader = &DRIVER_DUMMY;
+ config.testrun = true;
+ break;
+ case 'F':
+ config.compare = true;
+ break;
+ }
+ if(transtype_set(v[1], &config.rom) == false){
+ puts("mode argument error");
+ return;
+ }
+ switch(c){
+ case 5: //mode script target cpu_flash_device
+ if(config_parse(v[3], v[4], "dummy", &config) == false){
+ nesbuffer_free(&config.rom, 0);
+ return;
+ }
+ break;
+ case 6: //mode script target cpu_flash_device ppu_flash_device
+ if(config_parse(v[3], v[4], v[5], &config) == false){
+ nesbuffer_free(&config.rom, 0);
+ return;
+ }
+ break;
+ default:
+ puts("mode script target cpu_flash_device ppu_flash_device");
+ return;
+ }
+ if(config.reader->open_or_close(READER_OPEN) == NG){
+ puts("reader open error");
+ nesbuffer_free(&config.rom, 0);
+ return;
+ }
+ config.reader->init();
+ script_flash_execute(&config);
+ nesbuffer_free(&config.rom, 0);
+ config.reader->open_or_close(READER_CLOSE);
+}
+static void dump(int c, char **v)
+{
+ struct config_dump config;
+ if(c < 4){
+ puts("argument error");
+ return;
+ }
+ config.increase.cpu = 1;
+ config.increase.ppu = 1;
+ config.progress = true;
+ switch(v[1][0]){
+ case 'D':
+ config.progress = false;
+ break;
+ }
+ switch(v[1][1]){
+ case '2':
+ config.increase.cpu = 2;
+ break;
+ case '4':
+ config.increase.cpu = 4;
+ break;
+ }
+ if(v[1][1] != '\0'){
+ switch(v[1][2]){
+ case '2':
+ config.increase.ppu = 2;
+ break;
+ case '4':
+ config.increase.ppu = 4;
+ break;
+ }
+ }
+ config.script = v[2];
+ config.target = v[3];
+ config.reader = &DRIVER_KAZZO;
+ config.mappernum = -1;
+ if(c == 5){
+ config.mappernum = atoi(v[4]);
+ }
+ if(config.reader->open_or_close(READER_OPEN) == NG){
+ puts("reader open error");
+ return;
+ }
+ config.reader->init();
+ script_dump_execute(&config);
+ config.reader->open_or_close(READER_CLOSE);
+}
+static void usage(const char *v)
+{
+ puts("famicom bus simluator 'anago'");
+ printf("%s [mode] [script] [target] ....\n", v);
+}
+int main(int c, char **v)
+{
+ mm_init();
+ if(c >= 2){
+ switch(v[1][0]){
+ case 'a': case 'f': case 'F':
+ program(c, v);
+ break;
+ case 'd': case 'D':
+ dump(c,v);
+ break;
+ default:
+ usage(v[0]);
+ puts("mode are a, d, D, f, g");
+ break;
+ }
+ }else{
+ usage(v[0]);
+ }
+ mm_end();
+ return 0;
+}
--- /dev/null
+all: $(TARGET)
+VPATH = ..
+ifeq ($(RELEASE),1)
+ CFLAGS = -O2 -DNDEBUG
+else
+ CFLAGS = -g -O0
+endif
+CFLAGS += -Wall -Werror -DDEBUG=1 -DANAGO=1
+CFLAGS += -I.. -I$(SQUIRREL)/include -I$(KAZZO)
+ifneq ($(strip $(LIBUSB)),)
+ CFLAGS += -I$(LIBUSB)/include
+endif
+LDFLAG = -L$(SQUIRREL)/lib
+ifneq ($(strip $(LIBUSB)),)
+ LDFLAG += -L$(LIBUSB)/lib/gcc
+endif
+CC = gcc
+OBJ = anago.o header.o crc32.o file.o \
+ script_flash.o script_dump.o script_common.o \
+ progress.o flash_device.o \
+ reader_dummy.o reader_kazzo.o usb_device.o squirrel_wrap.o memory_manage.o
+
+clean:
+ rm -f $(OBJ)
+$(TARGET): $(OBJ)
+ g++ -o $@ $(LDFLAG) $(OBJ) -lusb -lsqstdlib -lsquirrel
+
+script_flash.o: squirrel_wrap.h
+script_dump.o: squirrel_wrap.h
--- /dev/null
+mega <- 0x20000;
+function dump(d, mappernum, increase_cpu, increase_ppu)
+{
+ local vram = board.vram_mirrorfind == true ? 1 : 0;
+ if(mappernum == -1){
+ mappernum = board.mappernum;
+ }
+ memory_new(d, board.cpu_romsize * increase_cpu, board.ppu_romsize * increase_ppu);
+ cpu_dump(d, board.cpu_romsize * increase_cpu / board.cpu_banksize, board.cpu_banksize);
+ if(board.ppu_ramfind == true){
+ if(ppu_ramfind(d) == true){
+ nesfile_save(d, mappernum, vram);
+ return;
+ }
+ }
+ if(board.ppu_romsize != 0){
+ ppu_dump(d, board.ppu_romsize * increase_ppu / board.ppu_banksize, board.ppu_banksize);
+ }
+ nesfile_save(d, mappernum, vram);
+ return;
+}
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <squirrel.h>
+#include <sqstdio.h>
+#include <sqstdaux.h>
+#include "type.h"
+#include "memory_manage.h"
+#include "squirrel_wrap.h"
+#include "flash_device.h"
+
+static void call(HSQUIRRELVM v, const char *devicename)
+{
+ sq_pushroottable(v);
+ sq_pushstring(v, _SC("flash_device_get"), -1);
+ if(SQ_SUCCEEDED(sq_get(v,-2))){
+ sq_pushroottable(v);
+ sq_pushstring(v, _SC(devicename), -1);
+ SQRESULT r = sq_call(v, 2, SQTrue, SQTrue);
+ assert(r == SQ_OK);
+ r++; //avoid warning unused variable with -DNDEBUG
+ }
+}
+static bool long_get(HSQUIRRELVM v, const char *field, long *ret)
+{
+ sq_pushstring(v, _SC(field), -1);
+ SQRESULT r = sq_get(v, -2);
+ if(r != SQ_OK){
+ return false;
+ }
+ if(sq_gettype(v, -1) != OT_INTEGER){
+ return false;
+ }
+ SQInteger i;
+ r = sq_getinteger(v, -1, &i);
+ if(r != SQ_OK){
+ return false;
+ }
+ *ret = (long) i;
+ sq_pop(v, 1);
+ return true;
+}
+static bool bool_get(HSQUIRRELVM v, const char *field, bool *ret)
+{
+ sq_pushstring(v, _SC(field), -1);
+ SQRESULT r = sq_get(v, -2);
+ if(r != SQ_OK){
+ return false;
+ }
+ if(sq_gettype(v, -1) != OT_BOOL){
+ return false;
+ }
+ SQBool i;
+ r = sq_getbool(v, -1, &i);
+ if(r != SQ_OK){
+ return false;
+ }
+ if(i == SQTrue){
+ *ret = true;
+ }else{
+ *ret = false;
+ }
+ sq_pop(v, 1);
+ return true;
+}
+bool flash_device_get(const char *name, struct flash_device *t)
+{
+ HSQUIRRELVM v = qr_open();
+ if(SQ_FAILED(sqstd_dofile(v, _SC("flashdevice.nut"), SQFalse, SQTrue))){
+ puts("flash device script error");
+ qr_close(v);
+ return false;
+ }
+ SQInteger top = sq_gettop(v);
+ call(v, name);
+ if(sq_gettype(v, -1) != OT_TABLE){
+ goto field_error;
+ }
+ t->name = name;
+ if(long_get(v, "capacity", &t->capacity) == false){
+ goto field_error;
+ }
+ if(long_get(v, "pagesize", &t->pagesize) == false){
+ goto field_error;
+ }
+ if(long_get(v, "erase_wait", &t->erase_wait) == false){
+ goto field_error;
+ }
+ if(bool_get(v, "erase_require", &t->erase_require) == false){
+ goto field_error;
+ }
+ if(bool_get(v, "retry", &t->retry) == false){
+ goto field_error;
+ }
+ if(long_get(v, "command_mask", &t->command_mask) == false){
+ goto field_error;
+ }
+ long dd;
+ if(long_get(v, "id_manufacurer", &dd) == false){
+ goto field_error;
+ }
+ t->id_manufacurer = dd;
+ if(long_get(v, "id_device", &dd) == false){
+ goto field_error;
+ }
+ t->id_device = dd;
+ sq_settop(v, top);
+ qr_close(v);
+ return true;
+
+field_error:
+ puts("script field error");
+ qr_close(v);
+ return false;
+}
--- /dev/null
+#ifndef _FLASH_DEVICE_H_
+#define _FLASH_DEVICE_H_
+struct flash_device{
+ const char *name;
+ long capacity, pagesize;
+ long erase_wait; //unit is msec
+ bool erase_require, retry;
+ uint8_t id_manufacurer, id_device;
+ long command_mask;
+};
+
+bool flash_device_get(const char *name, struct flash_device *t);
+//0x80 °Ê¹ß¤ÏËÜÅö¤Î¥Ç¥Ð¥¤¥¹½ÅÊ£¤·¤Ê¤¤¤È»×¤¦. 狼 JEDEC ¤Î¤È¤³¤ò¤·¤é¤Ù¤Æ.
+enum{
+ FLASH_ID_DEVICE_SRAM = 0xf0,
+ FLASH_ID_DEVICE_DUMMY
+};
+#endif
--- /dev/null
+mega <- 0x20000;
+function loopsize_get(t, trans, image_size, device_size)
+{
+ local trans_full = 3, trans_top = 1, trans_bottom = 2; //header.h enum transtype
+ local loop = {start = 0, end = 0};
+ switch(trans){
+ case trans_full:{
+ local size = device_size < t.maxsize ? device_size : t.maxsize;
+ loop.end = size / t.banksize;
+ }break;
+ case trans_top:
+ loop.end = image_size / t.banksize;
+ break;
+ case trans_bottom:
+ loop.start = (t.maxsize - image_size) / t.banksize;
+ loop.end = t.maxsize / t.banksize;
+ break;
+ default:
+ loop.start = 0;
+ loop.end = 0;
+ break;
+ }
+ return loop;
+}
+
+function testrun(
+ d, mapper,
+ cpu_trans, cpu_image_size, cpu_device_size,
+ ppu_trans, ppu_image_size, ppu_device_size
+)
+{
+ local trans_empty = 0;
+ if((board.mappernum != mapper) && (mapper != 0)){
+ print("mapper number are not connected\n");
+ print("af:" + board.mappernum + " image:" + mapper + "\n");
+ }
+ local cpu_loop = loopsize_get(board.cpu, cpu_trans, cpu_image_size, cpu_device_size);
+ local ppu_loop = loopsize_get(board.ppu, ppu_trans, ppu_image_size, ppu_device_size);
+ if(board.vram_mirrorfind == true){
+ vram_mirrorfind(d);
+ }
+ initalize(d, board.cpu.banksize, board.ppu.banksize);
+ if(cpu_trans != trans_empty){
+ cpu_transfer(d, cpu_loop.start, cpu_loop.end, board.cpu.banksize);
+ }
+ if(ppu_trans != trans_empty){
+ ppu_transfer(d, ppu_loop.start, ppu_loop.end, board.ppu.banksize);
+ }
+}
+
+function program(
+ d, mapper,
+ cpu_trans, cpu_image_size, cpu_device_size,
+ ppu_trans, ppu_image_size, ppu_device_size
+)
+{
+ local trans_empty = 0;
+ if((board.mappernum != mapper) && (mapper != 0)){
+ return;
+ }
+ local cpu_loop = loopsize_get(board.cpu, cpu_trans, cpu_image_size, cpu_device_size);
+ local ppu_loop = loopsize_get(board.ppu, ppu_trans, ppu_image_size, ppu_device_size);
+ local co_cpu = newthread(cpu_transfer);
+ local co_ppu = newthread(ppu_transfer);
+ initalize(d, board.cpu.banksize, board.ppu.banksize);
+ if(cpu_trans != trans_empty){
+ cpu_erase(d);
+ }
+ if(ppu_trans != trans_empty){
+ ppu_erase(d);
+ }
+ erase_wait(d);
+ if(cpu_trans != trans_empty){
+ co_cpu.call(d, cpu_loop.start, cpu_loop.end, board.cpu.banksize);
+ }
+ if(ppu_trans != trans_empty){
+ co_ppu.call(d, ppu_loop.start, ppu_loop.end, board.ppu.banksize);
+ }
+ program_main(d, co_cpu, co_ppu)
+}
--- /dev/null
+//bit is masking MSB
+function mask_get(bit)
+{
+ local t = 1 << (bit + 1);
+ return t - 1;
+}
+function flash_device_get(name)
+{
+ local mega = 0x20000;
+ local MASK_A14 = mask_get(14);
+ local MASK_A10 = mask_get(10);
+ local device = {
+ ["dummy"] = {
+ capacity = 16 * mega, pagesize = 1,
+ erase_wait = 0, erase_require = false,
+ retry = false,
+ id_manufacurer = 0xf1, id_device = 0xf1,
+ command_mask = 0
+ },
+ ["W29C020"] = {
+ capacity = 2 * mega, pagesize = 0x80,
+ erase_wait = 50, erase_require = false,
+ retry = false,
+ id_manufacurer = 0xda, id_device = 0x45,
+ command_mask = MASK_A14
+ },
+ ["W29C040"] = {
+ capacity = 4 * mega, pagesize = 0x100,
+ erase_wait = 50, erase_require = false,
+ retry = true,
+ id_manufacurer = 0xda, id_device = 0x46,
+ command_mask = MASK_A14
+ },
+ ["W49F002"] = {
+ capacity = 2 * mega, pagesize = 1,
+ erase_wait = 100, erase_require = true,
+ retry = false,
+ id_manufacurer = 0xda, id_device = 0xae,
+ command_mask = MASK_A14
+ },
+ ["AT49F002"] = {
+ capacity = 2 * mega, pagesize = 1,
+ erase_wait = 100, erase_require = true,
+ retry = true,
+ id_manufacurer = 0x1f, id_device = 0x08,
+ command_mask = MASK_A14
+ },
+ ["EN29F002T"] = {
+ capacity = 2 * mega, pagesize = 1,
+ erase_wait = 2000, erase_require = true,
+ retry = false,
+ id_manufacurer = 0x1c, id_device = 0x92,
+ command_mask = MASK_A14
+ },
+ ["AM29F040B"] = {
+ capacity = 4 * mega, pagesize = 1,
+ erase_wait = 8000, erase_require = true,
+ retry = false,
+ id_manufacurer = 0x01, id_device = 0xa4,
+ command_mask = MASK_A10
+ },
+ //command mask is not written in datasheet!
+ ["PM29F002T"] = {
+ capacity = 2 * mega, pagesize = 1,
+ erase_wait = 500, erase_require = true,
+ retry = false,
+ id_manufacurer = 0x9d, id_device = 0x1d,
+ command_mask = MASK_A10 //maybe A10-A0
+ },
+ //chip erase time is not written in datasheet!!
+ ["MBM29F080A"] = {
+ capacity = 8 * mega, pagesize = 1,
+ erase_wait = 8000, erase_require = true,
+ retry = false,
+ id_manufacurer = 0x04, id_device = 0xd5,
+ command_mask = MASK_A10
+ },
+ ["SST39SF040"] = {
+ capacity = 4 * mega, pagesize = 1,
+ erase_wait = 100, erase_require = true,
+ retry = false,
+ id_manufacurer = 0xbf, id_device = 0xb7,
+ command_mask = MASK_A14
+ }
+ };
+ return device[name];
+}
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#ifdef WIN32
+ #include <windows.h>
+#endif
+#include "progress.h"
+
+void progress_init(void)
+{
+ printf("\n\n");
+}
+
+static void draw(const char *name, long offset, long count)
+{
+ if(count == 0){
+ printf("%s skip\n", name);
+ return;
+ }
+ const int barnum = 16;
+ const int unit = count / barnum;
+ int igeta = offset / unit;
+ char bar[barnum + 3 + 1];
+ char *t = bar;
+ int i;
+ assert(igeta <= barnum);
+ printf("%s 0x%06x/0x%06x ", name, (int)offset, (int)count);
+ *t++ = '|';
+ for(i = 0; i < igeta; i++){
+ if(i == barnum / 2){
+ *t++ = '|';
+ }
+ *t++ = '#';
+ }
+ for(; i < barnum; i++){
+ if(i == barnum / 2){
+ *t++ = '|';
+ }
+ *t++ = ' ';
+ }
+ *t++ = '|';
+ *t = '\0';
+ puts(bar);
+}
+void progress_draw(long program_offset, long program_count, long charcter_offset, long charcter_count)
+{
+#ifdef WIN32
+ HANDLE c;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ c = GetStdHandle(STD_OUTPUT_HANDLE);
+ if(GetConsoleScreenBufferInfo(c, &info) == 0){
+ //command.com, cygwin shell, mingw shell
+ printf("\x1b[2A\x1b[35D");
+ }else{
+ //cmd.exe
+ info.dwCursorPosition.X = 0;
+ info.dwCursorPosition.Y -= 2;
+ SetConsoleCursorPosition(c, info.dwCursorPosition);
+ }
+#else
+ printf("\x1b[2A\x1b[35D");
+#endif
+ draw("program memory ", program_offset, program_count);
+ draw("charcter memory", charcter_offset, charcter_count);
+ fflush(stdout);
+}
--- /dev/null
+#ifndef _PROGRESSS_H_
+#define _PROGRESSS_H_
+void progress_init(void);
+void progress_draw(long program_offset, long program_count, long charcter_offset, long charcter_count);
+#endif
--- /dev/null
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "reader_master.h"
+#include "reader_dummy.h"
+
+static void dummy_init(void)
+{
+}
+static int dummy_open_close(enum reader_control oc)
+{
+ return OK;
+}
+//---- cpu ----
+static void dummy_cpu_read(long address, long length, uint8_t *data)
+{
+ printf("%s %06x %04x\n", __FUNCTION__, (int) address, (int) length);
+ memset(data, 0x55, length);
+}
+static void dummy_cpu_write_6502(long address, long length, const uint8_t *data)
+{
+ printf("%s %04x %04x %02x\n", __FUNCTION__, (int) address, (int) length, (int) *data);
+}
+static void dummy_cpu_flash_config(long c000x, long c2aaa, long c5555, long unit, bool retry)
+{
+ printf("%s %04x %04x %04x %04x\n", __FUNCTION__, (int) c000x, (int) c2aaa, (int) c5555, (int) unit);
+}
+static long dummy_cpu_flash_program(long address, long length, const u8 *data, bool dowait, bool skip)
+{
+ int i = 0x10;
+ printf("%s %06x\n", __FUNCTION__, (int) address);
+ if(0){
+ while(i != 0){
+ printf("%02x ", *data);
+ data++;
+ i--;
+ }
+ printf("\n");
+ }
+ return 0x100;
+}
+
+static void dummy_cpu_flash_erase(long address, bool dowait)
+{
+ printf("%s %04x\n", __FUNCTION__, (int) address);
+}
+
+//---- ppu ----
+static void dummy_ppu_read(long address, long length, u8 *data)
+{
+ printf("%s %06x %04x\n", __FUNCTION__, (int) address, (int) length);
+ memset(data, 0x55, length);
+}
+static void dummy_ppu_write(long address, long length, const uint8_t *data)
+{
+ printf("%s %04x %04x %02x\n", __FUNCTION__, (int) address, (int) length, (int) *data);
+}
+static void dummy_ppu_flash_config(long c000x, long c2aaa, long c5555, long unit, bool retry)
+{
+ printf("%s %04x %04x %04x %04x\n", __FUNCTION__, (int) c000x, (int) c2aaa, (int) c5555, (int) unit);
+}
+static long dummy_ppu_flash_program(long address, long length, const u8 *data, bool dowait, bool skip)
+{
+ int i = 0x10;
+ printf("%s %06x\n", __FUNCTION__, (int) address);
+ if(0){
+ while(i != 0){
+ printf("%02x ", *data);
+ data++;
+ i--;
+ }
+ printf("\n");
+ }
+ return 0x100;
+}
+
+static void dummy_ppu_flash_erase(long address, bool dowait)
+{
+ printf("%s %04x\n", __FUNCTION__, (int) address);
+}
+
+static void dummy_flash_status(uint8_t s[2])
+{
+ s[0] = 0;
+ s[1] = 0;
+}
+static void dummy_flash_device_get(uint8_t s[2])
+{
+ s[0] = 0x01;
+ s[1] = 0xa4;
+}
+static uint8_t dummy_vram_connection(void)
+{
+ return 0x05;
+}
+const struct reader_driver DRIVER_DUMMY = {
+ .name = "tester",
+ .open_or_close = dummy_open_close,
+ .init = dummy_init,
+ .cpu_read = dummy_cpu_read, .ppu_read = dummy_ppu_read,
+ .cpu_write_6502 = dummy_cpu_write_6502,
+ .flash_support = true,
+ .ppu_write = dummy_ppu_write,
+ .cpu_flash_config = dummy_cpu_flash_config,
+ .cpu_flash_erase = dummy_cpu_flash_erase,
+ .cpu_flash_program = dummy_cpu_flash_program,
+ .cpu_flash_device_get = dummy_flash_device_get,
+ .ppu_flash_config = dummy_ppu_flash_config,
+ .ppu_flash_erase = dummy_ppu_flash_erase,
+ .ppu_flash_program = dummy_ppu_flash_program,
+ .ppu_flash_device_get = dummy_flash_device_get,
+ .flash_status = dummy_flash_status,
+ .vram_connection = dummy_vram_connection
+};
--- /dev/null
+#ifndef _READER_DUMMY_H_
+#define _READER_DUMMY_H_
+const struct reader_driver DRIVER_DUMMY;
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdbool.h>
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+#include "type.h"
+#include "header.h"
+#include "reader_master.h"
+#include "script.h"
+
+static struct anago_flash_order{
+ int program_count, command_change;
+ long address, length;
+ long c2aaa, c5555, unit;
+ struct memory *memory;
+ void (*config)(long c2aaa, long c5555, long unit);
+ void (*write)(long address, long length, const uint8_t *data);
+ void (*read)(long address, long length, u8 *data);
+ void (*erase)(long address, bool dowait);
+ long (*program)(long address, long length, u8 *data, bool dowait);
+}order_cpu, order_ppu;
+static inline long long_get(lua_State *t, int index)
+{
+ lua_Number d = lua_tonumber(t, index);
+ return (long) d;
+}
+static void command_set(lua_State *l, struct anago_flash_order *t)
+{
+ long command = long_get(l, 1);
+ long address = long_get(l, 2);
+ long mask = long_get(l, 3);
+ long d = command & (mask - 1);
+ d |= address;
+ switch(command){
+ case 0x02aa: case 0x2aaa:
+ t->c2aaa = d;
+ break;
+ case 0x0555: case 0x5555:
+ t->c5555 = d;
+ break;
+ default:
+ puts("unknown command address");
+ return;
+ }
+ t->command_change += 1;
+}
+static int cpu_command(lua_State *l)
+{
+ command_set(l, &order_cpu);
+ return 0;
+}
+static int ppu_command(lua_State *l)
+{
+ command_set(l, &order_ppu);
+ return 0;
+}
+static int write(lua_State *l, struct anago_flash_order *t)
+{
+ long address = long_get(l, 1);
+ long data = long_get(l, 2);
+ uint8_t d8 = (uint8_t) data;
+ t->write(address, 1, &d8);
+ return 0;
+}
+static int cpu_write(lua_State *l)
+{
+ return write(l, &order_cpu);
+}
+static int program_regist(lua_State *l, const char *name, struct anago_flash_order *t)
+{
+ t->address = long_get(l, 1);
+ t->length = long_get(l, 2);
+ if(t->command_change != 0){
+ t->config(t->c2aaa, t->c5555, t->unit);
+ t->command_change = 0;
+ }
+
+ printf("programming %s area 0x%06x...\n", name, t->memory->offset);
+ fflush(stdout);
+ return lua_yield(l, 0);
+}
+static void program_execute(struct anago_flash_order *t)
+{
+ if(t->program_count == 0){
+ t->erase(t->c2aaa, false);
+ t->program_count += 1;
+ printf("erase...\n");
+ fflush(stdout);
+ return;
+ }
+ t->program_count += 1;
+// printf("writing %06x\n", t->memory->offset);
+// fflush(stdout);
+ const long w = t->program(t->address, t->length, t->memory->data + t->memory->offset, false);
+ t->address += w;
+ t->length -= w;
+ t->memory->offset += w;
+}
+static int cpu_program(lua_State *l)
+{
+ return program_regist(l, "program ROM", &order_cpu);
+}
+static int ppu_program(lua_State *l)
+{
+ return program_regist(l, "charcter ROM", &order_ppu);
+}
+static int mmc1_write(lua_State *l)
+{
+ long address = long_get(l, 1);
+ uint8_t data = (uint8_t) long_get(l, 2);
+ int i = 5;
+ while(i != 0){
+ order_cpu.write(address, 1, &data);
+ data >>= 1;
+ i--;
+ }
+ return 0;
+}
+
+void script_execute(struct config *c)
+{
+ order_cpu.command_change = 0;
+ order_cpu.program_count = 0;
+ order_cpu.unit = c->flash_cpu->pagesize;
+ order_cpu.memory = &c->rom.cpu_rom;
+ order_cpu.config = c->reader->cpu_flash_config;
+ order_cpu.write = c->reader->cpu_write_6502;
+ order_cpu.read = c->reader->cpu_read;
+ order_cpu.erase = c->reader->cpu_flash_erase;
+ order_cpu.program = c->reader->cpu_flash_program;
+
+ order_ppu.command_change = 0;
+ order_ppu.program_count = 0;
+ order_ppu.unit = c->flash_ppu->pagesize;
+ order_ppu.memory = &c->rom.ppu_rom;
+ order_ppu.config = c->reader->ppu_flash_config;
+ order_ppu.write = c->reader->ppu_write; //warning ¤Ï̵»ë
+ order_ppu.read = c->reader->ppu_read;
+ order_ppu.erase = c->reader->ppu_flash_erase;
+ order_ppu.program = c->reader->ppu_flash_program;
+
+ lua_State *const l = lua_open();
+ luaL_openlibs(l);
+ lua_register(l, "cpu_write", cpu_write);
+ lua_register(l, "cpu_program", cpu_program);
+ lua_register(l, "cpu_command", cpu_command);
+ lua_register(l, "ppu_program", ppu_program);
+ lua_register(l, "ppu_command", ppu_command);
+ lua_register(l, "mmc1_write", mmc1_write);
+ if(luaL_loadfile(l, c->script) == LUA_ERRFILE){
+ lua_close(l);
+ return;
+ }
+ if(lua_pcall(l, 0, 0, 0) != 0){
+ puts(lua_tostring(l, -1));
+ return;
+ }
+ lua_getfield(l, LUA_GLOBALSINDEX, "initalize");
+ lua_getglobal(l, "initalize");
+ lua_call(l, 0, 0);
+ lua_State *const co_cpu = lua_newthread(l);
+ lua_State *const co_ppu = lua_newthread(l);
+ lua_getglobal(co_cpu, "program_cpu");
+ lua_getglobal(co_ppu, "program_ppu");
+ int state_cpu = LUA_YIELD, state_ppu = LUA_YIELD;
+ if(order_cpu.memory->size == 0 || c->flash_cpu->id_device == FLASH_ID_DEVICE_DUMMY){
+ state_cpu = 0;
+ }
+ if(order_ppu.memory->size == 0 || c->flash_ppu->id_device == FLASH_ID_DEVICE_DUMMY){
+ state_ppu = 0;
+ }
+ if(state_cpu != 0){
+ state_cpu = lua_resume(co_cpu, 0);
+ }
+ if(state_ppu != 0){
+ state_ppu = lua_resume(co_ppu, 0);
+ }
+ do{
+ uint8_t s[2];
+ Sleep(2);
+ c->reader->flash_status(s);
+ if(state_cpu != 0 && s[0] == 0){
+ if(order_cpu.length == 0){
+ state_cpu = lua_resume(co_cpu, 0);
+ }else{
+ program_execute(&order_cpu);
+ }
+ }
+ if(state_ppu != 0 && s[1] == 0){
+ if(order_ppu.length == 0){
+ state_ppu = lua_resume(co_ppu, 0);
+ }else{
+ program_execute(&order_ppu);
+ }
+ }
+ }while(state_cpu != 0 || state_ppu != 0);
+ lua_close(l);
+}
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <squirrel.h>
+#include <sqstdio.h>
+#include <sqstdaux.h>
+#include "type.h"
+#include "squirrel_wrap.h"
+#include "script_common.h"
+
+SQInteger script_nop(HSQUIRRELVM v)
+{
+ return 0;
+}
+
+SQInteger range_check(HSQUIRRELVM v, const char *name, long target, const struct range *range)
+{
+ if((target < range->start) || (target > range->end)){
+ printf("%s range must be 0x%06x to 0x%06x", name, (int) range->start, (int) range->end);
+ return sq_throwerror(v, "script logical error");
+ }
+ return 0;
+}
+
+SQInteger cpu_write_check(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x4000, 0x10000};
+ static const struct range range_data = {0x0, 0xff};
+ long address, data;
+ SQRESULT r = qr_argument_get(v, 2, &address, &data);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = range_check(v, "address", address, &range_address);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return range_check(v, "data", data, &range_data);
+}
+
+SQInteger script_require(HSQUIRRELVM v)
+{
+ if(sq_gettop(v) != 2){
+ return sq_throwerror(v, "argument number error");
+ }
+ if(sq_gettype(v, 2) != OT_STRING){
+ return sq_throwerror(v, "argument type error");
+ }
+ const SQChar *file;
+ if(SQ_FAILED(sq_getstring(v, 2, &file))){
+ return sq_throwerror(v, "require error");
+ }
+ if(SQ_FAILED(sqstd_dofile(v, _SC(file), SQFalse, SQTrue))){
+ return sq_throwerror(v, "require error");
+ }
+ return 0;
+}
--- /dev/null
+#ifndef _SCRIPT_COMMON_H_
+#define _SCRIPT_COMMON_H_
+struct range{
+ long start, end;
+};
+SQInteger script_nop(HSQUIRRELVM v);
+SQInteger range_check(HSQUIRRELVM v, const char *name, long target, const struct range *range);
+SQInteger cpu_write_check(HSQUIRRELVM v);
+SQInteger script_require(HSQUIRRELVM v);
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <squirrel.h>
+#include <sqstdio.h>
+#include <sqstdaux.h>
+#include "type.h"
+#include "header.h"
+#include "progress.h"
+#include "memory_manage.h"
+#include "reader_master.h"
+#include "squirrel_wrap.h"
+#include "script_common.h"
+#include "script_dump.h"
+
+struct dump_driver{
+ const char *target;
+ struct memory_driver{
+ struct memory memory;
+ long read_count;
+ void (*const write)(long address, long length, const uint8_t *data);
+ void (*const read)(long address, long length, u8 *data);
+ }cpu, ppu;
+ uint8_t (*const vram_connection)(void);
+ bool progress;
+};
+static SQInteger write_memory(HSQUIRRELVM v, struct memory_driver *t)
+{
+ long address, data;
+ SQRESULT r = qr_argument_get(v, 2, &address, &data);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ uint8_t d8 = (uint8_t) data;
+ t->write(address, 1, &d8);
+ return 0;
+}
+static SQInteger cpu_write(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return write_memory(v, &d->cpu);
+}
+
+static void buffer_show(struct memory *t, long length)
+{
+ int i;
+ const uint8_t *buf = t->data + t->offset;
+ printf("%s 0x%06x:", t->name, t->offset);
+ for(i = 0; i < 0x10; i++){
+ char dump[3+1];
+ sprintf(dump, "%02x", buf[i]);
+ switch(i){
+ case 7:
+ dump[2] = '-';
+ break;
+ case 0x0f:
+ dump[2] = '\0';
+ break;
+ default:
+ dump[2] = ' ';
+ break;
+ }
+ dump[3] = '\0';
+ printf("%s", dump);
+ }
+ int sum = 0;
+ while(length != 0){
+ sum += (int) *buf;
+ buf++;
+ length--;
+ }
+ printf(":0x%06x\n", sum);
+ fflush(stdout);
+}
+
+static void progress_show(struct dump_driver *d)
+{
+ if(d->progress == true){
+ progress_draw(d->cpu.memory.offset, d->cpu.memory.size, d->ppu.memory.offset, d->ppu.memory.size);
+ }
+}
+static SQInteger read_memory(HSQUIRRELVM v, struct memory_driver *t, bool progress)
+{
+ long address, length;
+ SQRESULT r = qr_argument_get(v, 2, &address, &length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ t->read(address, length == 0 ? 1: length, t->memory.data + t->memory.offset);
+ if((length != 0) && (progress == false)){
+ buffer_show(&t->memory, length);
+ }
+ t->memory.offset += length;
+ return 0;
+}
+static SQInteger cpu_read(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = read_memory(v, &d->cpu, d->progress);
+ progress_show(d);
+ return r;
+}
+
+static SQInteger ppu_read(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = read_memory(v, &d->ppu, d->progress);
+ progress_show(d);
+ return r;
+}
+
+static SQInteger ppu_ramfind(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ enum{
+ testsize = 8,
+ testaddress = 1234
+ };
+ static const uint8_t test_val[testsize] = {0xaa, 0x55, 0, 0xff, 0x46, 0x49, 0x07, 0x21};
+ static const uint8_t test_str[testsize] = "pputest";
+ uint8_t test_result[testsize];
+
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ d->ppu.write(testaddress, testsize, test_val);
+ d->ppu.read(testaddress, testsize, test_result);
+ if(memcmp(test_val, test_result, testsize) != 0){
+ sq_pushbool(v, SQFalse);
+ return 1;
+ }
+ d->ppu.write(testaddress, testsize, test_str);
+ d->ppu.read(testaddress, testsize, test_result);
+ if(memcmp(test_str, test_result, testsize) != 0){
+ sq_pushbool(v, SQFalse);
+ return 1;
+ }
+ d->ppu.memory.offset = 0;
+ d->ppu.memory.size = 0;
+ sq_pushbool(v, SQTrue);
+ return 1;
+}
+
+//test »þ/1ÅÙÌܤΠcall ¤Ç»ÈÍÑ
+static SQInteger memory_new(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = qr_argument_get(v, 2, &d->cpu.memory.size, &d->ppu.memory.size);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ d->cpu.memory.offset = 0;
+ d->cpu.memory.data = Malloc(d->cpu.memory.size);
+ d->ppu.memory.offset = 0;
+ d->ppu.memory.data = Malloc(d->ppu.memory.size);
+ return 0;
+}
+
+//dump »þ/2ÅÙÌܤΠcall ¤Ç nesfile_save ¤È¤·¤Æ»ÈÍÑ
+static SQInteger nesfile_save(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ struct romimage image;
+ long mirrorfind;
+ r = qr_argument_get(v, 2, &image.mappernum, &mirrorfind);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ image.cpu_rom = d->cpu.memory;
+ image.cpu_ram.data = NULL;
+ image.ppu_rom = d->ppu.memory;
+ image.mirror = MIRROR_PROGRAMABLE;
+ if(mirrorfind == 1){
+ if(d->vram_connection() == 0x05){
+ image.mirror = MIRROR_VERTICAL;
+ }else{
+ image.mirror = MIRROR_HORIZONAL;
+ }
+ }
+ image.backupram = 0;
+ nesfile_create(&image, d->target);
+ nesbuffer_free(&image, 0); //0 is MODE_xxx_xxxx
+
+ d->cpu.memory.data = NULL;
+ d->ppu.memory.data = NULL;
+ return 0;
+}
+
+//dump »þ/1ÅÙÌܤΠcall ¤Ç nesfile_save ¤È¤·¤Æ»ÈÍÑ
+static SQInteger length_check(HSQUIRRELVM v)
+{
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ bool cpu = true, ppu = true;
+ r = 0;
+ if(d->cpu.memory.size != d->cpu.read_count){
+ cpu = false;
+ }
+ if(cpu == false){
+ printf("cpu_romsize is not connected 0x%06x/0x%06x\n", (int) d->cpu.read_count, (int) d->cpu.memory.size);
+ }
+ if(d->ppu.memory.size != d->ppu.read_count){
+ ppu = false;
+ }
+ if(ppu == false){
+ printf("ppu_romsize is not connected 0x%06x/0x%06x\n", (int) d->ppu.read_count, (int) d->ppu.memory.size);
+ }
+ if(cpu == false || ppu == false){
+ r = sq_throwerror(v, "script logical error");
+ }
+ return r;
+}
+
+static SQInteger read_count(HSQUIRRELVM v, struct memory_driver *t, const struct range *range_address, const struct range *range_length)
+{
+ long address, length;
+ SQRESULT r = qr_argument_get(v, 2, &address, &length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = range_check(v, "length", length, range_length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ if((address < range_address->start) || ((address + length) > range_address->end)){
+ printf("address range must be 0x%06x to 0x%06x", (int) range_address->start, (int) range_address->end);
+ return sq_throwerror(v, "script logical error");;
+ }
+ t->read_count += length;
+ return 0;
+}
+static SQInteger cpu_read_count(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x8000, 0x10000};
+ //length == 0 ¤Ï Âоݥ¢¥É¥ì¥¹¤ò¸Æ¤ó¤Ç¡¢¥Ð¥Ã¥Õ¥¡¤Ë¤¤¤ì¤Ê¤¤¡£mmc2, mmc4 ¤Ç»ÈÍѤ¹¤ë¡£
+ static const struct range range_length = {0x0000, 0x4000};
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return read_count(v, &d->cpu, &range_address, &range_length);
+}
+
+static SQInteger ppu_read_count(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x0000, 0x2000};
+ static const struct range range_length = {0x0001, 0x2000};
+ struct dump_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return read_count(v, &d->ppu, &range_address, &range_length);
+}
+
+static bool script_execute(HSQUIRRELVM v, struct config_dump *c, struct dump_driver *d)
+{
+ bool ret = true;
+ if(SQ_FAILED(sqstd_dofile(v, _SC("dumpcore.nut"), SQFalse, SQTrue))){
+ printf("dump core script error\n");
+ ret = false;
+ }else if(SQ_FAILED(sqstd_dofile(v, _SC(c->script), SQFalse, SQTrue))){
+ printf("%s open error\n", c->script);
+ ret = false;
+ }else{
+ SQRESULT r = qr_call(
+ v, "dump", (SQUserPointer) d, true,
+ 3, c->mappernum, c->increase.cpu, c->increase.ppu
+ );
+ if(SQ_FAILED(r)){
+ ret = false;
+ Free(d->cpu.memory.data);
+ Free(d->ppu.memory.data);
+ d->cpu.memory.data = NULL;
+ d->ppu.memory.data = NULL;
+ }
+ }
+ return ret;
+}
+void script_dump_execute(struct config_dump *c)
+{
+ struct dump_driver d = {
+ .cpu = {
+ .memory = {
+ .name = "program",
+ .size = 0, .offset = 0,
+ .attribute = MEMORY_ATTR_WRITE,
+ .transtype = TRANSTYPE_FULL,
+ .data = NULL
+ },
+ .read_count = 0,
+ .write = c->reader->cpu_write_6502,
+ .read = c->reader->cpu_read
+ },
+ .ppu = {
+ .memory = {
+ .name = "charcter",
+ .size = 0, .offset = 0,
+ .attribute = MEMORY_ATTR_WRITE,
+ .transtype = TRANSTYPE_FULL,
+ .data = NULL
+ },
+ .read_count = 0,
+ .write = c->reader->ppu_write,
+ .read = c->reader->ppu_read
+ },
+ .vram_connection = c->reader->vram_connection,
+ .target = c->target,
+ .progress = c->progress
+ };
+ {
+ HSQUIRRELVM v = qr_open();
+ qr_function_register_global(v, "ppu_ramfind", script_nop);
+ qr_function_register_global(v, "cpu_write", cpu_write_check);
+ qr_function_register_global(v, "memory_new", memory_new);
+ qr_function_register_global(v, "nesfile_save", length_check);
+ qr_function_register_global(v, "cpu_read", cpu_read_count);
+ qr_function_register_global(v, "ppu_read", ppu_read_count);
+ qr_function_register_global(v, "require", script_require);
+ if(script_execute(v, c, &d) == false){
+ qr_close(v);
+ return;
+ }
+ qr_close(v);
+ }
+ if(c->progress == true){
+ progress_init();
+ }
+ {
+ HSQUIRRELVM v = qr_open();
+ qr_function_register_global(v, "memory_new", script_nop);
+ qr_function_register_global(v, "nesfile_save", nesfile_save);
+ qr_function_register_global(v, "cpu_write", cpu_write);
+ qr_function_register_global(v, "cpu_read", cpu_read);
+ qr_function_register_global(v, "ppu_read", ppu_read);
+ qr_function_register_global(v, "ppu_ramfind", ppu_ramfind);
+ qr_function_register_global(v, "require", script_require);
+ script_execute(v, c, &d);
+ qr_close(v);
+ }
+}
--- /dev/null
+#ifndef _SCRIPT_DUMP_H_
+#define _SCRIPT_DUMP_H_
+struct config_dump{
+ const char *script, *target;
+ const struct reader_driver *reader;
+ long mappernum;
+ //struct romimage rom;
+ struct {long cpu, ppu;} increase;
+ bool progress;
+};
+void script_dump_execute(struct config_dump *c);
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <squirrel.h>
+#include <sqstdio.h>
+#include <sqstdaux.h>
+#include <kazzo_task.h>
+#include "type.h"
+#include "header.h"
+#include "memory_manage.h"
+#include "reader_master.h"
+#include "squirrel_wrap.h"
+#include "flash_device.h"
+#include "progress.h"
+#include "script_common.h"
+#include "script_flash.h"
+
+struct anago_driver{
+ struct anago_flash_order{
+ bool command_change;
+ struct{
+ long address, length, count, offset;
+ }programming, compare;
+ long c000x, c2aaa, c5555;
+ struct memory *const memory;
+ struct flash_device *const device;
+ void (*const config)(long c000x, long c2aaa, long c5555, long unit, bool retry);
+ void (*const device_get)(uint8_t s[2]);
+ void (*const write)(long address, long length, const uint8_t *data);
+ void (*const read)(long address, long length, u8 *data);
+ void (*const erase)(long address, bool dowait);
+ long (*const program)(long address, long length, const u8 *data, bool dowait, bool skip);
+ }order_cpu, order_ppu;
+ void (*const flash_status)(uint8_t s[2]);
+ uint8_t (*const vram_connection)(void);
+ const enum vram_mirroring vram_mirroring;
+ bool compare, testrun;
+};
+
+static SQInteger vram_mirrorfind(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ if((d->vram_connection() == 0x05) != (d->vram_mirroring == MIRROR_VERTICAL)){
+ puts("warning: vram mirroring is inconnect");
+ }
+ return 0;
+}
+static SQInteger command_set(HSQUIRRELVM v, struct anago_flash_order *t)
+{
+ long command, address ,mask;
+ SQRESULT r = qr_argument_get(v, 3, &command, &address, &mask);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ long d = command & (mask - 1);
+ d |= address;
+ switch(command){
+ case 0x0000:
+ t->c000x = d;
+ break;
+ case 0x02aa: case 0x2aaa:
+ t->c2aaa = d;
+ break;
+ case 0x0555: case 0x5555:
+ t->c5555 = d;
+ break;
+ default:
+ return sq_throwerror(v, "unknown command address");
+ }
+ t->command_change = true;
+ return 0;
+}
+static SQInteger cpu_command(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return command_set(v, &d->order_cpu);
+}
+static SQInteger ppu_command(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return command_set(v, &d->order_ppu);
+}
+static SQInteger write_memory(HSQUIRRELVM v, struct anago_flash_order *t)
+{
+ long address, data;
+ SQRESULT r = qr_argument_get(v, 2, &address, &data);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ uint8_t d8 = (uint8_t) data;
+ t->write(address, 1, &d8);
+ return 0;
+}
+static SQInteger cpu_write(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return write_memory(v, &d->order_cpu);
+}
+static SQInteger erase_set(HSQUIRRELVM v, struct anago_flash_order *t, const char *region)
+{
+ t->config(t->c000x, t->c2aaa, t->c5555, t->device->pagesize, t->device->retry);
+ t->command_change = false;
+ if(t->device->erase_require == true){
+ t->erase(t->c2aaa, false);
+ printf("erasing %s memory...\n", region);
+ fflush(stdout);
+ }
+ return 0;
+}
+static SQInteger cpu_erase(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return erase_set(v, &d->order_cpu, "program");
+}
+static SQInteger ppu_erase(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return erase_set(v, &d->order_ppu, "charcter");
+}
+static SQInteger program_regist(HSQUIRRELVM v, const char *name, struct anago_flash_order *t)
+{
+ SQRESULT r = qr_argument_get(v, 2, &t->programming.address, &t->programming.length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ t->compare = t->programming;
+ t->compare.offset = t->memory->offset & (t->memory->size - 1);
+ if(t->command_change == true){
+ t->config(t->c000x, t->c2aaa, t->c5555, t->device->pagesize, t->device->retry);
+ t->command_change = false;
+ }
+
+/* printf("programming %s ROM area 0x%06x...\n", name, t->memory->offset);
+ fflush(stdout);*/
+ return sq_suspendvm(v);
+}
+static void program_execute(struct anago_flash_order *t)
+{
+ const long w = t->program(t->programming.address, t->programming.length, t->memory->data + t->memory->offset, false, t->device->erase_require);
+ t->programming.address += w;
+ t->programming.length -= w;
+ t->memory->offset += w;
+ t->memory->offset &= t->memory->size - 1;
+ t->programming.offset += w;
+}
+
+static bool program_compare(struct anago_flash_order *t)
+{
+ uint8_t *comparea = Malloc(t->compare.length);
+ bool ret = false;
+ if(t->device->erase_require == true){
+ memset(comparea, 0xff, t->compare.length);
+ int doread = memcmp(comparea, t->memory->data + t->compare.offset, t->compare.length);
+ if(0){
+ memset(comparea, 0, t->compare.length);
+ doread &= memcmp(comparea, t->memory->data + t->compare.offset, t->compare.length);
+ }
+ if(doread == 0){
+ Free(comparea);
+ return true;
+ }
+ }
+
+ t->read(t->compare.address, t->compare.length, comparea);
+ if(memcmp(comparea, t->memory->data + t->compare.offset, t->compare.length) == 0){
+ ret = true;
+ }
+ Free(comparea);
+ return ret;
+}
+static SQInteger cpu_program_memory(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return program_regist(v, "program", &d->order_cpu);
+}
+static SQInteger ppu_program_memory(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return program_regist(v, "charcter", &d->order_ppu);
+}
+
+static long erase_timer_get(struct anago_flash_order *t)
+{
+ if(
+ (t->memory->transtype != TRANSTYPE_EMPTY) &&
+ (t->device->erase_require == true)
+ ){
+ return t->device->erase_wait;
+ }else{
+ return 0;
+ }
+}
+static SQInteger erase_wait(HSQUIRRELVM v)
+{
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ if(0){
+ long timer_wait = erase_timer_get(&d->order_cpu);
+ long timer_ppu = erase_timer_get(&d->order_ppu);
+ if(timer_wait < timer_ppu){
+ timer_wait = timer_ppu;
+ }
+ wait(timer_wait);
+ }else{
+ uint8_t s[2];
+ do{
+ wait(2);
+ d->flash_status(s);
+ //ËÜÍè¤Î°Õ¿Þ¤«¤é¤Ç¤Ï¤³¤³¤Î¾ò·ï¼°¤Ï && ¤Ç¤Ï¤Ê¤¯ || ¤À¤¬¡¢Àè¤Ë erase ¤¬½ª¤ï¤Ã¤¿¥Ç¥Ð¥¤¥¹¤¬Æ°¤«¤»¤ë¤Î¤Ç»Ä¤·¤Æ¤ª¤¯
+ }while((s[0] != KAZZO_TASK_FLASH_IDLE) && (s[1] != KAZZO_TASK_FLASH_IDLE));
+ }
+ return 0;
+}
+
+static bool program_memoryarea(HSQUIRRELVM co, struct anago_flash_order *t, bool compare, const char *region, SQInteger *state, bool *console_update)
+{
+ if(t->programming.length == 0){
+ if(t->programming.offset != 0 && compare == true){
+ if(program_compare(t) == false){
+ printf("%s memory compare error\n", region);
+ return false;
+ }
+ }
+
+ sq_wakeupvm(co, SQFalse, SQFalse, SQTrue/*, SQTrue*/);
+ *state = sq_getvmstate(co);
+ }else{
+ program_execute(t);
+ *console_update = true;
+ }
+ return true;
+}
+
+static SQInteger program_main(HSQUIRRELVM v)
+{
+ if(sq_gettop(v) != (1 + 3)){ //roottable, userpointer, co_cpu, co_ppu
+ return sq_throwerror(v, "argument number error");
+ }
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ HSQUIRRELVM co_cpu, co_ppu;
+ if(SQ_FAILED(sq_getthread(v, 3, &co_cpu))){
+ return sq_throwerror(v, "thread error");
+ }
+ if(SQ_FAILED(sq_getthread(v, 4, &co_ppu))){
+ return sq_throwerror(v, "thread error");
+ }
+ SQInteger state_cpu = sq_getvmstate(co_cpu);
+ SQInteger state_ppu = sq_getvmstate(co_ppu);
+ const long sleepms = d->compare == true ? 6 : 2; //W29C040 ¤Ç compare ¤ò¤¹¤ë¤È¡¢error ¤¬½Ð¤ë¤Î¤Ç½Ð¤Ê¤¤ÃͤËÄ´À° (¤ä¤Ã¤Ä¤±Âбþ)
+
+ progress_init();
+ while((state_cpu != SQ_VMSTATE_IDLE) || (state_ppu != SQ_VMSTATE_IDLE)){
+ uint8_t s[2];
+ bool console_update = false;
+ wait(sleepms);
+ d->flash_status(s);
+ if(state_cpu != SQ_VMSTATE_IDLE && s[0] == KAZZO_TASK_FLASH_IDLE){
+ if(program_memoryarea(co_cpu, &d->order_cpu, d->compare, "program", &state_cpu, &console_update) == false){
+ return 0;
+ }
+ }
+ if(state_ppu != SQ_VMSTATE_IDLE && s[1] == KAZZO_TASK_FLASH_IDLE){
+ if(program_memoryarea(co_ppu, &d->order_ppu, d->compare, "charcter", &state_ppu, &console_update) == false){
+ return 0;
+ }
+ }
+ if((console_update == true) && (d->testrun == false)){
+ progress_draw(d->order_cpu.programming.offset, d->order_cpu.programming.count, d->order_ppu.programming.offset, d->order_ppu.programming.count);
+ }
+ }
+ return 0;
+}
+
+static SQInteger program_count(HSQUIRRELVM v, struct anago_flash_order *t, const struct range *range_address, const struct range *range_length)
+{
+ SQRESULT r = qr_argument_get(v, 2, &t->programming.address, &t->programming.length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = range_check(v, "length", t->programming.length, range_length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ if((t->programming.address < range_address->start) || ((t->programming.address + t->programming.length) > range_address->end)){
+ printf("address range must be 0x%06x to 0x%06x", (int) range_address->start, (int) range_address->end - 1);
+ return sq_throwerror(v, "script logical error");;
+ }
+ t->programming.count += t->programming.length;
+ return 0;
+}
+static SQInteger cpu_program_count(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x8000, 0x10000};
+ static const struct range range_length = {0x0100, 0x4000};
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return program_count(v, &d->order_cpu, &range_address, &range_length);
+}
+
+static SQInteger ppu_program_count(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x0000, 0x2000};
+ static const struct range range_length = {0x0100, 0x2000};
+ struct anago_driver *d;
+ SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ return program_count(v, &d->order_ppu, &range_address, &range_length);
+}
+
+static bool script_execute(HSQUIRRELVM v, const char *function, struct config_flash *c, struct anago_driver *d)
+{
+ bool ret = true;
+ if(SQ_FAILED(sqstd_dofile(v, _SC("flashcore.nut"), SQFalse, SQTrue))){
+ printf("flash core script error\n");
+ ret = false;
+ }else if(SQ_FAILED(sqstd_dofile(v, _SC(c->script), SQFalse, SQTrue))){
+ printf("%s open error\n", c->script);
+ ret = false;
+ }else{
+ SQRESULT r = qr_call(
+ v, function, (SQUserPointer) d, true,
+ 1 + 3 * 2, c->rom.mappernum,
+ d->order_cpu.memory->transtype, d->order_cpu.memory->size, d->order_cpu.device->capacity,
+ d->order_ppu.memory->transtype, d->order_ppu.memory->size, d->order_ppu.device->capacity
+ );
+ if(SQ_FAILED(r)){
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+void script_flash_execute(struct config_flash *c)
+{
+ struct anago_driver d = {
+ .order_cpu = {
+ .command_change = true,
+ .programming = {
+ .count = 0, .offset = 0
+ },
+ .device = &c->flash_cpu,
+ .memory = &c->rom.cpu_rom,
+ .config = c->reader->cpu_flash_config,
+ .device_get = c->reader->cpu_flash_device_get,
+ .write = c->reader->cpu_write_6502,
+ .read = c->reader->cpu_read,
+ .erase = c->reader->cpu_flash_erase,
+ .program = c->reader->cpu_flash_program
+ },
+ .order_ppu = {
+ .command_change = true,
+ .programming = {
+ .count = 0, .offset = 0
+ },
+ .device = &c->flash_ppu,
+ .memory = &c->rom.ppu_rom,
+ .config = c->reader->ppu_flash_config,
+ .device_get = c->reader->ppu_flash_device_get,
+ .write = c->reader->ppu_write,
+ .read = c->reader->ppu_read,
+ .erase = c->reader->ppu_flash_erase,
+ .program = c->reader->ppu_flash_program,
+ },
+ .flash_status = c->reader->flash_status,
+ .vram_connection = c->reader->vram_connection,
+ .vram_mirroring = c->rom.mirror,
+ .compare = c->compare,
+ .testrun = c->testrun
+ };
+ {
+ static const char *functionname[] = {
+ "cpu_erase", "ppu_erase",
+ "erase_wait", "program_main"
+ };
+ HSQUIRRELVM v = qr_open();
+ int i;
+ for(i = 0; i < sizeof(functionname)/sizeof(char *); i++){
+ qr_function_register_global(v, functionname[i], script_nop);
+ }
+ qr_function_register_global(v, "cpu_write", cpu_write_check);
+ qr_function_register_global(v, "cpu_command", cpu_command);
+ qr_function_register_global(v, "cpu_program", cpu_program_count);
+
+ qr_function_register_global(v, "ppu_program", ppu_program_count);
+ qr_function_register_global(v, "ppu_command", ppu_command);
+ qr_function_register_global(v, "vram_mirrorfind", vram_mirrorfind);
+
+ if(script_execute(v, "testrun", c, &d) == false){
+ qr_close(v);
+ return;
+ }
+ qr_close(v);
+ assert(d.order_cpu.memory->size != 0);
+ if(d.order_cpu.programming.count % d.order_cpu.memory->size != 0){
+ printf("logical error: cpu_programsize is not connected 0x%06x/0x%06x\n", (int) d.order_cpu.programming.count, (int) d.order_cpu.memory->size);
+ return;
+ }
+ if(d.order_ppu.memory->size != 0){
+ if(d.order_ppu.programming.count % d.order_ppu.memory->size != 0){
+ printf("logical error: ppu_programsize is not connected 0x%06x/0x%06x\n", (int) d.order_ppu.programming.count, (int) d.order_ppu.memory->size);
+ return;
+ }
+ }
+ }
+ d.order_cpu.command_change = true;
+ d.order_ppu.command_change = true;
+ {
+ HSQUIRRELVM v = qr_open();
+ qr_function_register_global(v, "cpu_write", cpu_write);
+ qr_function_register_global(v, "cpu_erase", cpu_erase);
+ qr_function_register_global(v, "cpu_program", cpu_program_memory);
+ qr_function_register_global(v, "cpu_command", cpu_command);
+ qr_function_register_global(v, "ppu_erase", ppu_erase);
+ qr_function_register_global(v, "ppu_program", ppu_program_memory);
+ qr_function_register_global(v, "ppu_command", ppu_command);
+ qr_function_register_global(v, "program_main", program_main);
+ qr_function_register_global(v, "erase_wait", erase_wait);
+ qr_function_register_global(v, "vram_mirrorfind", script_nop);
+ script_execute(v, "program", c, &d);
+ qr_close(v);
+ }
+}
--- /dev/null
+#ifndef _SCRIPT_FLASH_H_
+#define _SCRIPT_FLASH_H_
+struct config_flash{
+ const char *script, *target;
+ struct flash_device flash_cpu, flash_ppu;
+ const struct reader_driver *reader;
+ struct romimage rom;
+ bool compare, testrun;
+};
+void script_flash_execute(struct config_flash *c);
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <squirrel.h>
+#include <sqstdio.h>
+#include <sqstdaux.h>
+
+#ifdef SQUNICODE
+#define scvprintf vwprintf
+#else
+#define scvprintf vprintf
+#endif
+static void printfunc(HSQUIRRELVM v, const SQChar *s, ...)
+{
+ va_list arglist;
+ va_start(arglist, s);
+ scvprintf(s, arglist);
+ va_end(arglist);
+}
+
+HSQUIRRELVM qr_open(void)
+{
+ HSQUIRRELVM v = sq_open(0x400);
+ sqstd_seterrorhandlers(v);
+ sqstd_register_iolib(v);
+ sq_setprintfunc(v, printfunc);
+ sq_pushroottable(v);
+ return v;
+}
+
+//SQInteger
+void qr_function_register_global(HSQUIRRELVM v, const char *name, SQFUNCTION f)
+{
+ sq_pushroottable(v);
+ sq_pushstring(v, name, -1);
+ sq_newclosure(v, f, 0);
+ sq_createslot(v, -3);
+ sq_pop(v, 1);
+}
+
+SQRESULT qr_call(HSQUIRRELVM v, const SQChar *functionname, SQUserPointer up, bool settop, int argnum, ...)
+{
+ SQRESULT r = SQ_ERROR;
+ SQInteger top = sq_gettop(v);
+ sq_pushroottable(v);
+ sq_pushstring(v, _SC(functionname), -1);
+ if(SQ_SUCCEEDED(sq_get(v,-2))){
+ int i;
+ va_list ap;
+ va_start(ap, argnum);
+ sq_pushroottable(v);
+ sq_pushuserpointer(v, up);
+ for(i = 0; i < argnum; i++){
+ sq_pushinteger(v, va_arg(ap, long));
+ }
+ r = sq_call(v, 2 + argnum, SQFalse, SQTrue); //calls the function
+ }
+ if(settop == true){
+ sq_settop(v, top); //restores the original stack size
+ }
+ return r;
+}
+
+void qr_close(HSQUIRRELVM v)
+{
+ sq_pop(v, 1);
+ sq_close(v);
+}
+
+static bool long_get(HSQUIRRELVM v, SQInteger index, long *d)
+{
+ if(sq_gettype(v, index) != OT_INTEGER){
+ return false;
+ }
+ SQInteger i;
+ if(SQ_FAILED(sq_getinteger(v, index, &i))){
+ return false;
+ }
+ *d = (long) i;
+ return true;
+}
+
+SQRESULT qr_argument_get(HSQUIRRELVM v, SQInteger num, ...)
+{
+ va_list ap;
+ if(sq_gettop(v) != (num + 2)){ //roottable, up, arguments...
+ return sq_throwerror(v, "argument number error");
+ }
+ va_start(ap, num);
+ SQInteger i;
+ for(i = 0; i < num; i++){
+ if(long_get(v, i + 3, va_arg(ap, long *)) == false){
+ return sq_throwerror(v, "argument type error");
+ }
+ }
+ return SQ_OK;
+}
+
+SQRESULT qr_userpointer_get(HSQUIRRELVM v, SQUserPointer *up)
+{
+ SQRESULT r;
+ assert(sq_gettype(v, 2) == OT_USERPOINTER);
+ r = sq_getuserpointer(v, 2, up);
+ if(SQ_FAILED(r)){
+ return sq_throwerror(v, "1st argument must be d (userpointer)");
+ }
+ return r;
+}
--- /dev/null
+#ifndef _SQUIRREL_WRAP_H_
+#define _SQUIRREL_WRAP_H_
+HSQUIRRELVM qr_open(void);
+void qr_function_register_global(HSQUIRRELVM v, const char *name, SQFUNCTION f);
+SQRESULT qr_call(HSQUIRRELVM v, const SQChar *functionname, SQUserPointer up, bool settop, int argnum, ...);
+void qr_close(HSQUIRRELVM v);
+SQRESULT qr_argument_get(HSQUIRRELVM v, SQInteger num, ...);
+SQRESULT qr_userpointer_get(HSQUIRRELVM v, SQUserPointer *up);
+#endif
--- /dev/null
+#ifndef _CLIENT_TEST_H_
+#define _CLIENT_TEST_H_
+void client_test(const struct reader_driver *const d, const char *option, const char *file, const char *devicename, const char *mappername);
+#endif
--- /dev/null
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+#include "reader_master.h"
+enum{
+ CONFIG_OVERRIDE_UNDEF = 4649,
+ CONFIG_OVERRIDE_TRUE = 1,
+ CONFIG_STR_LENGTH = 20
+};
+struct st_config{
+ //override config
+ long mapper;
+ int mirror, backupram;
+ //target filename
+ const char *ramimage, *romimage;
+ const char *script;
+ //device driver function pointer struct
+ const struct reader_driver *reader;
+ const struct flash_driver *cpu_flash_driver, *ppu_flash_driver;
+ //data mode
+ int mode, syntaxtest;
+ long transtype_cpu, transtype_ppu;
+ //debug member
+ long write_wait;
+ char flash_test_device[CONFIG_STR_LENGTH];
+ char flash_test_mapper[CONFIG_STR_LENGTH];
+};
+
+enum{
+ MODE_TEST,
+ MODE_ROM_DUMP,
+ MODE_RAM_READ,
+ MODE_RAM_WRITE,
+ MODE_ROM_PROGRAM
+};
+
+#endif
--- /dev/null
+/*
+GZIP file format specification version 4.3
+*/
+#include "type.h"
+#include "crc32.h"
+#include "crctable.h"
+/*
+ Update a running crc with the bytes buf[0..len-1] and return
+ the updated crc. The crc should be initialized to zero. Pre- and
+ post-conditioning (one's complement) is performed within this
+ function so it shouldn't be done by the caller. Usage example:
+
+ unsigned long crc = 0L;
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = update_crc(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+static uint32_t update_crc(uint32_t crc, const uint8_t *buf, int len)
+{
+ uint32_t c = crc ^ 0xffffffffUL;
+ int n;
+
+ for (n = 0; n < len; n++) {
+ c = CRCTABLE[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+ }
+ return c ^ 0xffffffffUL;
+}
+
+/* Return the CRC of the bytes buf[0..len-1]. */
+//uint32_t crc(uint8_t *buf, int len) //ÊÑ¿ô̾¤È¤«¤Ö¤ë¤Î¤Ç¤«¤¨¤ë
+uint32_t crc32_get(const uint8_t *buf, int len)
+{
+ return update_crc(0UL, buf, len);
+}
--- /dev/null
+#ifndef _CRC32_H_
+#define _CRC32_H_
+uint32_t crc32_get(const uint8_t *buf, int len);
+#endif
--- /dev/null
+enum{
+ CRC_TABLE_NUM = 256
+};
+#if 0
+/* Table of CRCs of all 8-bit messages. */
+static unsigned long crc_table[CRC_TABLE_NUM];
+
+/* Flag: has the table been computed? Initially false. */
+static int crc_table_computed = 0;
+
+/* Make the table for a fast CRC. */
+void make_crc_table(void)
+{
+ unsigned long c;
+ int n, k;
+ for (n = 0; n < CRC_TABLE_NUM; n++) {
+ c = (unsigned long) n;
+ for (k = 0; k < 8; k++) {
+ if (c & 1) {
+ c = 0xedb88320L ^ (c >> 1);
+ } else {
+ c = c >> 1;
+ }
+ }
+ crc_table[n] = c;
+ }
+ crc_table_computed = 1;
+}
+#endif
+
+static const uint32_t CRCTABLE[CRC_TABLE_NUM] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
--- /dev/null
+#include <stdio.h>
+#include "memory_manage.h"
+#include "file.h"
+
+int buf_load(u8 *buf, const char *file, int size)
+{
+ FILE *fp;
+
+ fp = fopen(file, "rb");
+ if(fp == NULL){
+ return NG;
+ }
+ fseek(fp, 0, SEEK_SET);
+ fread(buf, sizeof(u8), size, fp);
+ fclose(fp);
+ return OK;
+}
+
+void* buf_load_full(const char *file, int *size)
+{
+ FILE *fp;
+ u8 *buf;
+
+ *size = 0;
+ fp = fopen(file, "rb");
+ if(fp == NULL){
+ return NULL;
+ }
+ fseek(fp, 0, SEEK_END);
+ *size = ftell(fp);
+ if(*size == 0){
+ fclose(fp);
+ return NULL;
+ }
+ fseek(fp, 0, SEEK_SET);
+ buf = Malloc(*size);
+ fread(buf, sizeof(u8), *size, fp);
+ fclose(fp);
+ return buf;
+}
+
+void buf_save(const void *buf, const char *file, int size)
+{
+ FILE *fp;
+
+ fp = fopen(file, "wb");
+ fseek(fp, 0, SEEK_SET);
+ fwrite(buf, sizeof(u8), size, fp);
+ fclose(fp);
+}
+
--- /dev/null
+#ifndef _FILE_H_
+#define _FILE_H_
+#include "type.h"
+int buf_load(u8 *buf, const char *file, int size);
+void* buf_load_full(const char *file, int *size);
+void buf_save(const void *buf, const char *file, int size);
+#endif
--- /dev/null
+LIBUSB_PATH = d:/dev/LibUSB-Win32
+OBJ = \
+ unagi.o header.o crc32.o \
+ script_engine.o script_syntax.o \
+ reader_master.o \
+ reader_onajimi.o reader_hongkongfc.o reader_kazzo.o \
+ flashmemory.o \
+ file.o textutil.o giveio.o usb_device.o unagi.res.o
+TARGET = unagi.exe
+CC = gcc
+CFLAGS += -Wall -Werror -Wmissing-declarations -I..
+CFLAGS = -I$(LIBUSB_PATH)/include -I.. -I../../kazzo/firmware
+LDFLAG = -L$(LIBUSB_PATH)/lib/gcc -lusb
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+flash memory driver
+
+Copyright (C) 2008-2009 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+flashmemory.c ¤À¤±¤Î·Ù¹ð
+¤³¤Î¥½¡¼¥¹¥³¡¼¥É¤ò»²¹Í¡¢Å¾ÍѤ·¤Æ¥·¥§¥¢¥¦¥§¥¢¤Ê¤É¤ÇÍø±×¤òÆÀ¤Ê¤¤¤³¤È¡£
+ȽÌÀ¤·¤¿¾ì¹ç¤Ï LGPL ¤¬Å¬ÍѤµ¤ì¡¢³ºÅö²Õ½ê¤Î¥½¡¼¥¹¤ò¸ø³«¤¹¤ëɬÍפ¬¤¢¤ë¡£
+*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include "type.h"
+#include "header.h"
+#include "flashmemory.h"
+
+/*
+---- erase ----
+*/
+#if 0 //DEBUG==1
+static void sram_erase(const struct flash_order *d)
+{
+ //bank ÀÚ¤êÂؤ¨¤¬È¼¤¦¤Î¤Ç¼ÂÁõ¤Ç¤¤Ê¤¤
+}
+#endif
+
+static void init_nop(const struct flash_order *d, long wait)
+{
+}
+
+static void init_erase(const struct flash_order *d, long wait)
+{
+ assert(d->pagesize > 0);
+ d->erase(d->command_2aaa, true);
+ Sleep(wait);
+}
+
+static void program_dummy(const struct flash_order *d, long address, long length, const struct memory *m)
+{
+}
+static void program_sram(const struct flash_order *d, long address, long length, const struct memory *m)
+{
+ d->write(address, length, m->data);
+}
+static void program_flash(const struct flash_order *d, long address, long length, const struct memory *m)
+{
+ d->program(address, length, m->data, true, false);
+}
+/*
+¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
+*/
+enum{MEGA = 0x20000};
+const struct flash_driver FLASH_DRIVER_UNDEF = {
+ .name = "undefined",
+ .capacity = 0,
+ .pagesize = 1,
+ .erase_wait = 0,
+ .command_mask = 0,
+ .id_manufacurer = 0,
+ .id_device = 0,
+ .productid_check = NULL,
+ .init = NULL,
+ .program = NULL
+};
+static const struct flash_driver DRIVER_SRAM = {
+ .name = "SRAM",
+ .capacity = 4 * MEGA,
+ .pagesize = 1,
+ .erase_wait = 0,
+ .command_mask = 0,
+ .id_manufacurer = FLASH_ID_DEVICE_SRAM,
+ .id_device = FLASH_ID_DEVICE_SRAM,
+// .productid_check = productid_sram,
+ .init = init_nop,
+ .program = program_sram
+};
+
+static const struct flash_driver DRIVER_DUMMY = {
+ .name = "dummy",
+ .capacity = 16 * MEGA,
+ .pagesize = 1,
+ .erase_wait = 0,
+ .command_mask = 0,
+ .id_manufacurer = FLASH_ID_DEVICE_DUMMY,
+ .id_device = FLASH_ID_DEVICE_DUMMY,
+// .productid_check = productid_sram,
+ .init = init_nop,
+ .program = program_dummy
+};
+
+static const struct flash_driver DRIVER_W29C020 = {
+ .name = "W29C020",
+ .capacity = 2 * MEGA,
+ .pagesize = 0x80,
+ .erase_wait = 50,
+ .command_mask = 0x7fff,
+ .id_manufacurer = 0xda,
+ .id_device = 0x45,
+// .productid_check = productid_check,
+ .init = init_nop,
+ .program = program_flash
+};
+
+static const struct flash_driver DRIVER_W29C040 = {
+ .name = "W29C040",
+ .capacity = 4 * MEGA,
+ .pagesize = 0x100,
+ .erase_wait = 50,
+ .command_mask = 0x7fff,
+ .id_manufacurer = 0xda,
+ .id_device = 0x46,
+// .productid_check = productid_check,
+ .init = init_nop,
+ .program = program_flash
+};
+
+static const struct flash_driver DRIVER_W49F002 = {
+ .name = "W49F002",
+ .capacity = 2 * MEGA,
+ .pagesize = 1,
+ .erase_wait = 100, //typ 0.1, max 0.2 sec
+ .command_mask = 0x7fff,
+ .id_manufacurer = 0xda,
+ .id_device = 0xae,
+// .productid_check = productid_check,
+ .init = init_erase,
+ .program = program_flash
+};
+
+/*
+MANUFATUTER ID 0x7f1c
+EN29F002T DEVICE ID 0x7f92
+EN29F002B DEVICE ID 0x7f97
+
+command address ¤¬ 0x00555, 0x00aaa ¤Ë¤Ê¤Ã¤Æ¤ë
+*/
+static const struct flash_driver DRIVER_EN29F002T = {
+ .name = "EN29F002T",
+ .capacity = 2 * MEGA,
+ .pagesize = 1,
+ .erase_wait = 2000, //typ 2, max 5 sec
+ .command_mask = 0x07ff,
+ .id_manufacurer = 0x1c,
+ .id_device = 0x92,
+// .productid_check = productid_check,
+ .init = init_erase,
+ .program = program_flash
+};
+
+static const struct flash_driver DRIVER_AM29F040B = {
+ .name = "AM29F040B",
+ .capacity = 4 * MEGA,
+ .pagesize = 1,
+ .erase_wait = 8000, //typ 8, max 64 sec
+ .command_mask = 0x07ff,
+ .id_manufacurer = 0x01,
+ .id_device = 0xa4,
+// .productid_check = productid_check,
+ .init = init_erase,
+ .program = program_flash
+};
+
+static const struct flash_driver DRIVER_MBM29F080A = {
+ .name = "MBM29F080A",
+ .capacity = 8 * MEGA,
+ .pagesize = 1,
+ .erase_wait = 8000, //chip erase time is not written in datasheet!!
+ .command_mask = 0x07ff,
+ .id_manufacurer = 0x04,
+ .id_device = 0xd5,
+// .productid_check = productid_check,
+ .init = init_erase,
+ .program = program_flash
+};
+
+static const struct flash_driver *DRIVER_LIST[] = {
+ &DRIVER_W29C020, &DRIVER_W29C040,
+ &DRIVER_W49F002, &DRIVER_EN29F002T, &DRIVER_AM29F040B, &DRIVER_MBM29F080A,
+ &DRIVER_SRAM,
+ &DRIVER_DUMMY,
+ NULL
+};
+
+const struct flash_driver *flash_driver_get(const char *name)
+{
+ const struct flash_driver **d;
+ d = DRIVER_LIST;
+ while(*d != NULL){
+ if(strcmp(name, (*d)->name) == 0){
+ return *d;
+ }
+ d++;
+ }
+ return NULL;
+}
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+flash memory driver
+
+Copyright (C) 2008-2009 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+flashmemory.c ¤À¤±¤Î·Ù¹ð
+¤³¤Î¥½¡¼¥¹¥³¡¼¥É¤ò»²¹Í¡¢Å¾ÍѤ·¤Æ¥·¥§¥¢¥¦¥§¥¢¤Ê¤É¤ÇÍø±×¤òÆÀ¤Ê¤¤¤³¤È¡£
+ȽÌÀ¤·¤¿¾ì¹ç¤Ï LGPL ¤¬Å¬ÍѤµ¤ì¡¢³ºÅö²Õ½ê¤Î¥½¡¼¥¹¤ò¸ø³«¤¹¤ëɬÍפ¬¤¢¤ë¡£
+*/
+#ifndef _FLASHMEMORY_H_
+#define _FLASHMEMORY_H_
+
+struct flash_order{
+ //JEDEC command ¤ò½¼¤Æ¤ë CPU/PPU ÏÀÍý¥¢¥É¥ì¥¹
+ long command_0000, command_2aaa, command_5555;
+ long command_mask;
+ long pagesize;
+ //struct reader_driver ¤Î´Ø¿ô¥Ý¥¤¥ó¥¿¤òÅϤ¹¾ì½ê
+ void (*config)(long c000, long c2aaa, long c5555, long unit, bool retry);
+ void (*erase)(long address, bool dowait);
+ void (*write)(long address, long length, uint8_t *data);
+ long (*program)(long address, long length, const uint8_t *data, bool dowait, bool skip);
+};
+
+struct memory;
+struct flash_driver{
+ const char *name;
+ long capacity, pagesize;
+ long command_mask;
+ long erase_wait; //unit is msec
+ u8 id_manufacurer, id_device;
+ int (*productid_check)(const struct flash_order *d, const struct flash_driver *f);
+ void (*init)(const struct flash_order *d, long wait);
+ void (*program)(const struct flash_order *d, long address, long length, const struct memory *m);
+};
+const struct flash_driver FLASH_DRIVER_UNDEF;
+const struct flash_driver *flash_driver_get(const char *name);
+
+//0x80 °Ê¹ß¤ÏËÜÅö¤Î¥Ç¥Ð¥¤¥¹½ÅÊ£¤·¤Ê¤¤¤È»×¤¦. 狼 JEDEC ¤Î¤È¤³¤ò¤·¤é¤Ù¤Æ.
+enum{
+ FLASH_ID_DEVICE_SRAM = 0xf0,
+ FLASH_ID_DEVICE_DUMMY
+};
+#endif
--- /dev/null
+/*
+ Win32 GIVEIO(DirectI/O Access) Service Controll Module
+*/
+
+#include "giveio.h"
+#include <windows.h>
+#include <stdio.h>
+
+/**-----------------------------------------------------**/
+
+/*
++--------------------+---------+----+----+----+----+--------------------+
+|Products |Version |PFID|MJRV|MNRV|BNUM| note
++--------------------+---------+----+----+----+----+--------------------+
+|Windows 95 |4.00.950 | 1 | 4 | 0 | 950|(Windows 95 + SP1) |
+|Windows 95 OSR 2 |4.00.950B| 1 | 4 | 0 |1111|(Windows 95 OSR 2.1)|
+|Windows 95 OSR 2.5 |4.00.950C| 1 | 4 | 0 |1212| |
+|Windows 98 |4.10.1998| 1 | 4 | 10 |1998| |
+|Windows 98 SE |4.10.2222| 1 | 4 | 10 |2222| |
+|Windows Me |4.90.3000| 1 | 4 | 90 |3000| |
+|Windows NT 4.0 |4.00.1381| 2 | 4 | 0 |1381| |
+|Windows 2000 |5.00.2195| 2 | 5 | 0 |2195| |
+|Windows XP |5.01.2600| 2 | 5 | 1 |2600| |
++--------------------+---------+----+----+----+----+--------------------+
+
+PFID = dwPlatformId
+MJRV = dwMajorVersion
+MNRV = dwMinorVersion
+BNUM = dwBuildNumber
+*/
+
+/* check the OS which GIVEIO should be necessary */
+static int is_winnt(void)
+{
+ OSVERSIONINFO osvi;
+
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if( !GetVersionEx(&osvi) )
+ return 0;
+
+ switch (osvi.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_NT:
+ return 1;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ return 0;
+ case VER_PLATFORM_WIN32s:
+ return 0;
+ }
+
+ /* unknown */
+ return 0;
+}
+
+/**-----------------------------------------------------**/
+
+/* connect to local service control manager */
+static SC_HANDLE hSCMan = NULL;
+static int OpenServiceControlManager(void)
+{
+ if(hSCMan==NULL)
+ {
+ /* connect to local service control manager */
+ if ((hSCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
+ return GetLastError();
+ }
+ return 0;
+}
+
+static void ClseServiceControlManager(void)
+{
+ if(hSCMan==NULL)
+ CloseServiceHandle(hSCMan);
+ hSCMan = NULL;
+}
+
+/**-----------------------------------------------------**/
+/* #define MAX_PATH 256 */
+static DWORD DriverInstall(LPCTSTR lpFname,LPCTSTR lpDriver)
+{
+ BOOL dwStatus = 0;
+ SC_HANDLE hService = NULL;
+ char *address;
+ char fullpath[MAX_PATH];
+
+ /* connect to local service control manager */
+ if(OpenServiceControlManager())
+ return 1;
+
+ /* get full path of driver file in current directry */
+ GetFullPathName(lpFname,MAX_PATH,fullpath,&address);
+
+ /* add to service control manager's database */
+ if ((hService = CreateService(hSCMan, lpDriver,
+ lpDriver, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
+ SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, fullpath,
+ NULL, NULL, NULL, NULL, NULL)) == NULL)
+ dwStatus = GetLastError();
+ else CloseServiceHandle(hService);
+
+ return dwStatus;
+}
+
+static DWORD DriverStart(LPCTSTR lpDriver)
+{
+ BOOL dwStatus = 0;
+ SC_HANDLE hService = NULL;
+
+ /* connect to local service control manager */
+ if(OpenServiceControlManager())
+ return 1;
+
+ // get a handle to the service
+ if ((hService = OpenService(hSCMan, lpDriver, SERVICE_ALL_ACCESS)) != NULL)
+ {
+ // start the driver
+ if (!StartService(hService, 0, NULL))
+ dwStatus = GetLastError();
+ } else dwStatus = GetLastError();
+
+ if (hService != NULL) CloseServiceHandle(hService);
+
+ return dwStatus;
+} // DriverStart
+
+/**-----------------------------------------------------**/
+static DWORD DriverStop(LPCTSTR lpDriver)
+{
+ BOOL dwStatus = 0;
+ SC_HANDLE hService = NULL;
+ SERVICE_STATUS serviceStatus;
+
+ /* connect to local service control manager */
+ if(OpenServiceControlManager())
+ return 1;
+
+
+ // get a handle to the service
+ if ((hService = OpenService(hSCMan, lpDriver,
+ SERVICE_ALL_ACCESS)) != NULL)
+ {
+ // stop the driver
+ if (!ControlService(hService, SERVICE_CONTROL_STOP,
+ &serviceStatus))
+ dwStatus = GetLastError();
+ } else dwStatus = GetLastError();
+
+ if (hService != NULL) CloseServiceHandle(hService);
+ return dwStatus;
+} // DriverStop
+
+/**-----------------------------------------------------**/
+static DWORD DriverRemove(LPCTSTR lpDriver)
+{
+ BOOL dwStatus = 0;
+ SC_HANDLE hService = NULL;
+
+ /* connect to local service control manager */
+ if(OpenServiceControlManager())
+ return 1;
+
+ // get a handle to the service
+ if ((hService = OpenService(hSCMan, lpDriver,
+ SERVICE_ALL_ACCESS)) != NULL)
+ {
+ // remove the driver
+ if (!DeleteService(hService))
+ dwStatus = GetLastError();
+ } else dwStatus = GetLastError();
+
+ if (hService != NULL) CloseServiceHandle(hService);
+ return dwStatus;
+} // DriverRemove
+
+/*****************************************************************************/
+
+const char giveio_dname[] = "\\\\.\\giveio"; /* device name */
+const char giveio_fname[] = "giveio.sys"; /* driver-file name */
+const char giveio_sname[] = "giveio"; /* service name */
+
+/*
+open & close "giveio" device for Direct I/O Access
+
+1st try : open giveio
+2nd try : start service & open
+3rd try : install current "giveio.sys" file & start & open
+*/
+
+int giveio_start(void)
+{
+ HANDLE h;
+ int res;
+
+ /* escape when Win95/98/Me */
+ if(!is_winnt())
+ return GIVEIO_WIN95;
+
+
+ /* WinNT , try GIVEIO */
+ res = GIVEIO_OPEN;
+ while(1)
+ {
+ if(res>=GIVEIO_INSTALL)
+ {
+/* printf("Install\n"); */
+ /* Install "GIVEIO.SYS" file in currect directry */
+ if( DriverInstall(giveio_fname,giveio_sname) )
+ {
+ /* if install error , no retry */
+ break;
+ }
+ }
+ if(res>=GIVEIO_START)
+ {
+/* printf("Start\n"); */
+ /* Start GIVEIO Service */
+ if( DriverStart(giveio_sname) )
+ {
+ /* error , retry with install */
+ res ++;
+ continue;
+ }
+ }
+/* printf("Open\n"); */
+ /* open driver */
+ h = CreateFile(giveio_dname, GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(h != INVALID_HANDLE_VALUE)
+ {
+ /* OK */
+ CloseHandle(h);
+ return res;
+ }
+ /* error , retry with Start,Install */
+ res++;
+ }
+
+ /* error */
+ return GIVEIO_ERROR;
+}
+
+int giveio_stop(int param)
+{
+ /* escape when Win95/98/Me */
+ if(!is_winnt())
+ return 0;
+
+ if(param>=GIVEIO_STOP)
+ {
+/* printf("Stop\n"); */
+ if( DriverStop(giveio_sname) )
+ return param;
+ if(param>=GIVEIO_REMOVE)
+ {
+/* printf("Remove\n"); */
+ if(DriverRemove(giveio_sname) )
+ return param;
+ }
+ }
+
+ ClseServiceControlManager();
+
+ /* Okay */
+ return 0;
+}
+
--- /dev/null
+#ifndef __GIVEIO_H__
+#define __GIVEIO_H__
+
+/* result of giveio_start() */
+#define GIVEIO_ERROR 0
+#define GIVEIO_WIN95 1 /* windows 95/98/Me, unnecessary */
+#define GIVEIO_OPEN 2 /* giveio opened */
+#define GIVEIO_START 3 /* giveio service start & opened */
+#define GIVEIO_INSTALL 4 /* giveio install,start & opened */
+int giveio_start(void);
+
+/* parameter of giveio_stop() */
+#define GIVEIO_STOP 3 /* giveio stop service */
+#define GIVEIO_REMOVE 4 /* giveio stop & remove driver */
+int giveio_stop(int param);
+
+#endif
--- /dev/null
+#ifndef _HARD_DOZEU_H_
+#define _HARD_DOZEU_H_
+enum{
+ DIRECTION_INPUT = 0,
+ DIRECTION_OUTPUT,
+ DIRECTION_INPUT_8BIT = 0,
+ DIRECTION_OUTPUT_8BIT = 0xff,
+};
+
+enum{
+ WAVEFORM_BANK_CPU_6502_HIGH = 0,
+ WAVEFORM_BANK_CPU_FLASH_HIGH,
+ WAVEFORM_BANK_PPU,
+ WAVEFORM_BANK_CPU_6502_LOW,
+ WAVEFORM_BANK_UNDEF = 123
+};
+enum{
+ WAVEFORM_WAVE_READ_SINGLE = 0,
+ WAVEFORM_WAVE_WRITE_SINGLE,
+ WAVEFORM_WAVE_READ_MULTI,
+ WAVEFORM_WAVE_WRITE_MULTI,
+};
+#endif
--- /dev/null
+#ifndef _HONGKONGFC_HARD_H_
+#define _HONGKONGFC_HARD_H_
+/*
+DATA PORT
+BIT0-BIT7: DATA IN/OUT, ADDRESS, BUS CONTROL
+STATUS PORT:
+BIT7: DATA ½ÐÎϳÎǧ?
+CONTROL PORT:
+BIT~0: DATA PORT LATCH CLOCK
+ H->L ¤Ç LATCH
+BIT~1 2 3: DATA PORT SELECT
+BIT4: ³ä¤ê¹þ¤ßµö²Ä MUST BE 0
+BIT5: PORT DIRECTION
+ L PC->BUS
+ H BUS->PC
+*/
+enum{
+ BITNUM_CONTROL_DATA_LATCH = 0,
+ BITNUM_CONTROL_DATA_SELECT,
+ BITNUM_CONTROL_INTERRUPT = 4,
+ BITNUM_CONTROL_DIRECTION
+};
+/*
+DATA PORT SELECT
+0: DATA BUS DIRECTION PC->BUS
+1: DATA BUS DIRECTION BUS->PC
+2: WRITE->READ ¤ËÀڤ괹¤¨¤ë¤È DATA_SELECT_A23toA16 ¤¬ÇË»¤¹¤ë
+3: WRITE->READ ¤ËÀڤ괹¤¨¤ë¤È DATA_SELECT_CONTROL ¤¬ÇË»¤¹¤ë
+4: LATCH cartridge control
+5: LATCH A23-A16, fc ¤Ç¤Ï write data
+6: LATCH A15-A8
+7: LATCH A7-A0
+*/
+enum{
+ DATA_SELECT_WRITE = 0,
+ DATA_SELECT_READ,
+ DATA_SELECT_BREAK_DATA,
+ DATA_SELECT_BREAK_CONTROL,
+ DATA_SELECT_A7toA0 = 4,
+ DATA_SELECT_A15toA8,
+ DATA_SELECT_A23toA16,
+ DATA_SELECT_CONTROL,
+ DATA_SELECT_WRITEDATA = DATA_SELECT_A23toA16
+};
+enum{
+ BITNUM_PPU_OUTPUT = 0,
+ BITNUM_PPU_SELECT,
+ BITNUM_PPU_RW,
+ //bit3̤»ÈÍÑ
+ BITNUM_WRITEDATA_OUTPUT = 4, //b0 L ¤Ç½ÐÎÏ
+ BITNUM_WRITEDATA_LATCH, //b1 L->H
+ BITNUM_CPU_RW, //b2
+ BITNUM_CPU_M2 //b3
+};
+#endif
--- /dev/null
+#ifndef _HARD_ONAJIMI_H_
+#define _HARD_ONAJIMI_H_
+/*
+STROB: CPU/PPU ADDRESS BUS control
+L Address reset, address = 0
+H Address Enable
+*/
+enum{
+ ADDRESS_RESET = 1,
+ ADDRESS_ENABLE = 0
+};
+/*
+D0: CPU/PPU ADDRESS BUS increment
+D1: CPU/PPU DATA SHIFT
+D2: CPU/PPU DATA WRITE DATA
+D3: CPU/PPU DATA DIRECTION
+D4: PPU /WR + CPU ¦Õ2
+D5: PPU /CS
+D6: CPU ROM area /CS
+D7: CPU /WR
+*/
+enum BITNUM{
+ BITNUM_ADDRESS_INCREMENT = 0,
+ BITNUM_DATA_SHIFT_RIGHT,
+ BITNUM_DATA_WRITE_DATA,
+ BITNUM_DATA_DIRECTION,
+ BITNUM_CPU_M2,
+ BITNUM_PPU_SELECT,
+ BITNUM_CPU_RAMROM_SELECT,
+ BITNUM_CPU_RW,
+ BITNUM_PPU_RW = BITNUM_CPU_M2
+};
+/*
+D0: CPU/PPU ADDRESS BUS increment
+H->L address += 1
+
+D1: CPU/PPU DATA SHIFT (¥Ð¥¹¤ÎÀܳ¤¬È¿Å¾¤·¤Æ¤¤¤ë)
+L->H D01234567
+
+D2: CPU/PPU DATA WRITE DATA
+LSB->MSB ºÇ²¼°Ìbit¤«¤é½ç¤Ë¡£
+*/
+enum{
+ ADDRESS_NOP = 1 << BITNUM_ADDRESS_INCREMENT,
+ DATA_SHIFT_NOP = 0 << BITNUM_DATA_SHIFT_RIGHT
+};
+/*
+D3: CPU/PPU DATA DIRECTION
+H FC read
+L FC write
+*/
+enum{
+ DATA_DIRECTION_WRITE = 0,
+ DATA_DIRECTION_READ = 1
+};
+/*
+D4: PPU /WE + CPU M2
+H PPU read + CPU bus enable (for MMC5)
+L PPU write + CPU bus disable
+*/
+enum{
+ PPU_WRITE__CPU_DISABLE = 0,
+ PPU_READ__CPU_ENABLE
+};
+/*
+D5: PPU /RD + PPU A13
+H disable
+L enable
+*/
+enum{
+ PPU_ENABLE = 0,
+ PPU_DISABLE
+};
+/*
+D6: CPU ROM select (~A15)
+H RAM IO select, use $0000-$7fff
+L ROM select, use $8000-$ffff
+*/
+enum{
+ CPU_ROM_SELECT = 0,
+ CPU_RAM_SELECT
+};
+/*
+D7: CPU W/~R
+L write
+H read
+*/
+enum{
+ CPU_WRITE = 0,
+ CPU_READ
+};
+/*
+BUSY: CPU/PPU DATA READ DATA
+LSB->MSB ºÇ²¼°Ìbit¤«¤é½ç¤Ë¡£
+*/
+#endif
--- /dev/null
+/*
+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
--- /dev/null
+#ifndef _HEADER_H_
+#define _HEADER_H_
+#if ANAGO==0
+#include "flashmemory.h"
+#endif
+enum trastype{
+ TRANSTYPE_EMPTY,
+ TRANSTYPE_TOP,
+ TRANSTYPE_BOTTOM,
+ TRANSTYPE_FULL,
+};
+enum memory_attribute{
+ MEMORY_ATTR_READ, MEMORY_ATTR_WRITE, MEMORY_ATTR_NOTUSE
+};
+struct memory{
+ const char *name;
+ int size, offset;
+ enum memory_attribute attribute;
+ enum trastype transtype;
+ uint8_t *data;
+};
+/*
+ROM image Æâ struct memory ¤Î¥â¡¼¥ÉÊ̤λȤ¤Êý
+MODE_ROM_DUMP
+ cpu_rom ROM Æɤ߹þ¤ß¥Ð¥Ã¥Õ¥¡, file out
+ ppu_rom ROM Æɤ߹þ¤ß¥Ð¥Ã¥Õ¥¡, file out
+ cpu_ram ̤»ÈÍÑ
+MODE_RAM_READ
+ cpu_rom ̤»ÈÍÑ
+ ppu_rom ̤»ÈÍÑ
+ cpu_ram RAM Æɤ߹þ¤ß¥Ð¥Ã¥Õ¥¡. file out
+MODE_RAM_WRITE
+ cpu_rom ̤»ÈÍÑ
+ ppu_rom ̤»ÈÍÑ
+ cpu_ram RAM ½ñ¤¹þ¤ß¥Ð¥Ã¥Õ¥¡. . file in
+MODE_ROM_PROGRAM
+ cpu_rom ROM ½ñ¤¹þ¤ß¥Ð¥Ã¥Õ¥¡, file in
+ ppu_rom ROM ½ñ¤¹þ¤ß¥Ð¥Ã¥Õ¥¡, file in
+ cpu_ram ̤»ÈÍÑ
+*/
+enum vram_mirroring{
+ MIRROR_HORIZONAL = 0,
+ MIRROR_VERTICAL,
+ MIRROR_PROGRAMABLE = MIRROR_HORIZONAL
+};
+struct romimage{
+ struct memory cpu_rom, ppu_rom, cpu_ram;
+#if ANAGO==0
+ struct flash_order cpu_flash, ppu_flash;
+#endif
+ long mappernum;
+ enum vram_mirroring mirror;
+ int backupram;
+};
+
+enum{
+ MEMORY_AREA_CPU_RAM, MEMORY_AREA_CPU_ROM, MEMORY_AREA_PPU
+};
+#ifdef HEADEROUT
+void nesheader_set(const struct romimage *r, uint8_t *header);
+#endif
+bool nesbuffer_malloc(struct romimage *r, int mode);
+void nesfile_create(struct romimage *r, const char *romfilename);
+void nesbuffer_free(struct romimage *r, int mode);
+void backupram_create(const struct memory *r, const char *ramfilename);
+int memorysize_check(const long size, int region);
+bool nesfile_load(const char *errorprefix, const char *file, struct romimage *r);
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "memory_manage.h"
+enum{
+ MANAGE_NUM = 0x100
+};
+
+struct manage{
+ const char *file, *function;
+ int line;
+ void *addr;
+ int size;
+};
+static const struct manage EMPTY = {
+ .file = NULL, .line = 0, .function = NULL,
+ .addr = NULL, .size = 0
+};
+static struct manage management[MANAGE_NUM];
+void mm_init(void)
+{
+ int i;
+ for(i = 0; i < MANAGE_NUM; i++){
+ management[i] = EMPTY;
+ }
+}
+void *mm_malloc(const char *file, int line, const char *function, int size)
+{
+ int i;
+ struct manage *t = management;
+ for(i = 0; i < MANAGE_NUM; i++){
+ if(t->addr == NULL){
+ t->addr = malloc(size);
+ t->size = size;
+ t->file = file;
+ t->line = line;
+ t->function = function;
+ return t->addr;
+ }
+ t++;
+ }
+ assert(0);
+ return NULL;
+}
+void mm_free(void *addr)
+{
+ int i;
+ struct manage *t = management;
+ for(i = 0; i < MANAGE_NUM; i++){
+ if(t->addr == addr){
+ free(addr);
+ *t = EMPTY;
+ return;
+ }
+ t++;
+ }
+ assert(0);
+}
+void mm_end(void)
+{
+ int i;
+ struct manage *t = management;
+ for(i = 0; i < MANAGE_NUM; i++){
+ if(t->addr != NULL){
+ printf("**free forgot** %s:%d %s() size %d\n", t->file, t->line, t->function, t->size);
+ }
+ t++;
+ }
+}
--- /dev/null
+#ifndef _MEMORY_MANAGE_H_
+#define _MEMORY_MANAGE_H_
+void *mm_malloc(const char *file, int line, const char *function, int size);
+void mm_free(void *addr);
+#if DEBUG == 0
+ #define mm_init(a)
+ #define mm_end(a)
+#include <stdlib.h>
+ #define Malloc(size) malloc(size)
+ #define Free(addr) free(addr)
+#else
+ void mm_init(void);
+ void mm_end(void);
+ #define Malloc(size) mm_malloc(__FILE__, __LINE__, __FUNCTION__, size)
+ #define Free(addr) mm_free(addr)
+#endif
+#endif
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+¥Ñ¥é¥ì¥ë¥Ý¡¼¥È¶¦ÍÄêµÁ
+*/
+#ifndef _PARALELL_PORT_INLINE_H_
+#define _PARALELL_PORT_INLINE_H_
+#include "giveio.h"
+#include <windows.h>
+#define ASM_ENABLE (0)
+enum{
+ PORT_DATA = 0x0378,
+ PORT_BUSY,
+ PORT_CONTROL
+};
+
+int _inp(int);
+#if ASM_ENABLE==0
+void _outp(int, int);
+#else
+static inline void _outp(int address, int data){
+ asm(
+ " movl %0,%%edx\n"
+ " movl %1,%%eax\n"
+ " out %%al,%%dx\n"
+ :: "q"(address), "q"(data): "%edx", "%eax"
+ );
+}
+#endif
+
+#endif
--- /dev/null
+include ../file.mak
+CFLAGS += -O2 -pg -DDEBUG=0
+VPATH = ..
+$(TARGET): $(OBJ)
+ $(CC) -pg -o $@ $(OBJ)
+
+include ../rule.mak
+#---- depend file ----
+-include unagi.d
--- /dev/null
+#ifndef _READER_DOZEU_H_
+#define _READER_DOZEU_H_
+const struct reader_driver DRIVER_DOZEU;
+#endif
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+hongkong FC driver
+
+Copyright (C) 2008 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+»ÅÍÍÉÔÌÀÍ×ÁÇ:
+ * 74138 ¤Î channel select ¤À¤¬¡¢¥Ñ¥é¥ì¥ë¥Ý¡¼¥È¤Î¥Ç¡¼¥¿¤ÎÊý¸þ¤òÊѹ¹¤¹¤ë¤È¡¢ÆÃÄê¤Î¥Á¥ã¥ó¥Í¥ë¤Î¥Ç¡¼¥¿¤¬Ç˲õ¤µ¤ì¤ë
+ * Ç˲õ¤µ¤ì¤ë¤¬¡¢Ç˲õÀ褬ÀßÄê¤Ç¤¤ë¤é¤·¤¯¤½¤ì¤Ë¤·¤¿
+*/
+#include "type.h"
+#include "paralellport.h"
+#include "reader_master.h"
+#include "reader_hongkongfc.h"
+#include "hard_hongkongfc.h"
+
+enum{
+ PORT_CONTROL_MASK_XOR = 0x03, //bit01 invert
+ PORT_CONTROL_READ = 0,
+ PORT_CONTROL_WRITE
+};
+
+static inline int busy_get(void)
+{
+ int d = _inp(PORT_BUSY);
+ d >>= 7;
+ return d ^ 1;
+}
+
+static inline void port_control_write(int s, int rw)
+{
+ if(rw == PORT_CONTROL_READ){
+ //H:BUS->PC
+ s = bit_set(s, BITNUM_CONTROL_DIRECTION);
+ }else{
+ //L:PC->BUS
+ s = bit_clear(s, BITNUM_CONTROL_DIRECTION);
+ }
+ s = bit_clear(s, BITNUM_CONTROL_INTERRUPT);
+ s ^= PORT_CONTROL_MASK_XOR;
+ _outp(PORT_CONTROL, s);
+}
+
+static inline void data_port_latch(int select, long data)
+{
+ select <<= BITNUM_CONTROL_DATA_SELECT;
+ select = bit_set(select, BITNUM_CONTROL_DATA_LATCH);
+ port_control_write(select, PORT_CONTROL_WRITE);
+ _outp(PORT_DATA, data);
+ select = bit_clear(select, BITNUM_CONTROL_DATA_LATCH);
+ port_control_write(select, PORT_CONTROL_WRITE);
+}
+
+enum{ADDRESS_CPU_OPEN, ADDRESS_CPU_CLOSE};
+static inline void address_set(long address)
+{
+ long address_h = address >> 8;
+ long address_l = address & 0xff;
+ data_port_latch(DATA_SELECT_A15toA8, address_h);
+ data_port_latch(DATA_SELECT_A7toA0, address_l);
+}
+
+static inline u8 data_port_get(long address, int bus)
+{
+ address_set(address);
+ if(bus != 0){
+ data_port_latch(DATA_SELECT_CONTROL, bus);
+ }
+ port_control_write(DATA_SELECT_BREAK_DATA << BITNUM_CONTROL_DATA_SELECT, PORT_CONTROL_WRITE);
+ int s = DATA_SELECT_READ << BITNUM_CONTROL_DATA_SELECT;
+ s = bit_set(s, BITNUM_CONTROL_DATA_LATCH);
+ port_control_write(s, PORT_CONTROL_READ);
+ return (u8) _inp(PORT_DATA);
+}
+
+/*
+ËÜÂÎ A23-A16 port ¤Ë latch ¤µ¤»¤¿¤¢¤È¤Ë¡¢
+fc adapater ÆâÉô¤Ë¤µ¤é¤Ë latch ¤µ¤»¤ë¡£
+*/
+static void data_port_set(int c, long data)
+{
+ data_port_latch(DATA_SELECT_WRITEDATA, data);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ c = bit_set(c, BITNUM_WRITEDATA_LATCH);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+}
+
+// /A15 ¤À¤±¤ò»ÈÍѤ¹¤ë
+static const int BUS_CONTROL_CPU_READ = (
+ (1 << BITNUM_PPU_OUTPUT) |
+ (1 << BITNUM_PPU_RW) |
+ (1 << BITNUM_PPU_SELECT) |
+ (1 << BITNUM_WRITEDATA_OUTPUT) |
+ (0 << BITNUM_WRITEDATA_LATCH) |
+ (1 << BITNUM_CPU_M2) |
+ (1 << BITNUM_CPU_RW)
+);
+static const int BUS_CONTROL_PPU_READ = (
+ (0 << BITNUM_PPU_OUTPUT) |
+ (1 << BITNUM_PPU_RW) |
+ (0 << BITNUM_PPU_SELECT) |
+ (1 << BITNUM_WRITEDATA_OUTPUT) |
+ (0 << BITNUM_WRITEDATA_LATCH) |
+ (1 << BITNUM_CPU_M2) |
+ (1 << BITNUM_CPU_RW)
+);
+//static const int BUS_CONTROL_BUS_STANDBY = BUS_CONTROL_CPU_READ; //¥¨¥é¡¼¤Ë¤Ê¤ë
+#define BUS_CONTROL_BUS_STANDBY BUS_CONTROL_CPU_READ
+/*
+namcot ¤Î SRAM ÉÕ¥«¡¼¥È¥ê¥Ã¥¸¤Ï¦Õ2¤ò0x80²ó¾å¤²¤ë¤È½ÐÎϤ¬°ÂÄꤹ¤ë
+RAM ¥¢¥À¥×¥¿¤âƱÍÍ??
+ÉÔ°ÂÄê»þ¤Ï CPU ¤È PPU ¤Î data ¤¬º®¹ç¤µ¤ì¤Æ¤¤¤ëʪ¤¬¤Ç¤Æ¤¤¤ëµ¤¤¬¤¹¤ë
+*/
+static void hk_init(void)
+{
+ int c = BUS_CONTROL_CPU_READ;
+ int i = 0x80;
+ while(i != 0){
+ c = bit_set(c, BITNUM_CPU_M2);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ c = bit_clear(c, BITNUM_CPU_M2);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ i--;
+ }
+}
+
+static void hk_cpu_read(long address, long length, u8 *data)
+{
+ //fc bus ½é´ü²½
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_CPU_READ);
+ //A15 ¤òȿž¤·¡¢ /ROMCS ¤Ë¤·¤¿¤â¤Î¤òÅϤ¹
+ address ^= ADDRESS_MASK_A15;
+ while(length != 0){
+ *data = data_port_get(address, 0);
+ address++;
+ data++;
+ length--;
+ }
+}
+
+//patch. charcter ¤Î½ñ¤¹þ¤ß¤Î°ÂÄ꤬²þÁ±¤µ¤ì¤¿¤éºï½ü¤¹¤ë
+int hongkong_flash_patch = 0;
+static void hk_ppu_read(long address, long length, u8 *data)
+{
+ if(hongkong_flash_patch == 0){
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_BUS_STANDBY);
+ }else{
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_PPU_READ);
+ }
+
+ address &= ADDRESS_MASK_A0toA12; //PPU charcter data area mask
+ address |= ADDRESS_MASK_A15; //CPU area disk
+ while(length != 0){
+ if(hongkong_flash_patch == 0){
+ *data = data_port_get(address, BUS_CONTROL_PPU_READ);
+ }else{
+ *data = data_port_get(address, 0);
+ }
+ address++;
+ data++;
+ length--;
+ if(hongkong_flash_patch == 0){
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_BUS_STANDBY);
+ }
+ }
+}
+
+static inline void cpu_romcs_set(long address)
+{
+ data_port_latch(DATA_SELECT_A15toA8, address >> 8);
+}
+
+static void hk_cpu_write_6502(long address, long length, const uint8_t *data)
+{
+ while(length != 0){
+ int c = BUS_CONTROL_BUS_STANDBY;
+ //Á´¤Æ¤Î¥Ð¥¹¤ò»ß¤á¤ë
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ // /rom ¤ò H ¤Ë¤·¤Æ¥Ð¥¹¤ò»ß¤á¤ë
+ address_set(address | ADDRESS_MASK_A15);
+
+ //¦Õ2 = L, R/W=L, address set, data set
+ c = bit_clear(c, BITNUM_CPU_M2);
+ data_port_set(c, *data); //latch¤Ï¤³¤Î´Ø¿ôÆâÉô¤Ç¹Ô¤¦
+ if(address & ADDRESS_MASK_A15){
+ cpu_romcs_set(address & ADDRESS_MASK_A0toA14);
+ }
+ c = bit_clear(c, BITNUM_CPU_RW);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //wait(wait_msec);
+ //¦Õ2 = H, data out
+ c = bit_set(c, BITNUM_CPU_M2);
+ c = bit_clear(c, BITNUM_WRITEDATA_OUTPUT);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //wait(wait_msec);
+ //¦Õ2 = L, H ¤Ë¤¹¤ë¤Þ¤Ç R/W, address, Data ¤ò͸ú¾õÂ֤ˤ¹¤ë
+ c = bit_clear(c, BITNUM_CPU_M2);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //wait(wait_msec);
+ //¦Õ2 = H, R/W = H, address disable, data out disable
+ if(address & ADDRESS_MASK_A15){
+ //address & ADDRESS_MASK_A15 ¤ÇÆ°¤¤¤Æ¤¿..?
+ cpu_romcs_set(address | ADDRESS_MASK_A15);
+ }
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_BUS_STANDBY);
+ address += 1;
+ data += 1;
+ length -= 1;
+ }
+}
+
+//onajimi ¤À¤È /CS ¤È /OE ¤¬Æ±¤¸¤Ë¤Ê¤Ã¤Æ¤¤¤ë¤¬¡¢hongkong¤À¤È»ß¤á¤é¤ì¤ë¡£½ñ¤¹þ¤ß»þ¤Ë output enable ¤Ï H ¤Ç¤¢¤ë¤Ù¤¡£
+static void hk_ppu_write(long address, long length, const uint8_t *data)
+{
+ while(address != 0){
+ int c = BUS_CONTROL_BUS_STANDBY;
+ c = bit_clear(c, BITNUM_CPU_M2); //¤¿¤Ö¤ó¤¤¤ë
+ //c = bit_clear(c, BITNUM_CPU_RW);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //cpu rom ¤ò»ß¤á¤¿¥¢¥É¥ì¥¹¤òÅϤ¹
+ address_set((address & ADDRESS_MASK_A0toA12) | ADDRESS_MASK_A15);
+ data_port_set(c, *data);
+ // data_port_latch(DATA_SELECT_CONTROL, c);
+ //CS down
+ c = bit_clear(c, BITNUM_PPU_SELECT);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //WE down
+ c = bit_clear(c, BITNUM_WRITEDATA_OUTPUT);
+ c = bit_clear(c, BITNUM_PPU_RW);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //WE up
+ c = bit_set(c, BITNUM_PPU_RW);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //CS up
+ // c = bit_set(c, BITNUM_WRITEDATA_OUTPUT);
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_BUS_STANDBY);
+
+ address += 1;
+ data += 1;
+ length -= 1;
+ }
+}
+
+#if 0
+static const int FLASH_CPU_WRITE = (
+ (1 << BITNUM_PPU_OUTPUT) |
+ (1 << BITNUM_PPU_RW) |
+ (1 << BITNUM_PPU_SELECT) |
+ (1 << BITNUM_WRITEDATA_OUTPUT) |
+ (0 << BITNUM_WRITEDATA_LATCH) |
+ (0 << BITNUM_CPU_M2) |
+ (1 << BITNUM_CPU_RW)
+);
+
+static void hk_cpu_flash_write(long address, long data)
+{
+ int c = FLASH_CPU_WRITE;
+ //Á´¤Æ¤Î¥Ð¥¹¤ò»ß¤á¤ë
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ address_set(address | ADDRESS_MASK_A15);
+ data_port_set(c, data);
+/*
+W29C020
+During the byte-load cycle, the addresses are latched by the falling
+edge of either CE or WE,whichever occurs last. The data are latched
+by the rising edge of either CE or WE, whicheveroccurs first.
+W49F002
+#CS or #WE ¤¬¹ß¤ê¤¿¤È¤¤Ë address latch
+#CS or #WE ¤¬¾å¤¬¤Ã¤¿¤È¤¤Ë data latch
+
+hongkong ·Ï¤Ï address ¤È /ROMCS ¤¬Æ±¤¸¥Ð¥¤¥È¤Ç¡¢ /CS À©¸æ¤Ë¤¹¤ë¤È
+hongkong ¥Ç¡¼¥¿Ç˲õ+¥¢¥É¥ì¥¹ÉÔ°ÂÄê¤Ë¤Ê¤ë¤Î¤Ç¡¢/WE À©¸æ¤Ë¤·¤Ê¤¤¤ÈÆ°¤«¤Ê¤¤¡£
+*/
+ //CS down
+ cpu_romcs_set(address & ADDRESS_MASK_A0toA14);
+ //WE down
+ c = bit_clear(c, BITNUM_WRITEDATA_OUTPUT);
+ c = bit_clear(c, BITNUM_CPU_RW);
+// c = bit_clear(c, BITNUM_CPU_M2);
+ data_port_latch(DATA_SELECT_CONTROL, c);
+ //WE up
+ data_port_latch(DATA_SELECT_CONTROL, FLASH_CPU_WRITE);
+ //CS up
+ cpu_romcs_set(address | ADDRESS_MASK_A15);
+}
+#endif
+
+const struct reader_driver DRIVER_HONGKONGFC = {
+ .name = "hongkongfc",
+ .open_or_close = paralellport_open_or_close,
+ .init = hk_init,
+ .cpu_read = hk_cpu_read,
+ .ppu_read = hk_ppu_read,
+ .cpu_write_6502 = hk_cpu_write_6502,
+ .ppu_write = hk_ppu_write,
+ .flash_support = NG,
+ .cpu_flash_config = NULL, .cpu_flash_erase = NULL, .cpu_flash_program = NULL,
+ .ppu_flash_config = NULL, .ppu_flash_erase = NULL, .ppu_flash_program = NULL
+};
+
+#ifdef TEST
+#include "giveio.h"
+#include <stdio.h>
+#include <stdlib.h>
+static void data_show(u8 *d, int length)
+{
+ int sum = 0;
+ int offset = 0;
+ while(length != 0){
+ char safix;
+ switch(offset & 0xf){
+ default:
+ safix = ' ';
+ break;
+ case 7:
+ safix = '-';
+ break;
+ case 0xf:
+ safix = '\n';
+ break;
+ }
+ printf("%02x%c", *d, safix);
+ sum += *d;
+ d++;
+ offset++;
+ length--;
+ }
+ printf("sum 0x%06x", sum);
+}
+
+int main(int c, char **v)
+{
+ const int gg = giveio_start();
+ switch(gg){
+ case GIVEIO_OPEN:
+ case GIVEIO_START:
+ case GIVEIO_WIN95:
+ break;
+ default:
+ case GIVEIO_ERROR:
+ printf("Can't Access Direct IO %d\n", gg);
+ return 0;
+ }
+
+ long d = strtol(v[2], NULL, 0x10);
+
+ switch(v[1][0]){
+ case 'w':
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_BUS_STANDBY);
+ port_control_write(DATA_SELECT_WRITE << BITNUM_CONTROL_DATA_SELECT, PORT_CONTROL_WRITE);
+ _outp(PORT_DATA, d);
+ break;
+ case 'c':
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_CPU_READ);
+ address_set(d ^ ADDRESS_MASK_A15);
+ port_control_write(DATA_SELECT_BREAK_DATA << BITNUM_CONTROL_DATA_SELECT, PORT_CONTROL_WRITE);
+ port_control_write(DATA_SELECT_READ << BITNUM_CONTROL_DATA_SELECT, PORT_CONTROL_READ);
+ printf("%02x\n", _inp(PORT_DATA));
+ break;
+ case 'C':{
+ const long length = 0x1000;
+ u8 data[length];
+ hk_cpu_read(d, length, data);
+ data_show(data, length);
+ }
+ break;
+ case 'p':
+ data_port_latch(DATA_SELECT_CONTROL, BUS_CONTROL_PPU_READ);
+ address_set(d | ADDRESS_MASK_A15, ADDRESS_RESET);
+ port_control_write(DATA_SELECT_READ << BITNUM_CONTROL_DATA_SELECT, PORT_CONTROL_READ);
+ printf("%02x\n", _inp(PORT_DATA));
+ break;
+ case 'P':{
+ const long length = 0x200;
+ u8 data[length];
+ hk_ppu_read(d, length, data);
+ data_show(data, length);
+ }
+ break;
+ }
+
+ if(gg != GIVEIO_WIN95){
+ giveio_stop(GIVEIO_STOP);
+ }
+ return 0;
+}
+#endif
--- /dev/null
+#ifndef _READER_HONGKONGFC_H_
+#define _READER_HONGKONGFC_H_
+const struct reader_driver DRIVER_HONGKONGFC;
+#endif
--- /dev/null
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <usb.h>
+#include <kazzo_request.h>
+#include <kazzo_task.h>
+#include "memory_manage.h"
+#include "reader_master.h"
+#include "usb_device.h"
+#include "reader_kazzo.h"
+
+static usb_dev_handle *device_open(void)
+{
+ usb_dev_handle *handle = NULL;
+ const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID};
+ const unsigned char rawPid[2] = {USB_CFG_DEVICE_ID};
+ char vendor[] = {USB_CFG_VENDOR_NAME, 0};
+ char product[] = {USB_CFG_DEVICE_NAME, 0};
+ int vid, pid;
+
+ /* compute VID/PID from usbconfig.h so that there is a central source of information */
+ vid = (rawVid[1] << 8) | rawVid[0];
+ pid = (rawPid[1] << 8) | rawPid[0];
+
+ if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) == 0){
+ return handle;
+ }
+ fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid);
+ return NULL;
+}
+static usb_dev_handle *handle = NULL;
+static int kazzo_open_close(enum reader_control oc)
+{
+ switch(oc){
+ case READER_OPEN:
+ handle = device_open();
+ return handle == NULL ? NG : OK;
+ case READER_CLOSE:
+ usb_close(handle);
+ handle = NULL;
+ return OK;
+ }
+ return NG;
+}
+enum{
+ TIMEOUT = 4000
+};
+//-------- read sequence --------
+static void device_read(usb_dev_handle *handle, enum request r, enum index index, long address, long length, uint8_t *data)
+{
+ int cnt = usb_control_msg(
+ handle,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
+ r, address,
+ index, (char *) data, length, TIMEOUT
+ );
+ if(cnt != length){
+ puts(__FUNCTION__);
+ puts(usb_strerror());
+ exit(1);
+ }
+}
+static void read_main(const enum request r, enum index index, long address, long length, uint8_t *data)
+{
+ const int packet = READ_PACKET_SIZE;
+ while(length >= packet){
+ device_read(handle, r, index, address, packet, data);
+ data += packet;
+ address += packet;
+ length -= packet;
+ }
+ if(length != 0){
+ device_read(handle, r, index, address, length, data);
+ }
+}
+static void kazzo_cpu_read(long address, long length, uint8_t *data)
+{
+ read_main(REQUEST_CPU_READ, INDEX_IMPLIED, address, length, data);
+// read_main(REQUEST_CPU_READ_6502, address, length, data);
+}
+static void kazzo_ppu_read(long address, long length, uint8_t *data)
+{
+ read_main(REQUEST_PPU_READ, INDEX_IMPLIED, address, length, data);
+}
+//-------- write sequence --------
+/*
+When host send data that contains 0xff many times, v-usb losts some
+bits. To prevent losting bits, mask data xor 0xa5;
+*/
+static void device_write(usb_dev_handle *handle, enum request w, enum index index, long address, long length, const uint8_t *data)
+{
+ uint8_t *d = Malloc(length);
+ int i;
+ memcpy(d, data, length);
+ for(i = 0; i < length; i++){
+ d[i] ^= 0xa5;
+ }
+ int cnt = usb_control_msg(
+ handle,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT,
+ w, address,
+ index, (char *) d, length, TIMEOUT
+ );
+ if(cnt != length){
+ puts(__FUNCTION__);
+ puts(usb_strerror());
+ exit(1);
+ }
+ Free(d);
+}
+
+static void kazzo_init(void)
+{
+ device_write(handle, REQUEST_PHI2_INIT, INDEX_IMPLIED, 0, 0, NULL);
+}
+
+static void write_memory(enum request r, long address, long length, const uint8_t *data)
+{
+ while(length != 0){
+ long l = length >= FLASH_PACKET_SIZE ? FLASH_PACKET_SIZE : length;
+ device_write(handle, r, INDEX_IMPLIED, address, l, data);
+ address += l;
+ data += l;
+ length -= l;
+ }
+}
+static void kazzo_cpu_write_6502(long address, long length, const uint8_t *data)
+{
+ write_memory(REQUEST_CPU_WRITE_6502, address, length, data);
+}
+/*static void kazzo_cpu_write_flash(long address, long data)
+{
+ uint8_t d = (uint8_t) (data & 0xff);
+ device_write(handle, REQUEST_CPU_WRITE_FLASH, address, 1, &d);
+}*/
+static void kazzo_ppu_write(long address, long length, const uint8_t *data)
+{
+ write_memory(REQUEST_PPU_WRITE, address, length, data);
+}
+
+static inline void pack_short_le(long l, uint8_t *t)
+{
+ t[0] = l & 0xff;
+ t[1] = (l >> 8) & 0xff;
+}
+static void flash_config(enum request r, enum index index, long c000x, long c2aaa, long c5555, long unit, bool retry)
+{
+ const int size = 2 * 4 + 1;
+ uint8_t buf[size];
+ uint8_t *t = buf;
+ assert(unit >= 1 && unit < 0x400);
+ pack_short_le(c000x, t);
+ t += sizeof(uint16_t);
+ pack_short_le(c2aaa, t);
+ t += sizeof(uint16_t);
+ pack_short_le(c5555, t);
+ t += sizeof(uint16_t);
+ pack_short_le(unit, t);
+ t += sizeof(uint16_t);
+ *t = retry == true ? 1 : 0;
+ device_write(handle, r, index, 0, size, buf);
+}
+static void kazzo_cpu_flash_config(long c000x, long c2aaa, long c5555, long unit, bool retry)
+{
+ flash_config(REQUEST_FLASH_CONFIG_SET, INDEX_CPU, c000x, c2aaa, c5555, unit, retry);
+}
+static void kazzo_ppu_flash_config(long c000x, long c2aaa, long c5555, long unit, bool retry)
+{
+ flash_config(REQUEST_FLASH_CONFIG_SET, INDEX_PPU, c000x, c2aaa, c5555, unit, retry);
+}
+
+static inline void flash_execute(enum request p, enum request s, enum index index, long address, const uint8_t *data, int size, bool dowait, bool skip)
+{
+ uint8_t status;
+ int filled = 1;
+ if(skip == true){
+ uint8_t *filldata = Malloc(size);
+ memset(filldata, 0xff, size);
+ filled = memcmp(filldata, data, size);
+ if(0){ //nesasm fill 0 to unused area. When this routine is enabled, programming will speed up and compare mode will not work.
+ memset(filldata, 0, size);
+ filled &= memcmp(filldata, data, size);
+ }
+ Free(filldata);
+ }
+ if(filled != 0){
+ device_write(handle, p, index, address, size, data);
+ }
+ if(dowait == true){
+ do{
+ wait(10);
+ device_read(handle, s, index, 0, 1, &status);
+ }while(status != KAZZO_TASK_FLASH_IDLE);
+ }
+}
+static void kazzo_cpu_flash_erase(long address, bool dowait)
+{
+ flash_execute(REQUEST_FLASH_ERASE, REQUEST_FLASH_STATUS, INDEX_CPU, address, NULL, 0, dowait, false);
+}
+static void kazzo_ppu_flash_erase(long address, bool dowait)
+{
+ flash_execute(REQUEST_FLASH_ERASE, REQUEST_FLASH_STATUS, INDEX_PPU, address, NULL, 0, dowait, false);
+}
+
+static void dump(const uint8_t *w, const uint8_t *r, long length)
+{
+ while(length != 0){
+ if(memcmp(r, w, 0x10) != 0){
+ int i;
+ printf("* ");
+ for(i = 0; i < 0x10; i+=4){
+ printf("%02x %02x %02x %02x-", w[i], w[i+1], w[i+2], w[i+3]);
+ }
+ puts("");
+ printf(" ");
+ for(i = 0; i < 0x10; i+=4){
+ printf("%02x %02x %02x %02x-", r[i], r[i+1], r[i+2], r[i+3]);
+ }
+ puts("");
+ }
+ w += 0x10;
+ r += 0x10;
+ length -= 0x10;
+ }
+}
+static long flash_program(enum index index, long address, long length, const uint8_t *data, bool dowait, bool skip)
+{
+ enum request p = REQUEST_FLASH_PROGRAM;
+ enum request s = REQUEST_FLASH_STATUS;
+ if(dowait == false){
+ flash_execute(p, s, index, address, data, FLASH_PACKET_SIZE, dowait, skip);
+ return FLASH_PACKET_SIZE;
+ }
+ long count = 0;
+ uint8_t *d = Malloc(FLASH_PACKET_SIZE);
+ while(length >= FLASH_PACKET_SIZE){
+ flash_execute(p, s, index, address, data, FLASH_PACKET_SIZE, dowait, skip);
+ if(0){
+ //device_read(handle, REQUEST_FLASH_BUFFER_GET, index, 0, FLASH_PACKET_SIZE, d);
+ if(memcmp(d, data, FLASH_PACKET_SIZE) != 0){
+ puts("packet send error");
+ dump(data, d, FLASH_PACKET_SIZE);
+ }
+ }
+ address += FLASH_PACKET_SIZE;
+ data += FLASH_PACKET_SIZE;
+ count += FLASH_PACKET_SIZE;
+ length -= FLASH_PACKET_SIZE;
+ }
+ Free(d);
+ return count;
+}
+static long kazzo_cpu_flash_program(long address, long length, const uint8_t *data, bool dowait, bool skip)
+{
+ return flash_program(INDEX_CPU, address, length, data, dowait, skip);
+}
+static long kazzo_ppu_flash_program(long address, long length, const uint8_t *data, bool dowait, bool skip)
+{
+ return flash_program(INDEX_PPU, address, length, data, dowait, skip);
+}
+
+static void kazzo_flash_status(uint8_t s[2])
+{
+ read_main(REQUEST_FLASH_STATUS, INDEX_BOTH, 0, 2, s);
+}
+static void kazzo_cpu_flash_device_get(uint8_t s[2])
+{
+ read_main(REQUEST_FLASH_DEVICE, INDEX_CPU, 0, 2, s);
+}
+static void kazzo_ppu_flash_device_get(uint8_t s[2])
+{
+ read_main(REQUEST_FLASH_DEVICE, INDEX_PPU, 0, 2, s);
+}
+static uint8_t kazzo_vram_connection(void)
+{
+ uint8_t s;
+ read_main(REQUEST_VRAM_CONNECTION, INDEX_IMPLIED, 0, 1, &s);
+ return s;
+}
+const struct reader_driver DRIVER_KAZZO = {
+ .name = "kazzo",
+ .open_or_close = kazzo_open_close,
+ .init = kazzo_init,
+ .cpu_read = kazzo_cpu_read, .ppu_read = kazzo_ppu_read,
+ .cpu_write_6502 = kazzo_cpu_write_6502,
+ .flash_support = true,
+ .ppu_write = kazzo_ppu_write,
+ .cpu_flash_config = kazzo_cpu_flash_config,
+ .cpu_flash_erase = kazzo_cpu_flash_erase,
+ .cpu_flash_program = kazzo_cpu_flash_program,
+ .cpu_flash_device_get = kazzo_cpu_flash_device_get,
+ .ppu_flash_config = kazzo_ppu_flash_config,
+ .ppu_flash_erase = kazzo_ppu_flash_erase,
+ .ppu_flash_program = kazzo_ppu_flash_program,
+ .ppu_flash_device_get = kazzo_ppu_flash_device_get,
+ .flash_status = kazzo_flash_status,
+ .vram_connection = kazzo_vram_connection
+};
--- /dev/null
+#ifndef _READER_KAZZO_H_
+#define _READER_KAZZO_H_
+const struct reader_driver DRIVER_KAZZO;
+#endif
--- /dev/null
+#include <assert.h>
+#include <string.h>
+#include "giveio.h"
+#include "reader_master.h"
+#include "reader_onajimi.h"
+#include "reader_hongkongfc.h"
+//#include "reader_dozeu.h"
+#include "reader_kazzo.h"
+
+int paralellport_open_or_close(enum reader_control oc)
+{
+ static int giveio_status;
+ switch(oc){
+ case READER_OPEN:
+ giveio_status = giveio_start();
+ switch(giveio_status){
+ case GIVEIO_OPEN:
+ case GIVEIO_START:
+ case GIVEIO_WIN95:
+ break;
+ default:
+ case GIVEIO_ERROR:
+ //printf("%s Can't Access Direct IO %d\n", __FILE__, giveio_status);
+ return NG;
+ }
+ break;
+ case READER_CLOSE:
+ if(giveio_status != GIVEIO_WIN95){
+ giveio_stop(GIVEIO_STOP);
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ return OK;
+}
+
+const struct reader_driver *reader_driver_get(const char *name)
+{
+ static const struct reader_driver *DRIVER_LIST[] = {
+ &DRIVER_ONAJIMI, &DRIVER_HONGKONGFC, //&DRIVER_DOZEU,
+ &DRIVER_KAZZO,
+ NULL
+ };
+ const struct reader_driver **d;
+ d = DRIVER_LIST;
+ while(*d != NULL){
+ if(strcmp(name, (*d)->name) == 0){
+ return *d;
+ }
+ d++;
+ }
+ return NULL;
+}
--- /dev/null
+#ifndef _READER_MASTER_H_
+#define _READER_MASTER_H_
+#include "type.h"
+#ifdef WIN32
+ #include <windows.h>
+#else
+ #include <unistd.h>
+#endif
+
+//C++ ¤Î Class ¤â¤É¤¤ò C ¤Ç¼ÂÁõ¤·¤Æ¤¤¤ë´¶¤¬Áý¤·¤Æ¤¤¿...
+enum reader_control{
+ READER_OPEN, READER_CLOSE
+};
+struct reader_driver{
+ const char *name;
+ int (*open_or_close)(enum reader_control oc);
+ void (*init)(void);
+ void (*cpu_read)(long address, long length, uint8_t *data);
+ void (*cpu_write_6502)(long address, long length, const uint8_t *data);
+ void (*ppu_read)(long address, long length, uint8_t *data);
+ void (*ppu_write)(long address, long length, const uint8_t *data);
+ bool flash_support;
+ void (*cpu_flash_config)(long c000x, long c2aaa, long c5555, long unit, bool retry);
+ void (*cpu_flash_erase)(long address, bool wait);
+ long (*cpu_flash_program)(long address, long length, const uint8_t *data, bool wait, bool skip);
+ void (*cpu_flash_device_get)(uint8_t s[2]);
+ void (*ppu_flash_config)(long c000x, long c2aaa, long c5555, long unit, bool retry);
+ void (*ppu_flash_erase)(long address, bool wait);
+ long (*ppu_flash_program)(long address, long length, const uint8_t *data, bool wait, bool skip);
+ void (*ppu_flash_device_get)(uint8_t s[2]);
+ void (*flash_status)(uint8_t s[2]);
+ uint8_t (*vram_connection)(void);
+};
+int paralellport_open_or_close(enum reader_control oc);
+const struct reader_driver *reader_driver_get(const char *name);
+enum{
+ ADDRESS_MASK_A0toA12 = 0x1fff,
+ ADDRESS_MASK_A0toA14 = 0x7fff,
+ ADDRESS_MASK_A15 = 0x8000
+};
+enum{
+ M2_CONTROL_TRUE, M2_CONTROL_FALSE
+};
+/*
+static inline ¤Ï¶¦Í¥Þ¥¯¥í°·¤¤
+*/
+static inline int bit_set(int data, const int bit)
+{
+ data |= 1 << bit;
+ return data;
+}
+
+static inline int bit_clear(int data, const int bit)
+{
+ data &= ~(1 << bit);
+ return data;
+}
+
+static inline void wait(long msec)
+{
+ if(msec == 0){
+ return;
+ }
+#ifdef WIN32
+ Sleep(msec);
+#else
+ usleep(msec * 1000);
+#endif
+}
+#endif
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+emuste.net ¤Ç¤ª¤Ê¤¸¤ß¤Î¤â¤Î¤Î¥Ï¡¼¥É¥É¥é¥¤¥Ð
+
+Copyright (C) 2008 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+memo:
+* -O0 ¤Ê¤é inline asm ¤Ç¤âÈ¿±þ¤Ç¤¤ë¤¬¡¢-O2 ¤À¤ÈÆ°¤«¤Ê¤¤
+ * ͽÁÛ¤ËÈ¿¤·¤Æ out ¤ÏÆ°¤¯¤¬¡¢ in ¤Ë wait ¤¬É¬Íפߤ¿¤¤
+* gcc ¤Î¥¢¥»¥ó¥Ö¥é¤Ï x86 ¤Ç¤¢¤í¤¦¤È src,dst ¤Î½ç¤Çȿž¤·¤Æ¤¤¤ë
+* http://download.intel.com/jp/developer/jpdoc/IA32_Arh_Dev_Man_Vol2A_i.pdf
+ * out,in ¤Î¥¢¥É¥ì¥¹¤Ë dx ¤ò»È¤ï¤Ê¤¤¤È 8bit ¥¢¥É¥ì¥¹¤Ë¤Ê¤ë
+ * out,in ¤Î¥Ç¡¼¥¿¤Ï¥ì¥¸¥¹¥¿¤Ç¥Ç¡¼¥¿Éý¤¬ÊѤï¤ë al:8bit, ax:16bit, eax:32bit
+*/
+#include "type.h"
+#include "paralellport.h"
+#include "hard_onajimi.h"
+#include "reader_master.h"
+#include "reader_onajimi.h"
+
+static inline void bus_control(int data)
+{
+#if ASM_ENABLE==0
+ _outp(PORT_DATA, data);
+#else
+ asm(
+ " movl %0,%%edx\n"
+ " movl %1,%%eax\n"
+ " out %%al,%%dx\n"
+ :: "i"(PORT_DATA), "q"(data): "%edx", "%eax"
+ );
+#endif
+}
+
+/*
+CONTROL bit0 STROBE
+¥Ç¡¼¥¿¤¬È¿Å¾¤¹¤ë
+*/
+static inline void address_control(int data)
+{
+ data &= 0x01;
+ data ^= 0x01;
+#if ASM_ENABLE==0
+ _outp(PORT_CONTROL, data);
+#else
+ asm(
+ " movl %0,%%edx\n"
+ " movl %1,%%eax\n"
+ " out %%al,%%dx\n"
+ :: "i"(PORT_CONTROL), "q"(data): "%edx", "%eax"
+ );
+#endif
+}
+
+/* address control data & function */
+static long past_address = 0;
+
+static void address_reset(void)
+{
+ address_control(ADDRESS_RESET);
+ address_control(ADDRESS_ENABLE);
+ past_address = 0;
+}
+
+/*
+H->L ¤Çaddressincrement
+*/
+static inline void address_increment(int data)
+{
+ data = bit_set(data, BITNUM_ADDRESS_INCREMENT);
+ bus_control(data);
+
+ data = bit_clear(data, BITNUM_ADDRESS_INCREMENT);
+ bus_control(data);
+ past_address += 1;
+ past_address &= ADDRESS_MASK_A0toA14;
+}
+
+static void address_set(long address, int control)
+{
+ address &= ADDRESS_MASK_A0toA14;
+ long increment_count = address - past_address;
+ if(increment_count < 0){
+ address_reset();
+ increment_count = address;
+ }
+
+ while(increment_count != 0){
+ address_increment(control);
+ increment_count -= 1;
+ }
+}
+
+/*
+STATUS bit7 BUSY
+¥Ç¡¼¥¿¤¬È¿Å¾¤¹¤ë
+*/
+static inline int data_bit_get(void)
+{
+#if ASM_ENABLE==1
+ int data;
+ asm(
+ " xorl %%eax,%%eax\n"
+ " movl %1,%%edx\n"
+ " in %%dx,%%al\n"
+ " movl %%eax,%0"
+ :"=q"(data) : "i"(PORT_BUSY) :"%edx", "%eax"
+ );
+#else
+ int data = _inp(PORT_BUSY);
+#endif
+ data >>= 7;
+ data &= 0x01;
+ return data ^ 0x01;
+}
+
+/*
+L->H ¤Çshift
+*/
+static inline void data_shift(int control)
+{
+ control = bit_clear(control, BITNUM_DATA_SHIFT_RIGHT);
+ bus_control(control);
+ control = bit_set(control, BITNUM_DATA_SHIFT_RIGHT);
+ bus_control(control);
+}
+
+/*ºÇ¾å°Ìbit¤«¤é½çÈ֤ˤȤë*/
+static u8 data_get(int control)
+{
+ int data = 0;
+ int i;
+ //fcbus 8bit data load, shift count reset
+ control = bit_set(control, BITNUM_DATA_DIRECTION);
+ data_shift(control);
+ //shift mode
+ control = bit_clear(control, BITNUM_DATA_DIRECTION);
+ bus_control(control);
+ for(i = 0; i < 8; i++){
+ data |= (data_bit_get() << i);
+ data_shift(control);
+ }
+ return (u8) data;
+}
+
+//¤³¤³¤Î data ¤Ï 0 or 1
+static inline int writedata_set(long data)
+{
+ data &= 1;
+ return data << BITNUM_DATA_WRITE_DATA;
+}
+
+static void data_set(int control, long data)
+{
+ int i;
+ for(i = 0; i < 8; i++){
+ control = bit_clear(control, BITNUM_DATA_WRITE_DATA);
+ control |= writedata_set(data >> i);
+ bus_control(control);
+ data_shift(control);
+ }
+}
+
+static const int BUS_CONTROL_INIT = (
+ ADDRESS_NOP | DATA_SHIFT_NOP |
+ (DATA_DIRECTION_READ << BITNUM_DATA_DIRECTION) |
+ (PPU_DISABLE << BITNUM_PPU_SELECT) |
+ (PPU_WRITE__CPU_DISABLE << BITNUM_CPU_M2) |
+ (CPU_RAM_SELECT << BITNUM_CPU_RAMROM_SELECT) |
+ (CPU_READ << BITNUM_CPU_RW)
+);
+static void reader_init(void)
+{
+ int c = BUS_CONTROL_INIT;
+ int i = 0x80;
+ bus_control(c);
+ address_reset();
+ /*
+ namcot bus °ÂÄê½èÃÖ
+ reader_hongkong »²¾È
+ */
+ while(i != 0){
+ c = bit_set(c, BITNUM_CPU_M2);
+ bus_control(c);
+ c = bit_clear(c, BITNUM_CPU_M2);
+ bus_control(c);
+ i--;
+ }
+}
+
+static const int BUS_CONTROL_CPU_READ = (
+ ADDRESS_NOP | DATA_SHIFT_NOP |
+ (DATA_DIRECTION_READ << BITNUM_DATA_DIRECTION) |
+ (PPU_DISABLE << BITNUM_PPU_SELECT) |
+ (PPU_READ__CPU_ENABLE << BITNUM_CPU_M2) | //H
+ (CPU_RAM_SELECT << BITNUM_CPU_RAMROM_SELECT) |
+ (CPU_READ << BITNUM_CPU_RW)
+);
+
+static const int BUS_CONTROL_PPU_READ = (
+ ADDRESS_NOP | DATA_SHIFT_NOP |
+ (DATA_DIRECTION_READ << BITNUM_DATA_DIRECTION) |
+ (PPU_READ__CPU_ENABLE << BITNUM_CPU_M2) |
+ (PPU_ENABLE << BITNUM_PPU_SELECT) |
+ (CPU_RAM_SELECT << BITNUM_CPU_RAMROM_SELECT) |
+ (CPU_READ << BITNUM_CPU_RW)
+);
+
+static const int BUS_CONTROL_BUS_WRITE = (
+ ADDRESS_NOP | DATA_SHIFT_NOP |
+ (DATA_DIRECTION_WRITE << BITNUM_DATA_DIRECTION) |
+ (PPU_READ__CPU_ENABLE << BITNUM_CPU_M2) |
+ (PPU_DISABLE << BITNUM_PPU_SELECT) |
+ (CPU_RAM_SELECT << BITNUM_CPU_RAMROM_SELECT) |
+ (CPU_READ << BITNUM_CPU_RW)
+);
+
+static void fc_bus_read(long address, long length, u8 *data, int control, int m2_control)
+{
+ address_set(address, control);
+ if(m2_control == M2_CONTROL_TRUE){
+ control = bit_clear(control, BITNUM_CPU_M2);
+ bus_control(control); //H->L: mapper ¤¬¥¢¥É¥ì¥¹¤ò¼è¤Ã¤Æ¤¯¤ë
+ }
+ while(length != 0){
+ if(m2_control == M2_CONTROL_TRUE){
+ //L->H: mapper ¤¬ data ¤ò½Ð¤¹
+ control = bit_set(control, BITNUM_CPU_M2);
+ }
+ *data = data_get(control);
+ if(m2_control == M2_CONTROL_TRUE){
+ //H->L: ¤ª¤ä¤¹¤ß
+ control = bit_clear(control, BITNUM_CPU_M2);
+ bus_control(control);
+ //L->H: increment
+ control = bit_set(control, BITNUM_CPU_M2);
+ }
+ address_increment(control);
+
+ if(m2_control == M2_CONTROL_TRUE){
+ //H->L: mapper ¤¬¥¢¥É¥ì¥¹¤ò¼è¤Ã¤Æ¤¯¤ë
+ control = bit_clear(control, BITNUM_CPU_M2);
+ bus_control(control);
+ }
+
+ data++;
+ length--;
+ }
+ control = bit_set(control, BITNUM_CPU_M2);
+}
+
+static void cpu_read(long address, long length, u8 *data)
+{
+ int control = BUS_CONTROL_CPU_READ;
+ if(address & ADDRESS_MASK_A15){
+ control = bit_clear(control, BITNUM_CPU_RAMROM_SELECT);
+ }
+ fc_bus_read(address, length, data, control, M2_CONTROL_TRUE);
+}
+
+static void ppu_read(long address, long length, u8 *data)
+{
+ fc_bus_read(address, length, data, BUS_CONTROL_PPU_READ, M2_CONTROL_FALSE);
+}
+/*
+6502 write cycle
+t |01234
+----+-----
+¦Õ2 |HLHLH
+/ROM|HHxxH
+R/W |HHLLH
+
+0 H bus:addressset
+1 H->L bus:data set, mapper:address get
+2 L->H bus:data write
+3 H->L mapper: data write enable
+4 L->H mapper: data get, bus:close
+
+H:1, L:0, x:ROMareaaccess»þ0, ¤½¤ì°Ê³°1
+*/
+static void cpu_write_6502(long address, long length, const uint8_t *data)
+{
+ while(length != 0){
+ int control = BUS_CONTROL_BUS_WRITE;
+ //addressÀßÄê + Á´¤Æ¤Î¥Ð¥¹¤ò»ß¤á¤ë
+ address_set(address, control);
+
+ //¦Õ2 = L, R/W=L, data set, dataout
+ control = bit_clear(control, BITNUM_CPU_M2);
+ data_set(control, *data);
+ control = bit_clear(control, BITNUM_CPU_RW);
+ bus_control(control);
+ if(address & ADDRESS_MASK_A15){
+ control = bit_clear(control, BITNUM_CPU_RAMROM_SELECT);
+ }
+ //wait(wait_msec);
+
+ //¦Õ2 = H, data out
+ control = bit_set(control, BITNUM_CPU_M2);
+ bus_control(control);
+ //wait(wait_msec);
+ //¦Õ2 = L, H ¤Ë¤¹¤ë¤Þ¤Ç R/W, address, Data ¤ò͸ú¾õÂ֤ˤ¹¤ë
+ control = bit_clear(control, BITNUM_CPU_M2);
+ bus_control(control);
+ //wait(wait_msec);
+ //¦Õ2 = H, R/W = H, address disable, data out disable
+ bus_control(BUS_CONTROL_BUS_WRITE);
+
+ address += 1;
+ data += 1;
+ length--;
+ }
+}
+
+static void ppu_write(long address, long length, const uint8_t *data)
+{
+ while(length != 0){
+ int control = BUS_CONTROL_BUS_WRITE;
+
+ address_set(address, control);
+ bus_control(control);
+ data_set(control, *data);
+ control = bit_clear(control, BITNUM_PPU_RW);
+ control = bit_clear(control, BITNUM_PPU_SELECT);
+ bus_control(control);
+ bus_control(BUS_CONTROL_BUS_WRITE);
+
+ address += 1;
+ data += 1;
+ length -= 1;
+ }
+}
+
+/*
+static const int BUS_CONTROL_CPU_FLASH_WRITE = (
+ ADDRESS_NOP | DATA_SHIFT_NOP |
+ (DATA_DIRECTION_READ << BITNUM_DATA_DIRECTION) |
+ (PPU_DISABLE << BITNUM_PPU_SELECT) |
+ (PPU_READ__CPU_ENABLE << BITNUM_CPU_M2) | //H
+ (CPU_RAM_SELECT << BITNUM_CPU_RAMROM_SELECT) |
+ (CPU_READ << BITNUM_CPU_RW)
+);
+
+static void cpu_flash_write(long address, long data)
+{
+ int control = BUS_CONTROL_BUS_WRITE;
+ control = bit_clear(control, BITNUM_CPU_M2);
+ address_set(address, control);
+
+ //WE down
+ control = bit_clear(control, BITNUM_CPU_RW);
+ data_set(control, data);
+ //CS down
+ control = bit_clear(control, BITNUM_CPU_RAMROM_SELECT);
+ bus_control(control);
+ //CS up
+ control = bit_set(control, BITNUM_CPU_RAMROM_SELECT);
+ bus_control(control);
+ //WE up
+ control = bit_set(control, BITNUM_CPU_RW);
+ bus_control(control);
+}*/
+
+const struct reader_driver DRIVER_ONAJIMI = {
+ .name = "onajimi",
+ .open_or_close = paralellport_open_or_close,
+ .init = reader_init,
+ .cpu_read = cpu_read,
+ .cpu_write_6502 = cpu_write_6502,
+ .ppu_read = ppu_read,
+ .ppu_write = ppu_write,
+ .flash_support = NG,
+ .cpu_flash_config = NULL, .cpu_flash_erase = NULL, .cpu_flash_program = NULL,
+ .ppu_flash_config = NULL, .ppu_flash_erase = NULL, .ppu_flash_program = NULL
+};
--- /dev/null
+#ifndef _READER_ONAJIMI_H_
+#define _READER_ONAJIMI_H_
+const struct reader_driver DRIVER_ONAJIMI;
+#endif
--- /dev/null
+include ../file.mak
+CFLAGS += -O2 -DDEBUG=0 -DNDEBUG -fomit-frame-pointer
+VPATH = ..
+$(TARGET): $(OBJ)
+ $(CC) -o $@ $(OBJ) $(LDFLAG)
+ strip $@
+
+include ../rule.mak
+#---- depend file ----
+-include unagi.d
--- /dev/null
+#\8eg\97p\82·\82é\83n\81[\83h\82Ì\83R\83\81\83\93\83g\82ð\8aO\82µ\82Ä\82\82¾\82³\82¢\r
+#DRIVER kazzo\r
+#DRIVER hongkongfc\r
+#DRIVER onajimi\r
+#hongkong fc \82Ì flash \82Ì\8f\91\82«\8d\9e\82Ý\82ª\82Å\82«\82È\82¢\8fê\8d\87\82Í\83R\83\81\83\93\83g\82ð\8aO\82µ\82Ä\r
+#\8e\8e\82µ\82Ä\82Ý\82Ä\82\82¾\82³\82¢\r
+#HONGKONG_FLASH 0.5.3\r
--- /dev/null
+all: $(TARGET) unagi.d
+unagi.d:
+ $(CC) -MM $(CFLAGS) ../*.c > $@
+clean:
+ rm -f $(OBJ) $(TARGET) unagi.d
+unagi.res.o: unagi.rc unagi.ico
+ windres -I.. -i $< -o $@
+all: $(TARGET) unagi.d
--- /dev/null
+#ifndef _SCRIPT_H_
+#define _SCRIPT_H_
+struct st_config;
+void script_load(const struct st_config *config);
+
+struct st_variable{
+ int type;
+ char variable;
+ long value;
+};
+
+struct st_expression{
+ struct st_variable left, right;
+ int operator;
+};
+
+struct script{
+ int opcode;
+ int line;
+ long value[4];
+ struct st_expression expression;
+ char variable;
+};
+
+enum{
+ VALUE_EXPRESSION = 0x1000000,
+ VALUE_VARIABLE,
+ VALUE_CONTANT_CPU_STEP_START,
+ VALUE_CONTANT_CPU_STEP_END,
+ VALUE_CONTANT_PPU_STEP_START,
+ VALUE_CONTANT_PPU_STEP_END,
+ VALUE_TRANSTYPE_EMPTY,
+ VALUE_TRANSTYPE_TOP,
+ VALUE_TRANSTYPE_BOTTOM,
+ VALUE_TRANSTYPE_FULL,
+ VALUE_UNDEF
+};
+enum{
+ EXPRESSION_TYPE_VARIABLE,
+ EXPRESSION_TYPE_VALUE
+};
+
+#endif
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+script engine
+
+Copyright (C) 2008-2009 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+todo:
+* ÊÑ¿ô´ÉÍý¤Î¥°¥í¡¼¥Ð¥ëÃͤò¡¢logical_test(), excute() ¥í¡¼¥«¥ë¤Ë¤·¤¿¤¤
+*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "memory_manage.h"
+#include "type.h"
+#include "file.h"
+#include "reader_master.h"
+#include "textutil.h"
+#include "config.h"
+#include "header.h"
+#include "script_syntax.h"
+#include "script.h"
+
+/*
+MAPPER num
+MIRROR [HV]
+CPU_ROMSIZE num
+CPU_RAMSIZE num
+PPU_ROMSIZE num
+DUMP_START
+CPU_READ address size
+CPU_WRITE address data -> ÊÑ¿ôŸ³«+±é»»»Ò»ÈÍѲÄǽ
+PPU_READ address size
+STEP_START variable start end step -> for(i=start;i<end;i+=step)
+STEP_END
+DUMP_END
+*/
+//#include "syntax.h"
+
+//ÊÑ¿ô´ÉÍý
+//step ¤ÎÊÑ¿ô¤Ï¾®Ê¸»ú¤Î a-z ¤Ç¤Ï¤¸¤Þ¤ë¤³¤È¡£2ʸ»úÌܰʹߤÏ̵»ë¤¹¤ë
+struct variable_manage{
+ char name;
+ long start,end,step;
+ long val;
+ const struct script *Continue;
+};
+
+enum{
+ STEP_MAX = 3,
+ VARIABLE_MAX = STEP_MAX
+};
+
+static const struct variable_manage VARIABLE_INIT = {
+ .name = '\0',
+ .start = 0, .end = 0, .step = 0,
+ .val = 0,
+ .Continue = NULL
+};
+static struct variable_manage variable_bank[VARIABLE_MAX];
+static int variable_num = 0;
+
+static void variable_init_single(int num)
+{
+ memcpy(&variable_bank[num], &VARIABLE_INIT, sizeof(struct variable_manage));
+}
+
+static void variable_init_all(void)
+{
+ int i;
+ variable_num = 0;
+ for(i = 0; i < VARIABLE_MAX; i++){
+ variable_init_single(i);
+ }
+}
+
+static int variable_get(char name, long *val)
+{
+ int i;
+ struct variable_manage *v;
+ v = variable_bank;
+ for(i = 0; i < variable_num; i++){
+ if(v->name == name){
+ *val = v->val;
+ return OK;
+ }
+ v++;
+ }
+ return NG;
+}
+
+static int expression_value_get(const struct st_variable *v, long *data)
+{
+ if(v->type == EXPRESSION_TYPE_VARIABLE){
+ if(variable_get(v->variable, data) == NG){
+ return NG;
+ }
+ }else{
+ *data = v->value;
+ }
+ return OK;
+}
+
+//ÊÑ¿ôŸ³«
+static int expression_calc(const struct st_expression *e, long *val)
+{
+ long left, right;
+ if(expression_value_get(&e->left, &left) == NG){
+ return NG;
+ }
+ if(e->operator == OPERATOR_NONE){
+ *val = left;
+ return OK;
+ }
+ if(expression_value_get(&e->right, &right) == NG){
+ return NG;
+ }
+ switch(e->operator){
+ case OPERATOR_PLUS:
+ *val = left + right;
+ break;
+ case OPERATOR_SHIFT_LEFT:
+ *val = left >> right;
+ //*val &= 1;
+ break;
+ case OPERATOR_SHIFT_RIGHT:
+ *val = left << right;
+ break;
+ case OPERATOR_AND:
+ *val = left & right;
+ break;
+ case OPERATOR_OR:
+ *val = left | right;
+ break;
+ case OPERATOR_XOR:
+ *val = left ^ right;
+ break;
+ }
+
+ return OK;
+}
+
+static int step_new(char name, long start, long end, long step, const struct script *Continue)
+{
+ if(variable_num >= VARIABLE_MAX){
+ return NG; //ÊÑ¿ôÄêµÁ¤¬Â¿¤¹¤®
+ }
+ struct variable_manage *v;
+ int i;
+ v = variable_bank;
+ for(i = 0; i < variable_num; i++){
+ if(v->name == name){
+ return NG; //ÊÑ¿ô̾½ÅÊ£
+ }
+ v++;
+ }
+ v = variable_bank;
+ v += variable_num;
+ v->name = name;
+ v->start = start;
+ v->end = end;
+ v->step = step;
+ v->val = start;
+ v->Continue = Continue;
+ variable_num++;
+ return OK;
+}
+
+static const struct script *step_end(const struct script *Break)
+{
+ //¸½ºß¤Î¥ë¡¼¥×¤ÎÂоÝÊÑ¿ô¤òÆÀ¤ë
+ struct variable_manage *v;
+ v = variable_bank;
+ v += (variable_num - 1);
+ //ÊÑ¿ô¹¹¿·
+ v->val += v->step;
+ if(v->val < v->end){
+ return v->Continue;
+ }
+ //¥ë¡¼¥×¤¬½ª¤ï¤Ã¤¿¤Î¤Ç¤½¤ÎÊÑ¿ô¤òÇË´þ¤¹¤ë
+ variable_init_single(variable_num - 1);
+ variable_num--;
+ return Break;
+}
+
+//int syntax_check(char **text, int text_num, struct script *s, int mode);
+/*
+logical_check() ÍÑ¥µ¥Ö´Ø¿ô¤È¥Ç¡¼¥¿
+*/
+static const char LOGICAL_ERROR_PREFIX[] = "logical error:";
+enum{
+ SCRIPT_PPUSIZE_0 = 0,
+ SCRIPT_MEMORYSIZE = 10,
+};
+struct logical_romsize{
+ const struct script *data[SCRIPT_MEMORYSIZE], *constant;
+ int count;
+};
+static int logical_flashsize_set(int region, struct logical_romsize *l, const struct script *s)
+{
+ //PPU Íѥǡ¼¥¿¤Î 0 ¤Ï size 0, Äê¿ô 0 ¤È¤·¤ÆͽÌ󤵤ì¤Æ¤ª¤ê¡¢0¤Î¾ì¹ç¤Ï¤³¤³¤ò¾å½ñ¤¤¹¤ë
+ if((region == MEMORY_AREA_PPU) && (s->value[0] == 0)){
+ l->data[SCRIPT_PPUSIZE_0] = s;
+ return OK;
+ }
+ if(l->count >= SCRIPT_MEMORYSIZE){
+ const char *opstr;
+ opstr = OPSTR_CPU_ROMSIZE; //warning Âкö
+ switch(region){
+ case MEMORY_AREA_CPU_ROM:
+ opstr = OPSTR_CPU_ROMSIZE;
+ break;
+ case MEMORY_AREA_PPU:
+ opstr = OPSTR_PPU_ROMSIZE;
+ break;
+ default:
+ assert(0);
+ }
+ printf("%d:%s %s override count over\n", s->line, LOGICAL_ERROR_PREFIX, opstr);
+ return NG;
+ }
+ l->data[l->count] = s;
+ l->count += 1;
+ return OK;
+}
+
+static int logical_flashsize_get(long transtype, long size, struct logical_romsize *l)
+{
+ int i;
+ for(i = 0; i < l->count; i++){
+ const struct script *s;
+ s = l->data[i];
+ if((s->value[0] == size) && (
+ (s->value[1] == transtype) ||
+ (s->value[1] == VALUE_TRANSTYPE_FULL)
+ )){
+ l->constant = s;
+ return OK;
+ }else if((s->value[0] == size) && (s->value[1] == VALUE_TRANSTYPE_EMPTY)){
+ l->constant = s;
+ return OK;
+ }
+ }
+ printf("%s flashsize not found\n", LOGICAL_ERROR_PREFIX);
+ return NG;
+}
+
+static long constant_get(long val, const struct script *cpu, const struct script *ppu)
+{
+ switch(val){
+ case VALUE_CONTANT_CPU_STEP_START:
+ return cpu->value[2];
+ case VALUE_CONTANT_CPU_STEP_END:
+ return cpu->value[3];
+ case VALUE_CONTANT_PPU_STEP_START:
+ return ppu->value[2];
+ case VALUE_CONTANT_PPU_STEP_END:
+ return ppu->value[3];
+ }
+ assert(0);
+ return -1;
+}
+
+static void logical_print_capacityerror(int line, const char *area)
+{
+ printf("%d:%s %s area flash memory capacity error\n", line, LOGICAL_ERROR_PREFIX, area);
+}
+
+static inline void logical_print_illgalarea(int line, const char *area, long address)
+{
+ printf("%d:%s illgal %s area $%06x\n", line, LOGICAL_ERROR_PREFIX, area, (int) address);
+}
+
+static inline void logical_print_illgallength(int line, const char *area, long length)
+{
+ printf("%d:%s illgal %s length $%04x\n", line, LOGICAL_ERROR_PREFIX, area, (int) length);
+}
+
+static inline void logical_print_overdump(int line, const char *area, long start, long end)
+{
+ printf("%d:%s %s area over dump $%06x-$%06x\n", line, LOGICAL_ERROR_PREFIX, area, (int)start ,(int)end);
+}
+
+static inline void logical_print_access(int line, const char *area, const char *rw, long addr, long len)
+{
+ printf("%d:%s %s $%04x $%02x\n", line, area, rw, (int) addr, (int) len);
+}
+
+static inline void logical_print_byteerror(int line, const char *area, long data)
+{
+ printf("%d:%s write data byte range over, %s $%x\n", line, LOGICAL_ERROR_PREFIX, area, (int) data);
+}
+
+static int dump_length_conform(const char *name, long logicallength, long configlength)
+{
+ if(configlength != logicallength){
+ printf("%s %s dump length error\n", LOGICAL_ERROR_PREFIX, name);
+ printf("%s: 0x%06x, dump length: 0x%06x\n", name, (int) configlength, (int) logicallength);
+ return 1;
+ }
+ return 0;
+}
+static inline int is_region_cpurom(long address)
+{
+ return (address >= 0x8000) && (address < 0x10000);
+}
+
+static inline int is_region_cpuram(long address)
+{
+ return (address >= 0x6000) && (address < 0x8000);
+}
+
+static inline int is_region_ppurom(long address)
+{
+ return (address >= 0) && (address < 0x2000);
+}
+
+static inline int is_data_byte(long data)
+{
+ return (data >= 0) && (data < 0x100);
+}
+
+//¤³¤ì¤À¤± is ·Ï¤Ç <= ±é»»»Ò¤ò»ÈÍѤ·¤Æ¤¤¤ë¤Î¤ÇÃí°Õ
+static inline int is_range(long data, long start, long end)
+{
+ return (data >= start) && (data <= end);
+}
+static const char STR_REGION_CPU[] = "cpu";
+static const char STR_REGION_PPU[] = "ppu";
+static const char STR_ACCESS_READ[] = "read";
+static const char STR_ACCESS_WRITE[] = "write";
+
+enum{
+ SETTING, DUMP, END, STEP_THOUGH
+};
+static int command_mask(const int region, const long address, const long offset, long size, struct flash_order *f)
+{
+ const char *str_region = STR_REGION_CPU;
+ if(region == MEMORY_AREA_PPU){
+ str_region = STR_REGION_PPU;
+ }
+ switch(region){
+ case MEMORY_AREA_CPU_ROM:
+ switch(offset){
+ case 0x8000: case 0xa000: case 0xc000:
+ break;
+ default:
+ printf("%s %s_COMMAND area offset error\n", LOGICAL_ERROR_PREFIX, str_region);
+ return NG;
+ }
+ switch(size){
+ case 0x2000: case 0x4000: case 0x8000:
+ break;
+ default:
+ printf("%s %s_COMMAND area mask error\n", LOGICAL_ERROR_PREFIX, str_region);
+ return NG;
+ }
+ break;
+ case MEMORY_AREA_PPU:
+ switch(offset){
+ case 0x0000: case 0x0400: case 0x0800: case 0x0c00:
+ case 0x1000: case 0x1400: case 0x1800: case 0x1c00:
+ break;
+ default:
+ printf("%s %s_COMMAND area offset error\n", LOGICAL_ERROR_PREFIX, str_region);
+ return NG;
+ }
+ switch(size){
+ case 0x0400: case 0x0800: case 0x1000: case 0x2000:
+ break;
+ default:
+ printf("%s %s_COMMAND area mask error\n", LOGICAL_ERROR_PREFIX, str_region);
+ return NG;
+ }
+ break;
+ default:
+ assert(0); //unknown memory area
+ }
+
+ const long mask = size - 1;
+ const long data = (address & mask) | offset;
+ switch(address){
+ case 0:
+ f->command_0000 = data;
+ break;
+ case 0x2aaa: case 0x02aa:
+ f->command_2aaa = data;
+ break;
+ case 0x5555: case 0x0555:
+ f->command_5555 = data;
+ break;
+ default:
+ printf("%s %s_COMMAND unknown commnand address\n", LOGICAL_ERROR_PREFIX, str_region);
+ return NG;
+ }
+ return OK;
+}
+
+enum{
+ STEP_VALIABLE = 0, STEP_START, STEP_END, STEP_NEXT,
+ STEP_NUM
+};
+static const struct script SCRIPT_PPU_ROMSIZE_0 = {
+ .opcode = SCRIPT_OPCODE_PPU_ROMSIZE,
+ .line = -1,
+ .value = {0, VALUE_TRANSTYPE_EMPTY, 0, 0},
+ //.expression, .variable ̤ÄêµÁ
+};
+
+static int logical_check(const struct script *s, const struct st_config *c, struct romimage *r)
+{
+ //(CPU|PPU)_(READ|PROGRAM|RAMRW) ¤Î length ²Ã»»ÃÍ
+ long cpu_romsize = 0, cpu_ramsize = 0, ppu_romsize = 0;
+ //DUMP_START ľ¸å¤Ë ROM or RAM image ¤ò³«¤¯¥Õ¥é¥°
+ //use program mode or ram write mode
+ int imagesize = 0; //for write or program mode
+ int status = SETTING;
+ //override (CPU|PPU)_ROMSIZE pointer. Program mode only
+ struct logical_romsize script_cpu_flashsize = {
+ .constant = NULL,
+ .count = 0
+ };
+ struct logical_romsize script_ppu_flashsize = {
+ .constant = NULL,
+ .count = 1
+ };
+ script_ppu_flashsize.data[0] = &SCRIPT_PPU_ROMSIZE_0;
+ //logical error count. Ìá¤êÃÍ
+ int error = 0;
+
+ variable_init_all();
+ while(s->opcode != SCRIPT_OPCODE_DUMP_END){
+ if((status == DUMP) && (s->opcode < SCRIPT_OPCODE_DUMP_START)){
+ printf("%d:%s config script include DUMP_START area\n", s->line, LOGICAL_ERROR_PREFIX);
+ error += 1;
+ }
+
+ //romimage open for write or program mode
+ if((imagesize == 0) && (status == DUMP)){
+ switch(c->mode){
+ case MODE_RAM_WRITE: //CPU_RAMSIZE check
+ assert(r->cpu_ram.attribute == MEMORY_ATTR_READ);
+ r->cpu_ram.data = buf_load_full(c->ramimage, &imagesize);
+ if(r->cpu_ram.data == NULL){
+ printf("%s RAM image open error\n", LOGICAL_ERROR_PREFIX);
+ imagesize = -1;
+ error += 1;
+ }else if(r->cpu_ram.size != imagesize){
+ printf("%s RAM image size is not same\n", LOGICAL_ERROR_PREFIX);
+ Free(r->cpu_ram.data);
+ r->cpu_ram.data = NULL;
+ imagesize = -1;
+ error += 1;
+ }
+ break;
+ case MODE_ROM_PROGRAM: //MAPPER check
+ assert(c->cpu_flash_driver->program != NULL);
+ assert(r->cpu_rom.attribute == MEMORY_ATTR_READ);
+ assert(r->ppu_rom.attribute == MEMORY_ATTR_READ);
+ if(nesfile_load(LOGICAL_ERROR_PREFIX, c->romimage, r)== false){
+ error += 1;
+ }
+ //Äê¿ôÀë¸À¥¨¥é¡¼¤Ï̵¸Â¥ë¡¼¥×¤Î²ÄǽÀ¤¬¤¢¤ë¤Î¤Ç¥¹¥¯¥ê¥×¥ÈÆâÉô¥Á¥§¥Ã¥¯¤ò¤»¤º¤Ë»ß¤á¤ë
+ if(logical_flashsize_get(c->transtype_cpu, r->cpu_rom.size, &script_cpu_flashsize) == NG){
+ return error + 1;
+ }
+ if(logical_flashsize_get(c->transtype_ppu, r->ppu_rom.size, &script_ppu_flashsize) == NG){
+ return error + 1;
+ }
+ //flash memory capacity check
+ if(r->cpu_rom.size > c->cpu_flash_driver->capacity){
+ logical_print_capacityerror(s->line, r->cpu_rom.name);
+ error += 1;
+ }
+ if((r->ppu_rom.size != 0) && (r->ppu_rom.size > c->ppu_flash_driver->capacity)){
+ logical_print_capacityerror(s->line, r->ppu_rom.name);
+ error += 1;
+ }
+ imagesize = -1;
+ break;
+ default:
+ imagesize = -1;
+ break;
+ }
+ }
+
+ switch(s->opcode){
+ case SCRIPT_OPCODE_COMMENT:
+ break;
+ case SCRIPT_OPCODE_MAPPER:
+ r->mappernum = s->value[0];
+ break;
+ case SCRIPT_OPCODE_MIRROR:
+ r->mirror = s->value[0];
+ break;
+ case SCRIPT_OPCODE_CPU_ROMSIZE:{
+ const long size = s->value[0];
+ r->cpu_rom.size = size;
+ if(memorysize_check(size, MEMORY_AREA_CPU_ROM)){
+ printf("%s %s length error\n", LOGICAL_ERROR_PREFIX, OPSTR_CPU_ROMSIZE);
+ error += 1;
+ }
+ }break;
+ case SCRIPT_OPCODE_CPU_FLASHSIZE:
+ if(logical_flashsize_set(MEMORY_AREA_CPU_ROM, &script_cpu_flashsize, s) == NG){
+ error += 1;
+ }break;
+ case SCRIPT_OPCODE_CPU_RAMSIZE:
+ //memory size ¤Ï̤³ÎÄêÍ×ÁǤ¬Â¿¤¤¤Î¤Ç check ¤òÈ´¤¯
+ r->cpu_ram.size = s->value[0];
+ break;
+ case SCRIPT_OPCODE_CPU_COMMAND:
+ if(command_mask(MEMORY_AREA_CPU_ROM, s->value[0], s->value[1], s->value[2], &(r->cpu_flash)) == NG){
+ error += 1;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_ROMSIZE:{
+ const long size = s->value[0];
+ r->ppu_rom.size = size;
+ if(memorysize_check(size, MEMORY_AREA_PPU)){
+ printf("%s %s length error\n", LOGICAL_ERROR_PREFIX, OPSTR_PPU_ROMSIZE);
+ error += 1;
+ }
+ }break;
+ case SCRIPT_OPCODE_PPU_FLASHSIZE:
+ if(logical_flashsize_set(MEMORY_AREA_PPU, &script_ppu_flashsize, s) == NG){
+ error += 1;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_COMMAND:
+ if(command_mask(MEMORY_AREA_PPU, s->value[0], s->value[1], s->value[2], &(r->ppu_flash)) == NG){
+ error += 1;
+ }
+ break;
+ case SCRIPT_OPCODE_DUMP_START:
+ status = DUMP;
+ break;
+ case SCRIPT_OPCODE_CPU_READ:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ const long end = address + length - 1;
+
+ assert(r->cpu_rom.attribute == MEMORY_ATTR_WRITE);
+ //length filter. 0 ¤Ï¤À¤á
+ if(!is_range(length, 1, 0x4000)){
+ logical_print_illgallength(s->line, STR_REGION_CPU, length);
+ error += 1;
+ }
+ //address filter
+ else if(!is_region_cpurom(address)){
+ logical_print_illgalarea(s->line, STR_REGION_CPU, address);
+ error += 1;
+ }else if(end >= 0x10000){
+ logical_print_overdump(s->line, STR_REGION_CPU, address, end);
+ error += 1;
+ }
+ cpu_romsize += length;
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_CPU_WRITE:{
+ const long address = s->value[0];
+ long data;
+ if(expression_calc(&s->expression, &data) == NG){
+ printf("%d:%s expression calc error\n", s->line, LOGICAL_ERROR_PREFIX);
+ error += 1;
+ }
+ if(address < 0x5000 || address >= 0x10000){
+ logical_print_illgalarea(s->line, STR_REGION_CPU, address);
+ error += 1;
+ }else if(!is_data_byte(data)){
+ logical_print_byteerror(s->line, STR_REGION_CPU, data);
+ error += 1;
+ }
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_CPU_RAMRW:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ const long end = address + length - 1;
+ switch(c->mode){
+ case MODE_RAM_READ:
+ assert(r->cpu_ram.attribute == MEMORY_ATTR_WRITE);
+ break;
+ case MODE_RAM_WRITE:
+ assert(r->cpu_ram.attribute == MEMORY_ATTR_READ);
+ break;
+ }
+ //length filter. 0 ¤Ï¤À¤á
+ if(!is_range(length, 1, 0x2000)){
+ logical_print_illgallength(s->line, STR_REGION_CPU, length);
+ error += 1;
+ }
+ //address filter
+ else if(address < 0x5c00 || address >= 0xc000){
+ logical_print_illgalarea(s->line, STR_REGION_CPU, address);
+ error += 1;
+ }else if(0 && end >= 0x8000){
+ logical_print_overdump(s->line, STR_REGION_CPU, address, end);
+ error += 1;
+ }
+ cpu_ramsize += length;
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_CPU_PROGRAM:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ const long end = address + length - 1;
+
+ assert(r->cpu_rom.attribute == MEMORY_ATTR_READ);
+ assert(r->ppu_rom.attribute == MEMORY_ATTR_READ);
+ //length filter.
+ if(!is_range(length, 0x80, 0x4000)){
+ logical_print_illgallength(s->line, STR_REGION_CPU, length);
+ error += 1;
+ }
+ //address filter
+ else if(!is_region_cpurom(address)){
+ logical_print_illgalarea(s->line, STR_REGION_CPU, address);
+ error += 1;
+ }else if(end >= 0x10000){
+ logical_print_overdump(s->line, STR_REGION_CPU, address, end);
+ error += 1;
+ }
+ cpu_romsize += length;
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_RAMFIND:
+ //¥ë¡¼¥×ÆâÉô¤ËÆþ¤Ã¤Æ¤¿¤é¥¨¥é¡¼
+ if(variable_num != 0){
+ printf("%d:%s PPU_RAMTEST must use outside loop\n", s->line, LOGICAL_ERROR_PREFIX);
+ error += 1;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_SRAMTEST:
+ case SCRIPT_OPCODE_PPU_READ:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ const long end = address + length - 1;
+ assert(r->ppu_rom.attribute == MEMORY_ATTR_WRITE);
+ //length filter. 0 ¤òÍÆǧ¤¹¤ë
+ long min = 0;
+ if(s->opcode == SCRIPT_OPCODE_PPU_SRAMTEST){
+ min = 1;
+ }
+ if(!is_range(length, min, 0x2000)){
+ logical_print_illgallength(s->line, STR_REGION_PPU, length);
+ error += 1;
+ }
+ //address filter
+ else if(!is_region_ppurom(address)){
+ logical_print_illgalarea(s->line, STR_REGION_PPU, address);
+ error += 1;
+ }else if (end >= 0x2000){
+ logical_print_overdump(s->line, STR_REGION_PPU, address, end);
+ error += 1;
+ }
+ //dump length update
+ if((s->opcode == SCRIPT_OPCODE_PPU_READ) && is_region_ppurom(address)){
+ ppu_romsize += length;
+ }
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_WRITE:{
+ if(DEBUG==0){
+ break;
+ }
+ const long address = s->value[0];
+ long data;
+ if(expression_calc(&s->expression, &data) == NG){
+ printf("%d:%s expression calc error\n", s->line, LOGICAL_ERROR_PREFIX);
+ error += 1;
+ }
+ status = DUMP;
+ if(!is_region_ppurom(address)){
+ logical_print_illgalarea(s->line, STR_REGION_PPU, address);
+ error += 1;
+ }else if(!is_data_byte(data)){
+ logical_print_byteerror(s->line, STR_REGION_PPU, data);
+ error += 1;
+ }
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_PROGRAM:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ const long end = address + length - 1;
+
+ assert(r->ppu_rom.attribute == MEMORY_ATTR_READ);
+ assert(r->ppu_rom.size != 0);
+
+ //length filter.
+ if(!is_range(length, 0x80, 0x1000)){
+ logical_print_illgallength(s->line, STR_REGION_PPU, length);
+ error += 1;
+ }
+ //address filter
+ else if(!is_region_ppurom(address)){
+ logical_print_illgalarea(s->line, STR_REGION_PPU, address);
+ error += 1;
+ }else if(end >= 0x2000){
+ logical_print_overdump(s->line, STR_REGION_PPU, address, end);
+ error += 1;
+ }
+ ppu_romsize += length;
+ status = DUMP;
+ }
+ break;
+ case SCRIPT_OPCODE_STEP_START:{
+ const struct step_syntax{
+ long start, end;
+ int constant;
+ const char *name;
+ } RANGE[STEP_NUM] = {
+ {.start = 0, .end = 0, .constant = NG, .name = "variable"},
+ {.start = 0, .end = 0xff, .constant = OK, .name = "start"},
+ {.start = 0, .end = 0x100, .constant = OK, .name = "end"},
+ {.start = 1, .end = 0x100, .constant = NG, .name = "next"}
+ };
+ int i;
+ for(i = STEP_START; i < STEP_NUM; i++){
+ const struct step_syntax *ss;
+ ss = &RANGE[i];
+ //Äê¿ôobject ¤ò¼Â¿ô¤ËÊÑ´¹¤¹¤ë¤¿¤á¡¢const ¤ò³°¤·¤Æ½ñ¤´¹¤¨¤ë
+ long *v;
+ v = (long *) &s->value[i];
+ if((ss->constant == OK) && (is_range(*v, VALUE_CONTANT_CPU_STEP_START, VALUE_CONTANT_PPU_STEP_END))){
+ //VALUE_CONSTANT_xxx ¤ò¼ÂºÝ¤Ë»È¤ï¤ì¤ëÄê¿ô¤Ë¤·¤Æ¡¢¥¹¥¯¥ê¥×¥È¥Ç¡¼¥¿¤òÄ¥¤êÂؤ¨¤ë
+ *v = constant_get(*v, script_cpu_flashsize.constant, script_ppu_flashsize.constant);
+ }
+ if(!is_range(*v, ss->start, ss->end)){
+ printf("%d:%s step %s must %d-0x%x 0x%x\n", s->line, ss->name, LOGICAL_ERROR_PREFIX, (int) ss->start, (int) ss->end, (int) *v);
+ error += 1;
+ }
+ }
+ //charcter RAM ¤ÎÍÍ¤Ë step ÆâÉô¤ò¹Ô¤ï¤Ê¤¤¾ì¹ç¤Îscript¾õÂÖ¤ÎÊѹ¹
+ if(s->value[STEP_START] >= s->value[STEP_END]){
+ status = STEP_THOUGH;
+ }
+ //¥ë¡¼¥×¤ÎÌá¤êÀè¤Ï¤³¤ÎÌ¿Îá¤Î¼¡¤Ê¤Î¤Ç s[1]
+ else if(step_new(s->variable, s->value[STEP_START], s->value[STEP_END], s->value[STEP_NEXT], &s[1]) == NG){
+ printf("%d:%s step loop too much\n", s->line, LOGICAL_ERROR_PREFIX);
+ error += 1;
+ return error;
+ }else{
+ status = DUMP;
+ }
+ }break;
+ case SCRIPT_OPCODE_DUMP_END:
+ status = END;
+ break;
+ }
+
+ //status ÊÌ¤Ë script ¤ÎÀ©¸æ. while ¤òÈ´¤±¤ë¤Î¤Ç switch ¤ò»È¤¨¤Ê¤¤
+ if(status == END){
+ break;
+ }else if(status == STEP_THOUGH){
+ int stepcount = 1;
+ int end = 0;
+ while(s->opcode != SCRIPT_OPCODE_DUMP_END){
+ switch(s->opcode){
+ case SCRIPT_OPCODE_STEP_START:
+ stepcount++;
+ break;
+ case SCRIPT_OPCODE_STEP_END:
+ stepcount--;
+ if(stepcount == 0){
+ end = 1;
+ }
+ break;
+ }
+ s++;
+ if(end == 1){
+ break;
+ }
+ }
+ status = DUMP;
+ }
+ //opcode ÊÌ¤Ë script ¤ÎÀ©¸æ. while ¤òÈ´¤±¤ë¤Î¤Ç switch ¤ò»È¤¨¤Ê¤¤
+ if(s->opcode == SCRIPT_OPCODE_STEP_END){
+ if(variable_num == 0){
+ printf("%d:%s loop closed, missing STEP_START\n", s->line, LOGICAL_ERROR_PREFIX);
+ return error + 1;
+ }
+ s = step_end(&s[1]);
+ status = DUMP;
+ }else if(s->opcode == SCRIPT_OPCODE_DUMP_END){
+ break;
+ }else{
+ s++;
+ }
+ }
+
+ //loop open conform
+ if(variable_num != 0){
+ printf("%d:%s loop opened, missing STEP_END\n", s->line, LOGICAL_ERROR_PREFIX);
+ error += 1;
+ }
+ //dump length conform
+ error += dump_length_conform(OPSTR_CPU_ROMSIZE, cpu_romsize, r->cpu_rom.size);
+ error += dump_length_conform(OPSTR_CPU_RAMSIZE, cpu_ramsize, r->cpu_ram.size);
+ error += dump_length_conform(OPSTR_PPU_ROMSIZE, ppu_romsize, r->ppu_rom.size);
+
+ //command line config override
+ if(c->mirror != CONFIG_OVERRIDE_UNDEF){
+ r->mirror = c->mirror;
+ }
+ if(c->backupram != CONFIG_OVERRIDE_UNDEF){
+ r->backupram = 1;
+ }
+ if(c->mapper != CONFIG_OVERRIDE_UNDEF){
+ //program mode ¤Ç mapper Êѹ¹¤òËɤ°
+ assert(c->mode == MODE_ROM_DUMP);
+ r->mappernum = c->mapper;
+ }
+ if(c->syntaxtest == 1){
+ if(error == 0){
+ printf("syntax ok!\n");
+ }
+ error += 1;
+ }
+ return error;
+}
+
+/*
+execute() ÍÑ¥µ¥Ö´Ø¿ô¤È¥Ç¡¼¥¿
+*/
+static int execute_connection_check(const struct reader_driver *d)
+{
+ int ret = OK;
+ const int testsize = 0x80;
+ int testcount = 3;
+ uint8_t *master, *reload;
+ master = Malloc(testsize);
+ reload = Malloc(testsize);
+
+ d->cpu_read(0xfee0, testsize, master);
+
+ while(testcount != 0){
+ d->cpu_read(0xfee0, testsize, reload);
+ if(memcmp(master, reload, testsize) != 0){
+ ret = NG;
+ break;
+ }
+ testcount--;
+ }
+
+ Free(master);
+ Free(reload);
+ return ret;
+}
+
+enum {PPU_TEST_RAM, PPU_TEST_ROM};
+const uint8_t PPU_TEST_DATA[] = "PPU_TEST_DATA";
+static int ppu_ramfind(const struct reader_driver *d)
+{
+ const long length = sizeof(PPU_TEST_DATA);
+ const long testaddr = 123;
+ uint8_t writedata[length];
+ //ppu ram data fill 0
+ memset(writedata, 0, length);
+ d->ppu_write(testaddr, length, writedata);
+
+ //ppu test data write
+ d->ppu_write(testaddr, length, PPU_TEST_DATA);
+
+ d->ppu_read(testaddr, length, writedata);
+ if(memcmp(writedata, PPU_TEST_DATA, length) == 0){
+ return PPU_TEST_RAM;
+ }
+ return PPU_TEST_ROM;
+}
+
+static int ramtest(const int region, const struct reader_driver *d, long address, long length, uint8_t *writedata, uint8_t *testdata, const long filldata)
+{
+ memset(writedata, filldata, length);
+ switch(region){
+ case MEMORY_AREA_CPU_RAM:
+ d->cpu_write_6502(address, length, writedata);
+ break;
+ case MEMORY_AREA_PPU:
+ d->ppu_write(address, length, writedata);
+ break;
+ default:
+ assert(0);
+ }
+ switch(region){
+ case MEMORY_AREA_CPU_RAM:
+ d->cpu_read(address, length, testdata);
+ break;
+ case MEMORY_AREA_PPU:
+ d->ppu_read(address, length, testdata);
+ break;
+ default:
+ assert(0);
+ }
+ if(memcmp(writedata, testdata, length) == 0){
+ return 0;
+ }
+ return 1;
+}
+
+static const long SRAMTESTDATA[] = {0xff, 0xaa, 0x55, 0x00};
+static int sramtest(const int region, const struct reader_driver *d, long address, long length)
+{
+ uint8_t *writedata, *testdata;
+ int error = 0;
+ int i;
+ testdata = Malloc(length);
+ writedata = Malloc(length);
+ for(i = 0; i < sizeof(SRAMTESTDATA) / sizeof(long); i++){
+ const long filldata = SRAMTESTDATA[i];
+ error += ramtest(region, d, address, length, testdata, writedata, filldata);
+ }
+ Free(testdata);
+ Free(writedata);
+ return error;
+}
+
+static void readbuffer_print(const struct memory *m, long length)
+{
+ if(length >= 0x10){
+ length = 0x10;
+ }
+ printf("%s ROM 0x%05x:", m->name, m->offset);
+ int offset = 0;
+ const uint8_t *data;
+ data = m->data;
+ while(length != 0){
+ char safix;
+ switch(offset & 0xf){
+ default:
+ safix = ' ';
+ break;
+ case 0x7:
+ safix = '-';
+ break;
+ case 0xf:
+ safix = ';';
+ break;
+ }
+ printf("%02x%c", (int) *data, safix);
+ data++;
+ offset++;
+ length--;
+ }
+}
+
+static void checksum_print(const uint8_t *data, long length)
+{
+ int sum = 0;
+ while(length != 0){
+ sum += (int) *data;
+ data++;
+ length--;
+ }
+ printf(" 0x%06x\n", sum);
+}
+
+static void read_result_print(const struct memory *m, long length)
+{
+ readbuffer_print(m, length);
+ checksum_print(m->data, length);
+ fflush(stdout);
+}
+
+static void execute_program_begin(const struct memory *m, const long length)
+{
+ int tail = m->offset + (int) length - 1;
+ printf("writing %s area 0x%06x-0x%06x ... ", m->name, m->offset, tail);
+ fflush(stdout);
+}
+
+static const char STR_OK[] = "OK";
+static const char STR_NG[] = "NG";
+
+//memcmp ¤ÎÌá¤êÃͤ¬Æþ¤ë¤Î¤Ç 0 ¤¬Àµ¾ï
+static void execute_program_finish(int result)
+{
+ const char *str;
+ str = STR_NG;
+ if(result == 0){
+ str = STR_OK;
+ }
+ printf("%s\n", str);
+ fflush(stdout);
+}
+static const char EXECUTE_ERROR_PREFIX[] = "execute error:";
+static const char EXECUTE_PROGRAM_PREPARE[] = "%s device initialize ... ";
+static const char EXECUTE_PROGRAM_DONE[] = "done\n";
+static void execute_cpu_ramrw(const struct reader_driver *d, const struct memory *ram, int mode, long address, long length)
+{
+ if(mode == MODE_RAM_WRITE){
+ d->cpu_write_6502(address, length, ram->data);
+/* const uint8_t *writedata;
+ long a = address;
+ long l = length;
+ writedata = ram->data;
+ while(l != 0){
+ d->cpu_write_6502(a++, *writedata, wait);
+ writedata += 1;
+ l--;
+ }*/
+ uint8_t *compare;
+ compare = Malloc(length);
+ d->cpu_read(address, length, compare);
+ if(memcmp(ram->data, compare, length) == 0){
+ printf("RAM data write success\n");
+ }else{
+ printf("RAM data write failed\n");
+ }
+ Free(compare);
+ }else{
+ d->cpu_read(address, length, ram->data);
+ }
+}
+
+static int execute(const struct script *s, const struct st_config *c, struct romimage *r)
+{
+ const struct reader_driver *const d = c->reader;
+ switch(d->open_or_close(READER_OPEN)){
+ case OK:
+ d->init();
+ break;
+ case NG:
+ printf("%s driver open error\n", EXECUTE_ERROR_PREFIX);
+ return NG;
+ default:
+ assert(0);
+ }
+ if(execute_connection_check(d) == NG){
+ printf("%s maybe connection error\n", EXECUTE_ERROR_PREFIX);
+ d->open_or_close(READER_CLOSE);
+ return NG;
+ }
+ uint8_t *program_compare;
+ program_compare = NULL;
+ if(c->mode == MODE_ROM_PROGRAM){
+ printf("flashmemory/SRAM program mode. To abort programming, press Ctrl+C\n");
+ int size = r->cpu_rom.size;
+ if(size < r->ppu_rom.size){
+ size = r->ppu_rom.size;
+ }
+ program_compare = Malloc(size);
+ }
+ struct memory cpu_rom, ppu_rom, cpu_ram;
+ cpu_rom = r->cpu_rom;
+ ppu_rom = r->ppu_rom;
+ cpu_ram = r->cpu_ram;
+
+ int status = DUMP;
+ int programcount_cpu = 0, programcount_ppu = 0;
+ int flashcommand_change_cpu = 0, flashcommand_change_ppu = 0;
+ variable_init_all();
+ while(s->opcode != SCRIPT_OPCODE_DUMP_END){
+ //printf("%s\n", SCRIPT_SYNTAX[s->opcode].name);
+ switch(s->opcode){
+ case SCRIPT_OPCODE_CPU_COMMAND:
+ command_mask(MEMORY_AREA_CPU_ROM, s->value[0], s->value[1], s->value[2], &(r->cpu_flash));
+ flashcommand_change_cpu = 1;
+ break;
+ case SCRIPT_OPCODE_CPU_READ:{
+ struct memory *m;
+ const long address = s->value[0];
+ const long length = s->value[1];
+ m = &cpu_rom;
+ d->cpu_read(address, length, m->data);
+ read_result_print(m, length);
+ m->data += length;
+ m->offset += length;
+ }break;
+ case SCRIPT_OPCODE_CPU_WRITE:{
+ long data;
+ uint8_t d8;
+ expression_calc(&s->expression, &data);
+ d8 = data & 0xff;
+ d->cpu_write_6502(s->value[0], 1, &d8);
+ }
+ break;
+ case SCRIPT_OPCODE_CPU_RAMRW:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ if(c->mode == MODE_RAM_WRITE){
+ if(sramtest(MEMORY_AREA_CPU_RAM, d, address, length) != 0){
+ printf("SRAM test NG\n");
+ status = END;
+ break;
+ }
+ }
+ execute_cpu_ramrw(d, &cpu_ram, c->mode, address, length);
+ read_result_print(&cpu_ram, length);
+ cpu_ram.data += length;
+ cpu_ram.offset += length;
+ }
+ break;
+ case SCRIPT_OPCODE_CPU_PROGRAM:{
+ if(c->cpu_flash_driver->id_device == FLASH_ID_DEVICE_DUMMY){
+ break;
+ }
+ if(flashcommand_change_cpu != 0){
+ r->cpu_flash.config(
+ r->cpu_flash.command_0000,
+ r->cpu_flash.command_2aaa,
+ r->cpu_flash.command_5555,
+ r->cpu_flash.pagesize,
+ false
+ );
+ flashcommand_change_cpu = 0;
+ }
+ if(programcount_cpu++ == 0){
+ printf(EXECUTE_PROGRAM_PREPARE, cpu_rom.name);
+ fflush(stdout);
+ //device ¤Ë¤è¤Ã¤Æ¤Ï erase
+ c->cpu_flash_driver->init(&(r->cpu_flash), c->cpu_flash_driver->erase_wait);
+ printf(EXECUTE_PROGRAM_DONE);
+ fflush(stdout);
+ }
+ const long address = s->value[0];
+ const long length = s->value[1];
+ execute_program_begin(&cpu_rom, length);
+ c->cpu_flash_driver->program(
+ &(r->cpu_flash),
+ address, length,
+ &cpu_rom
+ );
+ int result;
+ if(1){
+ d->cpu_read(address, length, program_compare);
+ result = memcmp(program_compare, cpu_rom.data, length);
+ execute_program_finish(result);
+ }else{
+ puts("skip");
+ result = 1;
+ }
+ cpu_rom.data += length;
+ cpu_rom.offset += length;
+
+ if((DEBUG==0) && (result != 0)){
+ status = END;
+ }
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_COMMAND:
+ command_mask(MEMORY_AREA_PPU, s->value[0], s->value[1], s->value[2], &(r->ppu_flash));
+ flashcommand_change_ppu = 1;
+ break;
+ case SCRIPT_OPCODE_PPU_RAMFIND:
+ if(ppu_ramfind(d) == PPU_TEST_RAM){
+ printf("PPU_RAMFIND: charcter RAM found\n");
+ r->ppu_rom.size = 0;
+ status = END;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_SRAMTEST:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ printf("PPU_SRAMTEST: 0x%06x-0x%06x ", (int)ppu_rom.offset, (int) (ppu_rom.offset + length) - 1);
+ if(sramtest(MEMORY_AREA_PPU, d, address, length) == 0){
+ printf("%s\n", STR_OK);
+ }else{
+ printf("%s\n", STR_NG);
+ //status = END;
+ }
+ }break;
+ case SCRIPT_OPCODE_PPU_READ:{
+ const long address = s->value[0];
+ const long length = s->value[1];
+ if(length == 0){
+ /*for mmc2,4 protect.
+ ¤³¤Î¤È¤¤Ï1byteÆɤ߹þ¤ó¤Ç¡¢¤½¤ÎÆâÍƤϥХåե¡¤Ë¤¤¤ì¤Ê¤¤*/
+ uint8_t dummy;
+ d->ppu_read(address, 1, &dummy);
+ }else{
+ d->ppu_read(address, length, ppu_rom.data);
+ read_result_print(&ppu_rom, length);
+ }
+ ppu_rom.data += length;
+ ppu_rom.offset += length;
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_WRITE:
+ if(DEBUG == 1){
+ long data;
+ uint8_t d8;
+ expression_calc(&s->expression, &data);
+ d8 = data;
+ d->ppu_write(s->value[0], 1, &d8);
+ }
+ break;
+ case SCRIPT_OPCODE_PPU_PROGRAM:{
+ if(c->ppu_flash_driver->id_device == FLASH_ID_DEVICE_DUMMY){
+ break;
+ }
+ if(flashcommand_change_ppu != 0){
+ r->ppu_flash.config(
+ r->ppu_flash.command_0000,
+ r->ppu_flash.command_2aaa,
+ r->ppu_flash.command_5555,
+ r->ppu_flash.pagesize,
+ false
+ );
+ flashcommand_change_ppu = 0;
+ }
+ if(programcount_ppu++ == 0){
+ printf(EXECUTE_PROGRAM_PREPARE, ppu_rom.name);
+ fflush(stdout);
+ c->ppu_flash_driver->init(&(r->ppu_flash), c->ppu_flash_driver->erase_wait);
+ printf(EXECUTE_PROGRAM_DONE);
+ fflush(stdout);
+ }
+ const long address = s->value[0];
+ const long length = s->value[1];
+ execute_program_begin(&ppu_rom, length);
+ c->ppu_flash_driver->program(
+ &(r->ppu_flash),
+ address, length,
+ &ppu_rom
+ );
+ d->ppu_read(address, length, program_compare);
+ const int result = memcmp(program_compare, ppu_rom.data, length);
+ execute_program_finish(result);
+ ppu_rom.data += length;
+ ppu_rom.offset += length;
+
+ if((DEBUG==0) && (result != 0)){
+ status = END;
+ }
+ }
+ break;
+ case SCRIPT_OPCODE_STEP_START:{
+ if(s->value[STEP_START] >= s->value[STEP_END]){
+ status = STEP_THOUGH;
+ }else{
+ //¥ë¡¼¥×¤ÎÌá¤êÀè¤Ï¤³¤ÎÌ¿Îá¤Î¼¡¤Ê¤Î¤Ç &s[1]
+ step_new(s->variable, s->value[STEP_START], s->value[STEP_END], s->value[STEP_NEXT], &s[1]);
+ }
+ }break;
+ case SCRIPT_OPCODE_DUMP_END:
+ status = END;
+ break;
+ }
+ if(status == END){
+ break;
+ }else if(status == STEP_THOUGH){
+ //¤³¤Ô¤Ú
+ int stepcount = 1;
+ int end = 0;
+ while(s->opcode != SCRIPT_OPCODE_DUMP_END){
+ switch(s->opcode){
+ case SCRIPT_OPCODE_STEP_START:
+ stepcount++;
+ break;
+ case SCRIPT_OPCODE_STEP_END:
+ stepcount--;
+ if(stepcount == 0){
+ end = 1;
+ }
+ break;
+ }
+ s++;
+ if(end == 1){
+ break;
+ }
+ }
+ status = DUMP;
+ }
+
+ if(s->opcode == SCRIPT_OPCODE_STEP_END){
+ s = step_end(++s);
+ }else{
+ s++;
+ }
+ }
+ d->open_or_close(READER_CLOSE);
+ if(program_compare != NULL){
+ Free(program_compare);
+ }
+ return OK;
+}
+
+void script_load(const struct st_config *c)
+{
+ struct script *s;
+ {
+ int scriptsize = 0;
+ char *buf;
+
+ buf = buf_load_full(c->script, &scriptsize);
+ if(buf == NULL){
+ printf("scriptfile open error\n");
+ return;
+ }
+ char **text;
+ text = Malloc(sizeof(char*) * TEXT_MAXLINE);
+ const int text_num = text_load(buf, scriptsize, text);
+ if(text_num == 0){
+ printf("script line too much\n");
+ Free(buf);
+ Free(text);
+ return;
+ }
+ s = Malloc(sizeof(struct script) * (text_num + 1));
+ //logical_check, execute ¶¦¤Ë s->opcode ¤¬ DUMP_END ¤Ë¤Ê¤ë¤Þ¤Ç³¤±¤ë¡£DUMP_END ¤ÎÆþ¤ì˺¤ìÍѤËËöÈø¤Îscript¤Ëɬ¤º DUMP_END ¤ò¤¤¤ì¤ë
+ {
+ struct script *k;
+ k = s;
+ k += text_num;
+ k->opcode = SCRIPT_OPCODE_DUMP_END;
+ }
+ const int error = syntax_check(text, text_num, s, c->mode);
+ Free(buf);
+ Free(text);
+ if(error != 0){
+ Free(s);
+ return;
+ }
+ }
+ struct romimage r = {
+ .cpu_rom = {
+ .size = 0, .offset = 0,
+ .data = NULL,
+ .attribute = MEMORY_ATTR_NOTUSE,
+ .name = "program"
+ },
+ .ppu_rom = {
+ .size = 0, .offset = 0,
+ .data = NULL,
+ .attribute = MEMORY_ATTR_NOTUSE,
+ .name = "charcter"
+ },
+ .cpu_ram = {
+ .size = 0, .offset = 0,
+ .data = NULL,
+ .attribute = MEMORY_ATTR_NOTUSE,
+ .name = STR_REGION_CPU
+ },
+ //device ¤Ë±þ¤¸¤¿´Ø¿ô¥Ý¥¤¥ó¥¿¤ò flash_order ¤ËÅϤ¹
+ .cpu_flash = {
+ .command_0000 = 0x8000,
+ .command_2aaa = 0,
+ .command_5555 = 0,
+ .pagesize = c->cpu_flash_driver->pagesize,
+ .command_mask = c->cpu_flash_driver->command_mask,
+ .config = c->reader->cpu_flash_config,
+ .erase = c->reader->cpu_flash_erase,
+ .program = c->reader->cpu_flash_program,
+ .write = NULL //c->reader->cpu_write_6502
+ },
+ .ppu_flash = {
+ .command_0000 = 0,
+ .command_2aaa = 0,
+ .command_5555 = 0,
+ .pagesize = c->ppu_flash_driver->pagesize,
+ .command_mask = c->ppu_flash_driver->command_mask,
+ .config = c->reader->ppu_flash_config,
+ .erase = c->reader->ppu_flash_erase,
+ .program = c->reader->ppu_flash_program,
+ .write = NULL //c->reader->ppu_write
+ },
+ .mappernum = 0,
+ .mirror = MIRROR_PROGRAMABLE
+ };
+ //attribute ¤Ï¤½¤Î struct data ¤ËÂФ·¤Æ¤Î RW ¤Ê¤Î¤ÇÍ×Ãí°Õ
+ switch(c->mode){
+ case MODE_ROM_DUMP:
+ r.cpu_rom.attribute = MEMORY_ATTR_WRITE;
+ r.ppu_rom.attribute = MEMORY_ATTR_WRITE;
+ break;
+ case MODE_RAM_READ:
+ r.cpu_ram.attribute = MEMORY_ATTR_WRITE;
+ break;
+ case MODE_RAM_WRITE:
+ r.cpu_ram.attribute = MEMORY_ATTR_READ;
+ break;
+ case MODE_ROM_PROGRAM:
+ r.cpu_rom.attribute = MEMORY_ATTR_READ;
+ r.ppu_rom.attribute = MEMORY_ATTR_READ;
+ break;
+ default:
+ assert(0);
+ }
+
+ if(logical_check(s, c, &r) == 0){
+ //dump RAM Îΰè¼èÆÀ
+ if(nesbuffer_malloc(&r, c->mode) == false){
+ Free(s);
+ if((c->mode == MODE_RAM_WRITE) && (r.cpu_ram.data != NULL)){
+ Free(r.cpu_ram.data);
+ }
+ return;
+ }
+ //script execute!!
+ if(execute(s, c, &r) == OK){
+ //À®²Ì½ÐÎÏ
+ switch(c->mode){
+ case MODE_ROM_DUMP:
+ nesfile_create(&r, c->romimage);
+ break;
+ case MODE_RAM_READ:
+ backupram_create(&(r.cpu_ram), c->ramimage);
+ break;
+ }
+ }
+ //dump RAM Îΰè²òÊü
+ nesbuffer_free(&r, c->mode);
+ if((c->mode == MODE_RAM_WRITE) && (r.cpu_ram.data != NULL)){
+ Free(r.cpu_ram.data);
+ }
+ }
+ Free(s);
+}
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+script syntax data and function
+
+Copyright (C) 2008-2009 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "type.h"
+#include "textutil.h"
+#include "script.h"
+#include "script_syntax.h"
+
+static int syntax_check_expression(char **word, int word_num, struct st_expression *e)
+{
+ if(word_num == 0){
+ return NG;
+ }
+ //left
+ if(value_get(word[0], &(e->left.value)) == OK){
+ e->left.type = EXPRESSION_TYPE_VALUE;
+ }else{
+ e->left.type = EXPRESSION_TYPE_VARIABLE;
+ e->left.variable = word[0][0];
+ }
+ word_num--;
+ if(word_num == 0){
+ e->operator = OPERATOR_NONE;
+ return OK;
+ }
+ //operator
+ e->operator = operator_get(word[1]);
+ if(e->operator == OPERATOR_ERROR){
+ return NG;
+ }
+ word_num--;
+ if(word_num == 0){
+ return NG;
+ }
+ //right
+ if(value_get(word[2], &(e->right.value)) == OK){
+ e->right.type = EXPRESSION_TYPE_VALUE;
+ }else{
+ e->right.type = EXPRESSION_TYPE_VARIABLE;
+ e->right.variable = word[2][0];
+ }
+ return OK;
+}
+
+static int strto_enum(const char **t, const char *word, int start, long *val)
+{
+ long i = start;
+ while(*t != NULL){
+ if(strcmp(*t, word) == 0){
+ *val = i;
+ return OK;
+ }
+ i++;
+ t++;
+ }
+ return NG;
+}
+
+#include "syntax_data.h"
+static const char SYNTAX_ERROR_PREFIX[] = "syntax error:";
+
+/*
+return: error count, ¤³¤³¤Ç¤Ï 0 or 1
+*/
+static int syntax_check_phase(char **word, int word_num, struct script *s, const int mode)
+{
+ int i = sizeof(SCRIPT_SYNTAX) / sizeof(SCRIPT_SYNTAX[0]);
+ const struct script_syntax *syntax;
+ const char *opword;
+ opword = word[0];
+ syntax = SCRIPT_SYNTAX;
+ while(i != 0){
+ if(strcmp(syntax->name, opword) == 0){
+ int j;
+
+ s->opcode = syntax->script_opcode;
+ if((mode & syntax->permittion) == 0){
+ printf("%d:%s opcode %s is not allowed on current mode\n", s->line, SYNTAX_ERROR_PREFIX, syntax->name);
+ return 1;
+ };
+ {
+ int compare = 0;
+ switch(syntax->compare){
+ case SYNTAX_COMPARE_EQ:
+ compare = (syntax->argc == (word_num - 1));
+ break;
+ case SYNTAX_COMPARE_GT:
+ compare = ((word_num - 1) >= syntax->argc);
+ compare &= (word_num <= 5);
+ break;
+ }
+ if(!compare){
+ printf("%d:%s parameter number not match %s\n", s->line, SYNTAX_ERROR_PREFIX, opword);
+ return 1;
+ }
+ }
+ //opcode pointer ¤ò¤º¤é¤·¤Æñ¸ì¤Îµ¯ÅÀ¤ò°ú¿ô¤À¤±¤Ë¤¢¤ï¤»¤ë
+ word++;
+ word_num--;
+ for(j = 0; j < word_num; j++){
+ switch(syntax->argv_type[j]){
+ case SYNTAX_ARGVTYPE_NULL:
+ printf("%d:%s ARGV_NULL select\n", s->line, SYNTAX_ERROR_PREFIX);
+ return 1;
+ case SYNTAX_ARGVTYPE_VALUE:
+ if(value_get(word[j], &(s->value[j])) == NG){
+ printf("%d:%s value error %s %s\n", s->line, SYNTAX_ERROR_PREFIX, opword, word[j]);
+ return 1;
+ }
+ break;
+ case SYNTAX_ARGVTYPE_HV:
+ switch(word[j][0]){
+ case 'H':
+ case 'h':
+ s->value[j] = MIRROR_HORIZONAL;
+ break;
+ case 'V':
+ case 'v':
+ s->value[j] = MIRROR_VERTICAL;
+ break;
+ case 'A':
+ case 'a':
+ s->value[j] = MIRROR_PROGRAMABLE;
+ break;
+ default:
+ printf("%d:%s unknown scroll mirroring type %s\n", s->line, SYNTAX_ERROR_PREFIX, word[j]);
+ return 1;
+ }
+ break;
+ case SYNTAX_ARGVTYPE_EXPRESSION:
+ s->value[j] = VALUE_EXPRESSION;
+ //Ì¿Îá̾¤Îñ¸ì¤Èñ¸ì¿ô¤ò½ü³°¤·¤ÆÅϤ¹
+ if(syntax_check_expression(&word[j], word_num - 1, &s->expression) == NG){
+ printf("%d:%s expression error\n", s->line, SYNTAX_ERROR_PREFIX);
+ return 1;
+ }
+ //°Ü¹Ô¤Îñ¸ì¤ÏÆɤޤʤ¤¤³¤È¤Ë¤¹¤ë(¤Þ¤º¤¤¤«¤â)
+ return 0;
+ case SYNTAX_ARGVTYPE_VARIABLE:{
+ const char v = word[j][0];
+ if(v >= 'a' && v <= 'z'){
+ s->value[j] = VALUE_VARIABLE;
+ s->variable = v;
+ }else{
+ printf("%d:%s variable must use [a-z] %s\n", s->line, SYNTAX_ERROR_PREFIX, word[j]);
+ return 1;
+ }
+ }break;
+ case SYNTAX_ARGVTYPE_CONSTANT:{
+ if(value_get(word[j], &(s->value[j])) == OK){
+ break;
+ }else if(strto_enum(STR_CONSTANTNAME, word[j], VALUE_CONTANT_CPU_STEP_START, &(s->value[j])) == OK){
+ break;
+ }else{
+ printf("%d:%s constant error %s %s\n", s->line, SYNTAX_ERROR_PREFIX, opword, word[j]);
+ return 1;
+ }
+ }break;
+ case SYNTAX_ARGVTYPE_TRANSTYPE:{
+ if(strto_enum(STR_TRANSTYPE, word[j], VALUE_TRANSTYPE_EMPTY, &(s->value[j])) == NG){
+ printf("%d:%s unknown trans type %s\n", s->line, SYNTAX_ERROR_PREFIX, word[j]);
+ return 1;
+ }
+ }break;
+ default:
+ s->value[j] = VALUE_UNDEF;
+ break;
+ }
+ }
+ //opcode found and ÆþÎÏʸ»ú¼ïÀµ¾ï
+ return 0;
+ }
+ syntax++;
+ i--;
+ }
+ printf("%d:%s unknown opcode %s\n", s->line, SYNTAX_ERROR_PREFIX, opword);
+ return 1;
+}
+
+/*
+return: error count
+*/
+int syntax_check(char **text, int text_num, struct script *s, int mode)
+{
+ int error = 0;
+ int i;
+ mode = 1<< mode; //permittion ¤Ï bitflag ¤Ê¤Î¤Ç¤³¤³¤ÇÊÑ´¹¤¹¤ë
+ for(i = 0; i < text_num; i++){
+ char *word[TEXT_MAXWORD];
+ const int n = word_load(text[i], word);
+ s->line = i + 1;
+ switch(word[0][0]){
+ case '#':
+ case '\0':
+ s->opcode = SCRIPT_OPCODE_COMMENT;
+ break;
+ default:
+ error += syntax_check_phase(word, n, s, mode);
+ break;
+ }
+ s++;
+ }
+ return error;
+}
+
--- /dev/null
+#ifndef _SYNTAX_H_
+#define _SYNTAX_H_
+#include "config.h"
+#include "header.h"
+enum script_opcode{
+ SCRIPT_OPCODE_MAPPER,
+ SCRIPT_OPCODE_MIRROR,
+ SCRIPT_OPCODE_CPU_ROMSIZE,
+ SCRIPT_OPCODE_CPU_RAMSIZE,
+ SCRIPT_OPCODE_CPU_FLASHSIZE,
+ SCRIPT_OPCODE_PPU_ROMSIZE,
+ SCRIPT_OPCODE_PPU_FLASHSIZE,
+ SCRIPT_OPCODE_DUMP_START,
+ SCRIPT_OPCODE_CPU_COMMAND,
+ SCRIPT_OPCODE_CPU_READ,
+ SCRIPT_OPCODE_CPU_WRITE,
+ SCRIPT_OPCODE_CPU_RAMRW,
+ SCRIPT_OPCODE_CPU_PROGRAM,
+ SCRIPT_OPCODE_PPU_COMMAND,
+ SCRIPT_OPCODE_PPU_RAMFIND,
+ SCRIPT_OPCODE_PPU_SRAMTEST,
+ SCRIPT_OPCODE_PPU_READ,
+ SCRIPT_OPCODE_PPU_WRITE,
+ SCRIPT_OPCODE_PPU_PROGRAM,
+ SCRIPT_OPCODE_STEP_START,
+ SCRIPT_OPCODE_STEP_END,
+ SCRIPT_OPCODE_DUMP_END,
+ SCRIPT_OPCODE_COMMENT,
+ SCRIPT_OPCODE_NUM
+};
+extern const char OPSTR_CPU_ROMSIZE[];
+extern const char OPSTR_CPU_RAMSIZE[];
+extern const char OPSTR_CPU_FLASHSIZE[];
+extern const char OPSTR_PPU_ROMSIZE[];
+extern const char OPSTR_PPU_FLASHSIZE[];
+extern const char OPSTR_CPU_RAMRW[];
+struct script;
+int syntax_check(char **text, int text_num, struct script *s, int mode);
+#endif
--- /dev/null
+//included from syntax.c only
+enum syntax_argvtype{
+ SYNTAX_ARGVTYPE_NULL,
+ SYNTAX_ARGVTYPE_VALUE,
+ SYNTAX_ARGVTYPE_HV,
+ SYNTAX_ARGVTYPE_EXPRESSION,
+ SYNTAX_ARGVTYPE_VARIABLE,
+ SYNTAX_ARGVTYPE_CONSTANT,
+ SYNTAX_ARGVTYPE_TRANSTYPE
+};
+enum syntax_compare{
+ SYNTAX_COMPARE_EQ,
+ SYNTAX_COMPARE_GT
+};
+enum{
+ SYNTAX_ARGV_TYPE_NUM = 4
+};
+enum syntax_permittion{
+ PERMITTION_ROM_DUMP = 1 << MODE_ROM_DUMP,
+ PERMITTION_RAM_READ = 1 << MODE_RAM_READ,
+ PERMITTION_RAM_WRITE = 1 << MODE_RAM_WRITE,
+ PERMITTION_ROM_PROGRAM = 1 << MODE_ROM_PROGRAM,
+ PERMITTION_ALL = 0xffff
+};
+struct script_syntax{
+ const char *name;
+ enum script_opcode script_opcode;
+ enum syntax_permittion permittion;
+ int argc;
+ enum syntax_compare compare;
+ const enum syntax_argvtype *argv_type;
+};
+//¤³¤ì¤é¤Îʸ»úÎó¤Ï script_engine.c ¤Ç¤â»ÈÍѤ¹¤ë
+const char OPSTR_CPU_ROMSIZE[] = "CPU_ROMSIZE";
+const char OPSTR_CPU_RAMSIZE[] = "CPU_RAMSIZE";
+const char OPSTR_CPU_FLASHSIZE[] = "CPU_FLASHSIZE";
+const char OPSTR_PPU_ROMSIZE[] = "PPU_ROMSIZE";
+const char OPSTR_PPU_FLASHSIZE[] = "PPU_FLASHSIZE";
+const char OPSTR_CPU_RAMRW[] = "CPU_RAMRW";
+
+static const enum syntax_argvtype
+ARGV_TYPE_VALUE_ONLY[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL,
+ SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL
+};
+static const enum syntax_argvtype
+ARGV_TYPE_HV[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_HV, SYNTAX_ARGVTYPE_NULL,
+ SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL
+};
+static const enum syntax_argvtype
+ARGV_TYPE_NULL[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL,
+ SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL
+};
+static const enum syntax_argvtype
+ARGV_TYPE_ADDRESS_EXPRESSION[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_VALUE,
+ SYNTAX_ARGVTYPE_EXPRESSION, SYNTAX_ARGVTYPE_EXPRESSION, SYNTAX_ARGVTYPE_EXPRESSION
+};
+static const enum syntax_argvtype
+ARGV_TYPE_ADDRESS_LENGTH[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE,
+ SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL
+};
+static const enum syntax_argvtype
+ARGV_TYPE_STEP_START[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_VARIABLE, SYNTAX_ARGVTYPE_CONSTANT,
+ SYNTAX_ARGVTYPE_CONSTANT, SYNTAX_ARGVTYPE_VALUE
+};
+static const enum syntax_argvtype
+ARGV_TYPE_ADDRESS_COMMAND[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE,
+ SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL
+};
+static const enum syntax_argvtype
+ARGV_TYPE_FLASHSIZE[SYNTAX_ARGV_TYPE_NUM] = {
+ SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_TRANSTYPE,
+ SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE
+};
+static const struct script_syntax SCRIPT_SYNTAX[] = {
+ {
+ name: "MAPPER",
+ script_opcode: SCRIPT_OPCODE_MAPPER,
+ permittion: PERMITTION_ROM_DUMP | PERMITTION_ROM_PROGRAM,
+ argc: 1, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_VALUE_ONLY
+ },{
+ name: "MIRROR",
+ script_opcode: SCRIPT_OPCODE_MIRROR,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 1, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_HV
+ },{
+ name: OPSTR_CPU_ROMSIZE,
+ script_opcode: SCRIPT_OPCODE_CPU_ROMSIZE,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 1, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_VALUE_ONLY
+ },{
+ name: OPSTR_CPU_RAMSIZE,
+ script_opcode: SCRIPT_OPCODE_CPU_RAMSIZE,
+ permittion: PERMITTION_RAM_READ | PERMITTION_RAM_WRITE,
+ argc: 1, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_VALUE_ONLY
+ },{
+ name: OPSTR_CPU_FLASHSIZE,
+ script_opcode: SCRIPT_OPCODE_CPU_FLASHSIZE,
+ permittion: PERMITTION_ROM_PROGRAM,
+ argc: 4, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_FLASHSIZE
+ },{
+ name: OPSTR_PPU_ROMSIZE,
+ script_opcode: SCRIPT_OPCODE_PPU_ROMSIZE,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 1, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_VALUE_ONLY
+ },{
+ name: OPSTR_PPU_FLASHSIZE,
+ script_opcode: SCRIPT_OPCODE_PPU_FLASHSIZE,
+ permittion: PERMITTION_ROM_PROGRAM,
+ argc: 4, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_FLASHSIZE
+ },{
+ name: "CPU_COMMAND",
+ script_opcode: SCRIPT_OPCODE_CPU_COMMAND,
+ permittion: PERMITTION_ROM_PROGRAM,
+ argc:3, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_COMMAND
+ },{
+ name: "PPU_COMMAND",
+ script_opcode: SCRIPT_OPCODE_PPU_COMMAND,
+ permittion: PERMITTION_ROM_PROGRAM,
+ argc:3, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_COMMAND
+ },{
+ name: "DUMP_START",
+ script_opcode: SCRIPT_OPCODE_DUMP_START,
+ permittion: PERMITTION_ALL,
+ argc: 0, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_NULL
+ },{
+ name: "CPU_READ",
+ script_opcode: SCRIPT_OPCODE_CPU_READ,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 2, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_LENGTH
+ },{
+ name: "CPU_WRITE",
+ script_opcode: SCRIPT_OPCODE_CPU_WRITE,
+ permittion: PERMITTION_ALL,
+ argc: 2, compare: SYNTAX_COMPARE_GT,
+ argv_type: ARGV_TYPE_ADDRESS_EXPRESSION
+ },{
+ name: OPSTR_CPU_RAMRW,
+ script_opcode: SCRIPT_OPCODE_CPU_RAMRW,
+ permittion: PERMITTION_RAM_READ | PERMITTION_RAM_WRITE,
+ argc: 2, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_LENGTH
+ },{
+ name: "CPU_PROGRAM",
+ script_opcode: SCRIPT_OPCODE_CPU_PROGRAM,
+ permittion: PERMITTION_ROM_PROGRAM,
+ argc: 2, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_LENGTH
+ },{
+ name: "PPU_RAMFIND",
+ script_opcode: SCRIPT_OPCODE_PPU_RAMFIND,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 0, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_NULL
+ },{
+ name: "PPU_SRAMTEST",
+ script_opcode: SCRIPT_OPCODE_PPU_SRAMTEST,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 2, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_LENGTH
+ },{
+ name: "PPU_READ",
+ script_opcode: SCRIPT_OPCODE_PPU_READ,
+ permittion: PERMITTION_ROM_DUMP,
+ argc: 2, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_LENGTH
+ },
+#if DEBUG==1
+ {
+ name: "PPU_WRITE",
+ script_opcode: SCRIPT_OPCODE_PPU_WRITE,
+ permittion: PERMITTION_ROM_DUMP | PERMITTION_ROM_PROGRAM,
+ argc: 2, compare: SYNTAX_COMPARE_GT,
+ argv_type: ARGV_TYPE_ADDRESS_EXPRESSION
+ },
+#endif
+ {
+ name: "PPU_PROGRAM",
+ script_opcode: SCRIPT_OPCODE_PPU_PROGRAM,
+ permittion: PERMITTION_ROM_PROGRAM,
+ argc: 2, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_ADDRESS_LENGTH,
+ },
+ {
+ name: "STEP_START",
+ script_opcode: SCRIPT_OPCODE_STEP_START,
+ permittion: PERMITTION_ALL,
+ argc: 4, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_STEP_START
+ },{
+ name: "STEP_END",
+ script_opcode: SCRIPT_OPCODE_STEP_END,
+ permittion: PERMITTION_ALL,
+ argc: 0, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_NULL
+ },{
+ name: "DUMP_END",
+ script_opcode: SCRIPT_OPCODE_DUMP_END,
+ permittion: PERMITTION_ALL,
+ argc: 0, compare: SYNTAX_COMPARE_EQ,
+ argv_type: ARGV_TYPE_NULL
+ }
+};
+
+static const char *STR_TRANSTYPE[] = {
+ "EMPTY", "TOP", "BOTTOM", "FULL", NULL
+};
+
+static const char *STR_CONSTANTNAME[] = {
+ "C_START", "C_END",
+ "P_START", "P_END", NULL
+};
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "type.h"
+#include "textutil.h"
+#ifndef DEBUG
+ #define DEBUG 0
+#endif
+
+#define PRINT(msg) \
+ if(DEBUG == 1){ \
+ printf("%s %s\n", __FUNCTION__, msg);\
+ }
+
+int text_load(char *buf, int length, char **text)
+{
+ int line = 0;
+ char pastdata = '#';
+
+ text[line] = buf;
+ line++;
+ while(length != 0){
+ //Àµ³Î¤Ê¹Ô¿ôÇÄ°®¤È¼êÈ´¤¤Î¤¿¤á CR only ¤Î²þ¹Ô¥³¡¼¥É¤ò̤¥µ¥Ý¡¼¥È¤È¤¹¤ë
+ int current_lf = 0;
+
+ switch(*buf){
+ case '\n':
+ *buf = '\0';
+ current_lf = 1;
+ break;
+ case '\r':
+ *buf = '\0';
+ break;
+ }
+ switch(pastdata){
+ case '\0':
+ if(line >= TEXT_MAXLINE){
+ PRINT("line over")
+ return 0;
+ }
+ if(current_lf == 0){
+ text[line] = buf;
+ line++;
+ }
+ break;
+ }
+ pastdata = *buf;
+ buf++;
+ length--;
+ }
+ buf--;
+ *buf = '\0';
+ return line;
+}
+
+int word_load(char *buf, char **text)
+{
+ int word = 0;
+ char pastdata = '#';
+
+ switch(*buf){
+ case '\t':
+ case ' ':
+ break;
+ case '#': //¹ÔƬ¥³¥á¥ó¥È
+ text[word] = buf;
+ return 1;
+ default:
+ text[word] = buf;
+ word++;
+ break;
+ }
+
+ while(*buf != '\0'){
+ int current_spc = 0;
+ switch(*buf){
+ case '\t':
+ case ' ':
+ *buf = '\0';
+ current_spc = 1;
+ break;
+ }
+ switch(pastdata){
+ case '\0':
+ if(word >= TEXT_MAXWORD){
+ PRINT("word over")
+ return 0;
+ }
+ if(current_spc == 0){
+ /*if(*buf == '#'){
+ return word;
+ }*/
+ text[word] = buf;
+ word++;
+ }
+ break;
+ }
+ pastdata = *buf;
+ buf++;
+ }
+ return word;
+}
+
+int value_get(const char *str, long *val)
+{
+ int base = 10;
+ int sign = 1;
+ //-¤¬¤Ä¤¤¤Æ¤ë¤«
+ switch(*str){
+ case '\0':
+ return NG;
+ case '-':
+ sign = -1;
+ str++;
+ if(*str == '\0'){
+ return NG;
+ }
+ break;
+ }
+ //0x, 0b, $, % ¤¬¤Ä¤¤¤Æ¤ë¤«
+ switch(*str){
+ case '0':
+ switch(str[1]){
+ case '\0':
+ //¤¿¤ó¤Ê¤ë 0 ¤Ê¤Î¤Ç OK
+ break;
+ case 'x':
+ base = 0x10;
+ str += 2;
+ break;
+ case 'b':
+ base = 2;
+ str += 2;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ //C¤Ê¤é8¿Ê¿ô°·¤¤¤À¤±¤É10¿Ê¿ô°·¤¤¤Ë¤¹¤ë
+ break;
+ default:
+ return NG;
+ }
+ break;
+ case '$':
+ base = 0x10;
+ str += 1;
+ break;
+ case '%':
+ base = 2;
+ str += 1;
+ break;
+ }
+ //¤³¤Î»þÅÀ¤Ç¤Î str ¤Ï ¿ô»ú¤ÎÀèƬ¤È¤·¤Æ¤¿¾ì½ê
+ char *error;
+ *val = strtol(str, &error, base);
+ if(error[0] != '\0'){
+ //x01
+ //4M\0
+ if((error[1] == '\0') && (base == 10)){
+ switch(error[0]){
+ case 'K':
+ *val *= 0x400;
+ break;
+ case 'M':
+ *val *= 0x20000;
+ break;
+ default:
+ return NG;
+ }
+ }else{
+ return NG;
+ }
+ }
+
+ if(sign == -1){
+ *val = -(*val);
+ }
+ return OK;
+}
+
+struct operator_cmp{
+ char *str;
+ int operator;
+};
+static const struct operator_cmp CMP[] = {
+ {"+", OPERATOR_PLUS},
+ {">>", OPERATOR_SHIFT_LEFT},
+ {"<<", OPERATOR_SHIFT_RIGHT},
+ {"&", OPERATOR_AND},
+ {"|", OPERATOR_OR},
+ {"^", OPERATOR_XOR}
+};
+
+int operator_get(char *str)
+{
+ const struct operator_cmp *c;
+ int i = OPERATOR_ERROR;
+ c = CMP;
+ while(i != 0){
+ if(strcmp(c->str, str) == 0){
+ return c->operator;
+ }
+ c++;
+ i--;
+ }
+ return OPERATOR_ERROR;
+}
+
--- /dev/null
+#ifndef _TEXTUTIL_H_
+#define _TEXTUTIL_H_
+enum{
+ TEXT_MAXLINE = 0x100,
+ TEXT_MAXWORD = 10
+};
+int text_load(char *buf, int length, char **text);
+int word_load(char *buf, char **text);
+int value_get(const char *str, long *val);
+
+enum{
+ OPERATOR_PLUS,
+ OPERATOR_SHIFT_LEFT,
+ OPERATOR_SHIFT_RIGHT,
+ OPERATOR_AND,
+ OPERATOR_OR,
+ OPERATOR_XOR,
+ OPERATOR_ERROR,
+ OPERATOR_NONE,
+};
+
+int operator_get(char *str);
+#endif
--- /dev/null
+#ifndef _TYPE_H_
+#define _TYPE_H_
+#include <stdint.h>
+#include <stdbool.h>
+typedef uint8_t u8;
+enum{
+ OK = 0, NG
+};
+#endif
--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+command line interface, config file parser
+
+Copyright (C) 2008-2009 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "memory_manage.h"
+#include "type.h"
+#include "reader_master.h"
+#include "giveio.h"
+#include "file.h"
+#include "script.h"
+#include "header.h"
+#include "textutil.h"
+#include "config.h"
+#include "flashmemory.h"
+
+static int flag_get(const char *flag, struct st_config *c)
+{
+ while(*flag != '\0'){
+ switch(*flag){
+ case 'S': case 's':
+ c->backupram = CONFIG_OVERRIDE_TRUE;
+ break;
+ case 'H': case 'h':
+ c->mirror = MIRROR_HORIZONAL;
+ break;
+ case 'V': case 'v':
+ c->mirror = MIRROR_VERTICAL;
+ break;
+ case '_':
+ break;
+ case 'r':
+ c->syntaxtest = 1;
+ break;
+ default:
+ return NG;
+ }
+ flag++;
+ }
+ return OK;
+}
+//patch... for reader_hongkongfc.c
+extern int hongkong_flash_patch;
+static const char PREFIX_CONFIG_ERROR[] = "config error:";
+static int config_file_load(struct st_config *c)
+{
+ char *buf;
+ int size = 0;
+ c->reader = NULL;
+ buf = buf_load_full("unagi.cfg", &size);
+ if(buf == NULL){
+ printf("%s config file open error\n", PREFIX_CONFIG_ERROR);
+ return NG;
+ }
+ char **text;
+ text = Malloc(sizeof(char*) * TEXT_MAXLINE);
+ const int text_num = text_load(buf, size, text);
+ if(text_num == 0){
+ printf("%s script line too much\n", PREFIX_CONFIG_ERROR);
+ Free(buf);
+ Free(text);
+ return NG;
+ }
+ int i;
+ for(i=0; i<text_num; i++){
+ char *word[TEXT_MAXWORD];
+ word_load(text[i], word);
+ if(word[0][0] == '#'){
+ continue;
+ }
+ if(strcmp("DRIVER", word[0]) == 0){
+ c->reader = reader_driver_get(word[1]);
+ }else if(strcmp("HONGKONG_FLASH", word[0]) == 0){
+ hongkong_flash_patch = 0;
+ if(strcmp("0.5.3", word[1]) == 0){
+ hongkong_flash_patch = 1;
+ }
+ }else if((DEBUG == 1) && (strcmp("WRITE_WAIT", word[0]) == 0)){
+ if(value_get(word[1], &(c->write_wait)) == NG){
+ printf("%s write_wait parameter is illigal", PREFIX_CONFIG_ERROR);
+ Free(buf);
+ Free(text);
+ return NG;
+ }
+ }else if(strcmp("TEST_DEVICE", word[0]) == 0){
+ if(DEBUG == 1){
+ strncpy(c->flash_test_device, word[1], CONFIG_STR_LENGTH);
+ }
+ }else if(strcmp("TEST_MAPPER", word[0]) == 0){
+ if(DEBUG == 1){
+ strncpy(c->flash_test_mapper, word[1], CONFIG_STR_LENGTH);
+ }
+ }else{
+ printf("%s unknown config title %s", PREFIX_CONFIG_ERROR, word[1]);
+ Free(buf);
+ Free(text);
+ return NG;
+ }
+ }
+
+ Free(text);
+ if(c->reader == NULL){
+ printf("%s hardware not selected or not found\n", PREFIX_CONFIG_ERROR);
+ Free(buf);
+ return NG;
+ }
+ Free(buf);
+ return OK;
+}
+
+static int flash_pointer_init(const char *device, const struct flash_driver **f)
+{
+ *f = flash_driver_get(device);
+ if(*f == NULL){
+ printf("%s unknown flash device %s\n", PREFIX_CONFIG_ERROR, device);
+ return NG;
+ }
+ return OK;
+}
+
+enum{
+ ARGC_MODE = 1,
+ ARGC_SCRIPTFILE,
+ //DUMP MODE
+ ARGC_DUMP_OUT_NESFILE,
+ ARGC_DUMP_FLAG,
+ ARGC_DUMP_MAPPER,
+ //RAM RW MODE
+ ARGC_READ_OUT_RAMFILE = ARGC_DUMP_OUT_NESFILE,
+ ARGC_WRITE_IN_RAMFILE = ARGC_DUMP_OUT_NESFILE,
+ ARGC_RW_NUM,
+ //PROGRAM MODE
+ ARGC_PROGRAM_IN_NESFILE = ARGC_DUMP_OUT_NESFILE,
+ ARGC_PROGRAM_CPU_DEVICE,
+ ARGC_PROGRAM_PPU_DEVICE,
+ //TESTMODE
+ ARGC_TEST_OPTION = ARGC_SCRIPTFILE,
+ ARGC_TEST_FILE,
+ ARGC_TEST_NUM
+};
+
+static int config_init(const int argc, const char **argv, struct st_config *c)
+{
+ c->script = argv[ARGC_SCRIPTFILE];
+ c->romimage = NULL;
+ c->ramimage = NULL;
+ c->mapper = CONFIG_OVERRIDE_UNDEF;
+ c->mirror = CONFIG_OVERRIDE_UNDEF;
+ c->backupram = CONFIG_OVERRIDE_UNDEF;
+ c->mapper = CONFIG_OVERRIDE_UNDEF;
+ c->syntaxtest = 0;
+ c->cpu_flash_driver = &FLASH_DRIVER_UNDEF;
+ c->ppu_flash_driver = &FLASH_DRIVER_UNDEF;
+ c->write_wait = 0;
+ //mode ÊÌ target file ½é´ü²½
+ switch(argv[ARGC_MODE][0]){
+ case 'd':
+ c->mode = MODE_ROM_DUMP;
+ c->romimage = argv[ARGC_DUMP_OUT_NESFILE];
+ break;
+ case 'r':
+ c->mode = MODE_RAM_READ;
+ c->ramimage = argv[ARGC_READ_OUT_RAMFILE];
+ break;
+ case 'w':
+ c->mode = MODE_RAM_WRITE;
+ c->ramimage = argv[ARGC_WRITE_IN_RAMFILE];
+ break;
+ case 'f':
+ c->mode = MODE_ROM_PROGRAM;
+ c->romimage = argv[ARGC_PROGRAM_IN_NESFILE];
+ //ÍÆÎ̤¬¾¯¤Ê¤¤ ROM ¤ÎµÍ¤áÊý¤Î¥«¥¹¥¿¥Þ¥¤¥º
+ switch(argv[ARGC_MODE][1]){
+ case '\0':
+ c->transtype_cpu = VALUE_TRANSTYPE_TOP;
+ c->transtype_ppu = VALUE_TRANSTYPE_TOP;
+ break;
+ case 't':
+ c->transtype_cpu = VALUE_TRANSTYPE_TOP;
+ break;
+ case 'b':
+ c->transtype_cpu = VALUE_TRANSTYPE_BOTTOM;
+ break;
+ default:
+ printf("%s unkown flash trans mode cpu %c\n", PREFIX_CONFIG_ERROR, argv[ARGC_MODE][1]);
+ return NG;
+ }
+ if(argv[ARGC_MODE][1] == '\0'){
+ break;
+ }
+ switch(argv[ARGC_MODE][2]){
+ case '\0':
+ case 't':
+ c->transtype_ppu = VALUE_TRANSTYPE_TOP;
+ break;
+ case 'b':
+ c->transtype_ppu = VALUE_TRANSTYPE_BOTTOM;
+ break;
+ default:
+ printf("%s unkown flash trans mode ppu %c\n", PREFIX_CONFIG_ERROR, argv[ARGC_MODE][2]);
+ return NG;
+ }
+ break;
+ case 't':
+ if(DEBUG == 1){
+ c->mode = MODE_TEST;
+ break;
+ }
+ //²¼¤Ø
+ default:
+ printf("%s unkown mode %s\n", PREFIX_CONFIG_ERROR, argv[ARGC_MODE]);
+ return NG;
+ };
+ if(config_file_load(c) == NG){
+ return NG;
+ }
+ /*mode ÊÌ argc check.
+ DEBUG==0 argc: 4,5,6
+ DEBUG==1 argc: 3,4,5,6
+ */
+ switch(c->mode){
+ case MODE_ROM_DUMP:{
+ int flag_error = OK, mapper_error = OK;
+ switch(argc){
+ case 3:
+ return NG;
+ case 5:
+ flag_error = flag_get(argv[ARGC_DUMP_FLAG], c);
+ break;
+ case 6:
+ flag_error = flag_get(argv[ARGC_DUMP_FLAG], c);
+ mapper_error = value_get(argv[ARGC_DUMP_MAPPER], &c->mapper);
+ break;
+ }
+ if(flag_error != OK){
+ printf("%s unknown flag %s\n", PREFIX_CONFIG_ERROR, argv[ARGC_DUMP_FLAG]);
+ return NG;
+ }
+ if(mapper_error != OK){
+ printf("%s unknown mapper %s\n", PREFIX_CONFIG_ERROR, argv[ARGC_DUMP_MAPPER]);
+ return NG;
+ }
+ }break;
+ case MODE_RAM_READ:
+ case MODE_RAM_WRITE:
+ if(argc != ARGC_RW_NUM){
+ printf("%s too many argument\n", PREFIX_CONFIG_ERROR);
+ return NG;
+ }
+ break;
+ case MODE_ROM_PROGRAM:
+ if(c->reader->flash_support == false){
+ puts("this reader is not supported flash memory programming mode");
+ return NG;
+ }
+ switch(argc){
+ case 3:
+ case 4:
+ printf("%s few argument\n", PREFIX_CONFIG_ERROR);
+ return NG;
+ case 5:
+ if(flash_pointer_init(argv[ARGC_PROGRAM_CPU_DEVICE], &(c->cpu_flash_driver)) == NG){
+ return NG;
+ }
+ break;
+ case 6:
+ if(flash_pointer_init(argv[ARGC_PROGRAM_CPU_DEVICE], &(c->cpu_flash_driver)) == NG){
+ return NG;
+ }
+ if(flash_pointer_init(argv[ARGC_PROGRAM_PPU_DEVICE], &(c->ppu_flash_driver)) == NG){
+ return NG;
+ }
+ break;
+ }
+ break;
+ }
+
+ return OK;
+}
+
+#include "version.h"
+int main(int c, char **v)
+{
+ struct st_config config;
+ int config_result = NG;
+ mm_init();
+ switch(c){
+ case 3: //t testmode target
+ if(DEBUG == 0){
+ goto usage;
+ }
+ //²¼¤Ø
+ case 4: //mode script target
+ case 5:
+ //mode script target flag
+ //mode script target cpu_flash_device
+ case 6:
+ //mode script target flag mapper
+ //mode script target cpu_flash_device ppu_flash_device
+ config_result = config_init(c, (const char **) v, &config);
+ break;
+ usage:
+ default:
+ printf("famicom ROM cartridge utility - unagi version %s\n", STR_VERSION);
+ printf("%s [mode] [mapper script] [target file] [flag]\n", v[0]);
+ printf("mode - [d]ump ROM / [r]ead RAM/ [w]rite RAM/ [f]lash memory program\n");
+ break;
+ }
+ if((config.mode != MODE_TEST) && (config_result == OK)){
+ script_load(&config);
+ }
+ mm_end();
+ return 0;
+}
--- /dev/null
+UNAGI ICON "unagi.ico"
--- /dev/null
+famicom ROM cartridge utility - unagi
+client version 0.6.x
+by 鰻開発協同組合
+公式サイト http://unagi.sourceforge.jp/
+
+--はじめに--
+famicom ROM cartridge のデータ転送を行います。 ハードウェアは国内で有
+名な2種類に対応しています。
+
+--特徴--
+他の読み出しプログラムではマッパ別の対応はプログラムに内蔵されており、
+未対応のマッパの追加ができるのはプログラマだけでした。unagi ではマッパ
+対応をスクリプトに記載することによってユーザーが追加することができます。
+バンク切り替えの仕様をしることによって技術的な興味がわくかもしれません。
+
+コマンドラインでの無味乾燥なインタフェースによりビギナーお断りとなって
+おります。
+
+--動作環境--
+パラレルポートと読み出しハードを接続した Windows 環境
+* Windows XP にて動作確認しています。たぶん Win95 までなら大丈夫。
+* パラレルポートアドレスは 0x0378 固定です。USB 接続のものは使えるか分
+ かりません。
+USBと読み出しハードを接続した Windows 環境
+GIVEIO.SYS をインストールした環境
+* パッケージには含まれていませんので別途用意してください。
+
+cmd.exe, rxvt などのコマンドラインシェル
+
+--ハードウェアの選択--
+クライアントについている unagi.cfg をテキストエディタで編集して使用す
+るハードを選んでください。行頭に # がついているものは無視されます。
+
+== hongkong fc での問題 ==
+キャラクタROM/RAM 判定の PPU_RAMFIND が正しく動作しない場合やキャラク
+タROM領域の書き込みが安定しない場合はコメントを外して試してみてくださ
+い。根本的な対処方法は不明です。
+
+--コマンドライン引数--
+unagi.exe [mode] [script file] [target file] ...
+== d ROM DUMP MODE ==
+ROM イメージを作成します。
+unagi.exe d [script file] [dump file] [flag] [mapper]
+script file - 対応するマッパの ROM スクリプトファイルを指定します。
+dump file - 出力する ROM イメージファイルを指定します。
+以下は、通常は必要ありません。
+flag - 出力するヘッダを設定します。複数の場合はスペースをいれずに 記述します。
+ S カートリッジに backup RAM がついている場合
+ V スクリプトの設定を無視して mirroring を Vertical にする
+ H スクリプトの設定を無視して mirroring を Horizonal にする
+ _ mapper変更だけを適用する場合
+mapper - スクリプトの設定を無視してマッパ番号を設定します。
+
+== r RAM READ MODE ==
+バックアップ RAM イメージを PC 上に作成します。
+unagi.exe r [script file] [dump file]
+script file - 対応するマッパの RAM スクリプトファイルを指定します。
+dump file - 出力する RAM イメージファイルを指定します。
+
+== w RAM WRITE MODE ==
+バックアップ RAM イメージをカートリッジへ転送します。
+unagi.exe w [script file] [ram file]
+script file - 対応するマッパの RAM スクリプトファイルを指定します。
+ram file - 入力する RAM イメージファイルを指定します。
+
+== f flashmemory/SRAM PROGRAM MODE ==
+カートリッジ上の ROM を flashmemory か SRAM に交換した上で、ROM イメー
+ジデータを代替デバイスに転送するモードです。制限は多いですが、一応動作
+実績があります。
+
+--スクリプト仕様--
+ROM dump script パッケージの syntax.txt を参照してください。
+
+--ライセンス--
+unagi クライアントのバイナリとソースコード(例外有り)は下記が適用されま
+す。unagi スクリプトは naruko が作成したものは下記が適用されます。
+GNU General Public License v2
+
+例外物
+- GIVEIO.SYSアクセスライブラリに含まれる giveio.c, giveio.h
+えふ・ぴー・じー・えー・ぱーく管理人の「さとう」さんのご厚意によりソー
+スコードも配布ソースに含めてよい許可をいただいております。二次配布など
+の取り扱いはさとうさんの許可を得てください。
+
+- GIVEIO.SYS
+配布パッケージにも含めませんし、作者が誰なのかもわからないのでパッケー
+ジに含めないでください。
+
+- client_test.c
+実験的なソースが入っているのと、なくても RELEASE ビルドは可能なこと、
+無断転用でのトラブルを防ぐために非公開にしました。個別に要望があれば
+ソースは公開します。
+
+--謝辞--
+* 資料提供をしてくれた color さん, VirtuaNES のソース, nesdev
+* GIVEIO.SYSアクセスライブラリのさとうさん
+* ハードウェアを貸してくれたカシオン
+* アイコンを描いてくれたひろひろきさん
+* プログラミング環境の mingw と rxvt
+* 各種実験に協力してくださっているばくてんさん
+
+--使用ライブラリ--
+[LibUSB-Win32]
+Copyright (c) 2002-2004 Stephan Meyer, <ste_meyer@web.de>
+Copyright (c) 2000-2004 Johannes Erdfelt, <johannes@erdfelt.com>
+Copyright (c) Thomas Sailer, <sailer@ife.ee.ethz.ch>
+[opendevice.c] (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
--- /dev/null
+/* Name: opendevice.c -> renamed as usb_device.[ch]
+ * Project: V-USB host-side library
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-10
+ * Tabsize: 4
+ * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
+ * This Revision: $Id: opendevice.c 740 2009-04-13 18:23:31Z cs $
+ */
+#include <stdio.h>
+#include "usb_device.h"
+
+enum{
+ MATCH_SUCCESS = 1,
+ MATCH_FAILED = 0,
+ MATCH_ABORT = -1
+};
+/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */
+static int _shellStyleMatch(char *text, char *p)
+{
+ int last, matched, reverse;
+
+ for(; *p; text++, p++){
+ if(*text == 0 && *p != '*')
+ return MATCH_ABORT;
+ switch(*p){
+ case '\\':
+ /* Literal match with following character. */
+ p++;
+ /* FALLTHROUGH */
+ default:
+ if(*text != *p)
+ return MATCH_FAILED;
+ continue;
+ case '?':
+ /* Match anything. */
+ continue;
+ case '*':
+ while(*++p == '*')
+ /* Consecutive stars act just like one. */
+ continue;
+ if(*p == 0)
+ /* Trailing star matches everything. */
+ return MATCH_SUCCESS;
+ while(*text)
+ if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED)
+ return matched;
+ return MATCH_ABORT;
+ case '[':
+ reverse = p[1] == '^';
+ if(reverse) /* Inverted character class. */
+ p++;
+ matched = MATCH_FAILED;
+ if(p[1] == ']' || p[1] == '-')
+ if(*++p == *text)
+ matched = MATCH_SUCCESS;
+ for(last = *p; *++p && *p != ']'; last = *p)
+ if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
+ matched = MATCH_SUCCESS;
+ if(matched == reverse)
+ return MATCH_FAILED;
+ continue;
+ }
+ }
+ return *text == 0;
+}
+
+/* public interface for shell style matching: returns 0 if fails, 1 if matches */
+static int shellStyleMatch(char *text, char *pattern)
+{
+ if(pattern == NULL) /* NULL pattern is synonymous to "*" */
+ return 1;
+ return _shellStyleMatch(text, pattern) == MATCH_SUCCESS;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen)
+{
+char buffer[256];
+int rval, i;
+
+ if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
+ return rval;
+ if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0)
+ return rval;
+ if(buffer[1] != USB_DT_STRING){
+ *buf = 0;
+ return 0;
+ }
+ if((unsigned char)buffer[0] < rval)
+ rval = (unsigned char)buffer[0];
+ rval /= 2;
+ /* lossy conversion to ISO Latin1: */
+ for(i=1;i<rval;i++){
+ if(i > buflen) /* destination buffer overflow */
+ break;
+ buf[i-1] = buffer[2 * i];
+ if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
+ buf[i-1] = '?';
+ }
+ buf[i-1] = 0;
+ return i-1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int usbOpenDevice(
+ usb_dev_handle **device, int vendorID, char *vendorNamePattern,
+ int productID, char *productNamePattern,
+ char *serialNamePattern, FILE *printMatchingDevicesFp,
+ FILE *warningsFp
+)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ usb_dev_handle *handle = NULL;
+ int errorCode = USBOPEN_ERR_NOTFOUND;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ for(bus = usb_get_busses(); bus; bus = bus->next){
+ for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */
+ if((vendorID == 0 || dev->descriptor.idVendor == vendorID)
+ && (productID == 0 || dev->descriptor.idProduct == productID)){
+ char vendor[256], product[256], serial[256];
+ int len;
+ handle = usb_open(dev); /* we need to open the device in order to query strings */
+ if(!handle){
+ errorCode = USBOPEN_ERR_ACCESS;
+ if(warningsFp != NULL)
+ fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
+ continue;
+ }
+ /* now check whether the names match: */
+ len = vendor[0] = 0;
+ if(dev->descriptor.iManufacturer > 0){
+ len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor));
+ }
+ if(len < 0){
+ errorCode = USBOPEN_ERR_ACCESS;
+ if(warningsFp != NULL)
+ fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
+ }else{
+ errorCode = USBOPEN_ERR_NOTFOUND;
+ /* printf("seen device from vendor ->%s<-\n", vendor); */
+ if(shellStyleMatch(vendor, vendorNamePattern)){
+ len = product[0] = 0;
+ if(dev->descriptor.iProduct > 0){
+ len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product));
+ }
+ if(len < 0){
+ errorCode = USBOPEN_ERR_ACCESS;
+ if(warningsFp != NULL)
+ fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
+ }else{
+ errorCode = USBOPEN_ERR_NOTFOUND;
+ /* printf("seen product ->%s<-\n", product); */
+ if(shellStyleMatch(product, productNamePattern)){
+ len = serial[0] = 0;
+ if(dev->descriptor.iSerialNumber > 0){
+ len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial));
+ }
+ if(len < 0){
+ errorCode = USBOPEN_ERR_ACCESS;
+ if(warningsFp != NULL)
+ fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
+ }
+ if(shellStyleMatch(serial, serialNamePattern)){
+ if(printMatchingDevicesFp != NULL){
+ if(serial[0] == 0){
+ fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product);
+ }else{
+ fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial);
+ }
+ }else{
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ usb_close(handle);
+ handle = NULL;
+ }
+ }
+ if(handle) /* we have found a deice */
+ break;
+ }
+ if(handle != NULL){
+ errorCode = 0;
+ *device = handle;
+ }
+ if(printMatchingDevicesFp != NULL) /* never return an error for listing only */
+ errorCode = 0;
+ return errorCode;
+}
+
--- /dev/null
+/* Name: opendevice.h
+ * Project: V-USB host-side library
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-10
+ * Tabsize: 4
+ * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
+ * This Revision: $Id: opendevice.h 755 2009-08-03 17:01:21Z cs $
+ */
+
+/*
+General Description:
+This module offers additional functionality for host side drivers based on
+libusb or libusb-win32. It includes a function to find and open a device
+based on numeric IDs and textual description. It also includes a function to
+obtain textual descriptions from a device.
+
+To use this functionality, simply copy opendevice.c and opendevice.h into your
+project and add them to your Makefile. You may modify and redistribute these
+files according to the GNU General Public License (GPL) version 2 or 3.
+*/
+
+#ifndef __OPENDEVICE_H_INCLUDED__
+#define __OPENDEVICE_H_INCLUDED__
+
+#include <usb.h> /* this is libusb, see http://libusb.sourceforge.net/ */
+#include <stdio.h>
+
+int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen);
+/* This function gets a string descriptor from the device. 'index' is the
+ * string descriptor index. The string is returned in ISO Latin 1 encoding in
+ * 'buf' and it is terminated with a 0-character. The buffer size must be
+ * passed in 'buflen' to prevent buffer overflows. A libusb device handle
+ * must be given in 'dev'.
+ * Returns: The length of the string (excluding the terminating 0) or
+ * a negative number in case of an error. If there was an error, use
+ * usb_strerror() to obtain the error message.
+ */
+
+int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp);
+/* This function iterates over all devices on all USB busses and searches for
+ * a device. Matching is done first by means of Vendor- and Product-ID (passed
+ * in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard).
+ * When a device matches by its IDs, matching by names is performed. Name
+ * matching can be done on textual vendor name ('vendorNamePattern'), product
+ * name ('productNamePattern') and serial number ('serialNamePattern'). A
+ * device matches only if all non-null pattern match. If you don't care about
+ * a string, pass NULL for the pattern. Patterns are Unix shell style pattern:
+ * '*' stands for 0 or more characters, '?' for one single character, a list
+ * of characters in square brackets for a single character from the list
+ * (dashes are allowed to specify a range) and if the lis of characters begins
+ * with a caret ('^'), it matches one character which is NOT in the list.
+ * Other parameters to the function: If 'warningsFp' is not NULL, warning
+ * messages are printed to this file descriptor with fprintf(). If
+ * 'printMatchingDevicesFp' is not NULL, no device is opened but matching
+ * devices are printed to the given file descriptor with fprintf().
+ * If a device is opened, the resulting USB handle is stored in '*device'. A
+ * pointer to a "usb_dev_handle *" type variable must be passed here.
+ * Returns: 0 on success, an error code (see defines below) on failure.
+ */
+
+/* usbOpenDevice() error codes: */
+#define USBOPEN_SUCCESS 0 /* no error */
+#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */
+#define USBOPEN_ERR_IO 2 /* I/O error */
+#define USBOPEN_ERR_NOTFOUND 3 /* device not found */
+
+
+/* Obdev's free USB IDs, see USB-IDs-for-free.txt for details */
+
+#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */
+#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */
+#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */
+#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */
+#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */
+
+#endif /* __OPENDEVICE_H_INCLUDED__ */
--- /dev/null
+//include from unagi.c only
+static const char STR_VERSION[] = "0.6.1 "
+#if DEBUG==1
+"debug "
+#else
+"release "
+#endif
+"build";