famicom ROM cartridge utility - unagi
script engine
-Copyright (C) 2008 sato_tiff
+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
enum{
SETTING, DUMP, END
};
-static int command_mask(const int region, const long address, const long offset, long size, long *data)
+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_CPU);
+ 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_CPU);
+ printf("%s %s_COMMAND area mask error\n", LOGICAL_ERROR_PREFIX, str_region);
return NG;
}
break;
case 0x1000: case 0x1400: case 0x1800: case 0x1c00:
break;
default:
- printf("%s %s_COMMAND area offset error\n", LOGICAL_ERROR_PREFIX, STR_REGION_CPU);
+ 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_CPU);
+ 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: case 0x2aaa: case 0x5555:
+ 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:
- assert(0); //unknown command address
+ printf("%s %s_COMMAND unknown commnand address\n", LOGICAL_ERROR_PREFIX, str_region);
+ return NG;
}
- long mask = size - 1;
- *data = (address & mask) | offset;
return OK;
}
}
break;
case MODE_ROM_PROGRAM:
+ assert(c->cpu_flash_driver->write != 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)== NG){
}
//flash memory capacity check
//¤¤¤Þ¤Î¤È¤³¤í == ¤Ë¤·¤Æ¾®¤µ¤¤ÍÆÎ̤⤽¤Î¤¦¤ÁÂбþ
- else if((c->mode == MODE_ROM_PROGRAM) && (size != c->cpu_flash_driver->capacity)){
+ else if((c->mode == MODE_ROM_PROGRAM) && (size > c->cpu_flash_driver->capacity)){
printf("%s flash memory capacity error\n", LOGICAL_ERROR_PREFIX);
error += 1;
}
//memory size ¤Ï̤³ÎÄêÍ×ÁǤ¬Â¿¤¤¤Î¤Ç check ¤òÈ´¤¯
r->cpu_ram.size = s->value[0];
break;
- case SCRIPT_OPCODE_CPU_COMMAND_0000:
- if(command_mask(MEMORY_AREA_CPU_ROM, 0, s->value[0], s->value[1], &(r->cpu_flash.command_0000)) == NG){
- error += 1;
- }
- break;
- case SCRIPT_OPCODE_CPU_COMMAND_2AAA:
- if(command_mask(MEMORY_AREA_CPU_ROM, 0x2aaa, s->value[0], s->value[1], &(r->cpu_flash.command_2aaa)) == NG){
- error += 1;
- }
- break;
- case SCRIPT_OPCODE_CPU_COMMAND_5555:
- if(command_mask(MEMORY_AREA_CPU_ROM, 0x5555, s->value[0], s->value[1], &(r->cpu_flash.command_5555)) == NG){
+ 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;
printf("%s %s length error\n", LOGICAL_ERROR_PREFIX, OPSTR_PPU_ROMSIZE);
error += 1;
}
- }
- break;
- case SCRIPT_OPCODE_PPU_COMMAND_0000:
- if(command_mask(MEMORY_AREA_PPU, 0, s->value[0], s->value[1], &(r->ppu_flash.command_0000)) == NG){
+ else if((c->mode == MODE_ROM_PROGRAM) && (size > c->ppu_flash_driver->capacity)){
+ printf("%s flash memory capacity error\n", LOGICAL_ERROR_PREFIX);
error += 1;
}
- break;
- case SCRIPT_OPCODE_PPU_COMMAND_2AAA:
- if(command_mask(MEMORY_AREA_PPU, 0x2aaa, s->value[0], s->value[1], &(r->ppu_flash.command_2aaa)) == NG){
- error += 1;
}
break;
- case SCRIPT_OPCODE_PPU_COMMAND_5555:
- if(command_mask(MEMORY_AREA_PPU, 0x5555, s->value[0], s->value[1], &(r->ppu_flash.command_5555)) == NG){
+ 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;
setting = DUMP;
}
break;
- case SCRIPT_OPCODE_PPU_RAMTEST:
+ case SCRIPT_OPCODE_PPU_RAMFIND:
//¥ë¡¼¥×ÆâÉô¤ËÆþ¤Ã¤Æ¤¿¤é¥¨¥é¡¼
if(variable_num != 0){
printf("%s PPU_RAMTEST must use outside loop\n", 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 ¤òÍÆǧ¤¹¤ë
- if(!is_range(length, 0, 0x2000)){
+ long min = 0;
+ if(s->opcode == SCRIPT_OPCODE_PPU_SRAMTEST){
+ min = 1;
+ }
+ if(!is_range(length, min, 0x2000)){
logical_print_illgallength(STR_REGION_PPU, length);
error += 1;
}
error += 1;
}
//dump length update
- if(is_region_ppurom(address)){
+ if((s->opcode == SCRIPT_OPCODE_PPU_READ) && is_region_ppurom(address)){
ppu_romsize += length;
}
setting = DUMP;
setting = 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);
+ //length filter.
+ if(!is_range(length, 0x80, 0x1000)){
+ logical_print_illgallength(STR_REGION_PPU, length);
+ error += 1;
+ }
+ //address filter
+ else if(!is_region_ppurom(address)){
+ logical_print_illgalarea(STR_REGION_PPU, address);
+ error += 1;
+ }else if(end >= 0x2000){
+ logical_print_overdump(STR_REGION_PPU, address, end);
+ error += 1;
+ }
+ ppu_romsize += length;
+ setting = DUMP;
+ }
+ break;
case SCRIPT_OPCODE_STEP_START:{
int i;
{
enum {PPU_TEST_RAM, PPU_TEST_ROM};
const u8 PPU_TEST_DATA[] = "PPU_TEST_DATA";
-#if DEBUG==0
-static
-#endif
-int ppu_ramtest(const struct reader_driver *d)
+static int ppu_ramfind(const struct reader_driver *d)
{
const int length = sizeof(PPU_TEST_DATA);
const long testaddr = 123;
return PPU_TEST_ROM;
}
+static int ramtest(const struct reader_driver *d, long address, long length, u8 *writedata, u8 *testdata, const long filldata)
+{
+ long i = length;
+ long a = address;
+ while(i != 0){
+ d->ppu_write(a, filldata);
+ a++;
+ i--;
+ }
+ d->ppu_read(address, length, testdata);
+ memset(writedata, filldata, length);
+ if(memcmp(writedata, testdata, length) == 0){
+ return 0;
+ }
+ return 1;
+}
+
+static const long SRAMTESTDATA[] = {0xff, 0xaa, 0x55, 0x00};
+static int ppu_sramtest(const struct reader_driver *d, long address, long length)
+{
+ u8 *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(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){
fflush(stdout);
}
+static void execute_program_begin(const struct memory *m)
+{
+ if(0){ //DEBUG==1){
+ return;
+ }
+ printf("writing %s area 0x%06x ... ", m->name, m->offset);
+ fflush(stdout);
+}
+
+//memcmp ¤ÎÌá¤êÃͤ¬Æþ¤ë¤Î¤Ç 0 ¤¬Àµ¾ï
+static void execute_program_finish(int result)
+{
+ const char *str;
+ str = "NG";
+ if(result == 0){
+ str = "OK";
+ }
+ printf("%s\n", str);
+ fflush(stdout);
+}
const char EXECUTE_ERROR_PREFIX[] = "execute error:";
-static void execute_cpu_ramrw(const struct reader_driver *d, const struct memory *ram, int mode, long address, long length)
+static void execute_cpu_ramrw(const struct reader_driver *d, const struct memory *ram, int mode, long address, long length, long wait)
{
if(mode == MODE_RAM_WRITE){
const u8 *writedata;
long l = length;
writedata = ram->data;
while(l != 0){
- d->cpu_6502_write(a++, *writedata);
+ d->cpu_6502_write(a++, *writedata, wait);
writedata += 1;
l--;
}
d->open_or_close(READER_CLOSE);
return NG;
}
+ u8 *program_compare;
+ program_compare = NULL;
+ if(c->mode == MODE_ROM_PROGRAM){
+ //device ¤è¤Ã¤Æ¤Ï erase
+ c->cpu_flash_driver->init(&(r->cpu_flash));
+ if(r->ppu_rom.size != 0){
+ c->ppu_flash_driver->init(&(r->ppu_flash));
+ }
+ printf("flashmemory/SRAM program mode. you can abort programming 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;
case SCRIPT_OPCODE_CPU_WRITE:{
long data;
expression_calc(&s->expression, &data);
- d->cpu_6502_write(s->value[0], data);
+ d->cpu_6502_write(s->value[0], data, c->write_wait);
}
break;
case SCRIPT_OPCODE_CPU_RAMRW:{
const long length = s->value[1];
- execute_cpu_ramrw(d, &cpu_ram, c->mode, s->value[0], length);
+ execute_cpu_ramrw(d, &cpu_ram, c->mode, s->value[0], length, c->write_wait);
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;
+ }
const long address = s->value[0];
const long length = s->value[1];
+ execute_program_begin(&cpu_rom);
c->cpu_flash_driver->write(
&(r->cpu_flash),
address, length,
- cpu_rom.data
+ &cpu_rom
);
+ d->cpu_read(address, length, program_compare);
+ const int result = memcmp(program_compare, cpu_rom.data, length);
+ execute_program_finish(result);
cpu_rom.data += length;
cpu_rom.offset += length;
+
+ if((DEBUG==0) && (result != 0)){
+ end = 0;
+ }
}
break;
- case SCRIPT_OPCODE_PPU_RAMTEST:
- if(ppu_ramtest(d) == PPU_TEST_RAM){
- printf("PPU_RAMTEST: charcter RAM found\n");
+ case SCRIPT_OPCODE_PPU_RAMFIND:
+ if(ppu_ramfind(d) == PPU_TEST_RAM){
+ printf("PPU_RAMFIND: charcter RAM found\n");
r->ppu_rom.size = 0;
end = 0;
}
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(ppu_sramtest(d, address, length) == 0){
+ printf("ok\n");
+ }else{
+ printf("ng\n");
+ //end = 0;
+ }
+ }break;
case SCRIPT_OPCODE_PPU_READ:{
const long address = s->value[0];
const long length = s->value[1];
d->ppu_write(s->value[0], data);
}
break;
+ case SCRIPT_OPCODE_PPU_PROGRAM:{
+ if(c->ppu_flash_driver->id_device == FLASH_ID_DEVICE_DUMMY){
+ break;
+ }
+ const long address = s->value[0];
+ const long length = s->value[1];
+ execute_program_begin(&ppu_rom);
+ c->ppu_flash_driver->write(
+ &(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)){
+ end = 0;
+ }
+ }
+ break;
case SCRIPT_OPCODE_STEP_START:
//¥ë¡¼¥×¤ÎÌá¤êÀè¤Ï¤³¤ÎÌ¿Îá¤Î¼¡¤Ê¤Î¤Ç &s[1]
step_new(s->variable, s->value[1], s->value[2], s->value[3], &s[1]);
}
}
d->open_or_close(READER_CLOSE);
+ if(program_compare != NULL){
+ free(program_compare);
+ }
return OK;
}
.size = 0, .offset = 0,
.data = NULL,
.attribute = MEMORY_ATTR_NOTUSE,
- .name = STR_REGION_CPU
+ .name = "program ROM"
},
.ppu_rom = {
.size = 0, .offset = 0,
.data = NULL,
.attribute = MEMORY_ATTR_NOTUSE,
- .name = STR_REGION_PPU
+ .name = "charcter ROM"
},
.cpu_ram = {
.size = 0, .offset = 0,
.command_0000 = 0,
.command_2aaa = 0,
.command_5555 = 0,
+ .pagesize = c->cpu_flash_driver->pagesize,
.flash_write = c->reader->cpu_flash_write,
.read = c->reader->cpu_read
},
.command_0000 = 0,
.command_2aaa = 0,
.command_5555 = 0,
+ .pagesize = c->ppu_flash_driver->pagesize,
.flash_write = c->reader->ppu_write,
.read = c->reader->ppu_read
},