famicom ROM cartridge utility - unagi
flash memory driver
-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
#include <string.h>
#include <windows.h>
#include "type.h"
+#include "header.h"
#include "flashmemory.h"
/*
driver for Winbond W29C020, W49F002
{ADDRESS_5555, 0x20},
{FLASH_COMMAND_END, 0}
};
-static const struct flash_task ERASE[] = {
+static const struct flash_task ERASE_CHIP[] = {
{ADDRESS_5555, 0xaa},
{ADDRESS_2AAA, 0x55},
{ADDRESS_5555, 0x80},
{FLASH_COMMAND_END, 0}
};
+static const struct flash_task ERASE_SECTOR[] = {
+ {ADDRESS_5555, 0xaa},
+ {ADDRESS_2AAA, 0x55},
+ {ADDRESS_5555, 0x80},
+ {ADDRESS_5555, 0xaa},
+ {ADDRESS_2AAA, 0x55},
+ //¤³¤Î¤¢¤È sectoraddress ¤Ë 0x30 ¤ò write
+ {FLASH_COMMAND_END, 0}
+};
+
static const struct flash_task PP[] = {
{ADDRESS_5555, 0xaa},
{ADDRESS_2AAA, 0x55},
/*
---- product ID check ----
*/
+#define dprintf if(DEBUG==1) printf
static int productid_check(const struct flash_order *d, const struct flash_driver *f)
{
u8 data[3];
return OK;
}
+static int productid_sram(const struct flash_order *d, const struct flash_driver *f)
+{
+ return OK;
+}
/*
---- toggle check ----
databit6
*/
const int CHECK_RETRY_MAX = 0x10000;
-static int toggle_check(const struct flash_order *d, long address)
+static int toggle_check_d6(const struct flash_order *d, long address)
{
u8 predata;
int retry = 0;
return NG;
}
+static int toggle_check_d2d5d6(const struct flash_order *d, long address)
+{
+ u8 predata;
+ int retry = 0;
+ d->read(address, 1, &predata);
+ predata &= 0x40;
+ do{
+ u8 data;
+ d->read(address, 1, &data);
+ //DQ6 toggle check
+ if(predata == (data & 0x40)){
+ return OK;
+ }
+ //DQ5 == 0 ¤Ê¤é¤ä¤ê¤Ê¤ª¤·
+ if(data & 0x20){
+ //recheck toggle bit, read twice
+ u8 t[2];
+ d->read(address, 1, &t[0]);
+ d->read(address, 1, &t[1]);
+ if((t[0] & 0x40) == (t[1] & 0x40)){
+ return OK;
+ }
+ //Program/Erase operation not complete, write reset command.
+ return NG;
+ }
+ if((retry & 0x0f) == 0){
+ dprintf("toggle out %06x \n", (int) address);
+ }
+ retry++;
+ }while(retry < CHECK_RETRY_MAX);
+ return NG;
+}
+
/*
---- polling check ----
databit7
*/
-static int polling_check(const struct flash_order *d, long address, u8 truedata)
+static int polling_check_d7(const struct flash_order *d, long address, u8 truedata)
{
int retry = 0;
return NG;
}
-static void bootblock_lockout(const struct flash_order *d)
+static int polling_check_d5d7(const struct flash_order *d, long address, u8 truedata)
{
- u8 dummy[3];
- command_set(d, PP);
- d->read(0x8000 ,3, dummy);
- printf("%02x %02x %02x \n", dummy[0], dummy[1], dummy[2]);
- d->read(0xfff2 ,1, dummy);
- command_set(d, PRODUCTID_EXIT);
+ int retry = 0;
+
+ truedata &= 0x80;
+ do{
+ u8 data;
+ d->read(address, 1, &data);
+ if(truedata == (data & 0x80)){
+ return OK;
+ }
+ if(data & 0x20){
+ d->read(address, 1, &data);
+ if(truedata == (data & 0x80)){
+ return OK;
+ }
+ dprintf("%s error", __FUNCTION__);
+ return NG;
+ }
+ retry++;
+ }while(retry < CHECK_RETRY_MAX);
+ return NG;
}
/*
---- erase ----
*/
-static void flash_erase(const struct flash_order *d)
+static void flash_erase_chip_2aaa(const struct flash_order *d)
{
- if(0) bootblock_lockout(d);
- command_set(d, ERASE);
- toggle_check(d, d->command_2aaa);
+ command_set(d, ERASE_CHIP);
+ toggle_check_d6(d, d->command_2aaa);
Sleep(200); //Tec 0.2 sec
}
+static void flash_erase_chip_02aa(const struct flash_order *d)
+{
+ u8 data;
+ d->read(d->command_2aaa, 1, &data);
+ command_set(d, ERASE_CHIP);
+ if(0){
+ toggle_check_d2d5d6(d, d->command_2aaa);
+
+ }else{
+ polling_check_d5d7(d, d->command_2aaa, data);
+ }
+ Sleep(8000); //chip erase time 8sec, max64sec
+}
+
+#if DEBUG==1
+static void sram_erase(const struct flash_order *d)
+{
+ //bank ÀÚ¤êÂؤ¨¤¬È¼¤¦¤Î¤Ç¼ÂÁõ¤Ç¤¤Ê¤¤
+}
+#endif
+
/*
---- program ----
*/
static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
{
+ int retry = 0;
while(length != 0){
if(*data != 0xff){
- u8 dummy;
- d->read(address, 1, &dummy);
- if(*data != dummy){
- printf("%s %06x\n", __FUNCTION__, (int) address);
- fflush(stdout);
- command_set(d, PROTECT_DISABLE);
- d->flash_write(address, *data);
- if(toggle_check(d, address) == NG){
- if(DEBUG == 1){
- printf("%s NG\n", __FUNCTION__);
- }
- return NG;
- }
- Sleep(1);
+ fflush(stdout);
+ command_set(d, PROTECT_DISABLE);
+ d->flash_write(address, *data);
+ if(toggle_check_d6(d, address) == NG){
+ dprintf("%s NG\n", __FUNCTION__);
+ return NG;
}
}
- address++;
- data++;
- length--;
+ u8 dummy;
+ d->read(address, 1, &dummy);
+ if(*data == dummy){
+ address++;
+ data++;
+ length--;
+ retry = 0;
+ }else if(retry > 8){
+ dprintf("%s %06x error\n", __FUNCTION__, (int) address);
+ address++;
+ data++;
+ length--;
+ retry = 0;
+ if(DEBUG == 0){
+ return NG;
+ }
+ }else{
+ retry++;
+ }
}
return OK;
}
static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
{
- const long toggle_address = address;
+ const long toggle_address = address ;
command_set(d, PROTECT_DISABLE);
while(length != 0){
d->flash_write(address, *data);
data++;
length--;
}
- Sleep(15);
- int ret = toggle_check(d, toggle_address);
+ int ret = toggle_check_d6(d, toggle_address);
if(0){
data--;
- address -= 1;
- polling_check(d, address - 1, *data);
+ polling_check_d7(d, address - 1, *data);
}
- //command_set(d, PROTECT_ENABLE);
- //Sleep(15);
return ret;
}
/*
----- block compare ----
-*/
-static void compare(const struct flash_order *d, long address, const u8 *data, long length)
-{
- u8 *romdata, *r;
- int count = 0;
- romdata = malloc(length);
- d->read(address, length, romdata);
- r = romdata;
- while(length != 0){
- if(*r != *data){
- char safix = ' ';
- if((count & 7) == 7){
- safix = '\n';
- }
- count++;
- printf("%06x%c", (int)address, safix);
- }
- r++;
- data++;
- address++;
- length--;
- }
- free(romdata);
-}
-
-/*
¸ÇͥǥХ¤¥¹¥É¥é¥¤¥Ð
*/
static void w49f002_init(const struct flash_order *d)
byte program mode ¤Ç¤Ï 1->0 ¤Ë¤¹¤ë¤À¤±¡£ 0->1 ¤Ï erase ¤Î¤ß¡£
¤è¤Ã¤Æ½é´ü²½»þ¤Ë¤Ï erase ¤ò¼Â¹Ô¤¹¤ë
*/
- flash_erase(d);
+ flash_erase_chip_2aaa(d);
}
-static void w49f002_write(const struct flash_order *d, long address, long length, const u8 *data)
+static void w49f002_write(const struct flash_order *d, long address, long length, const struct memory *m)
{
- int writemiss = 0;
- int retry = 0;
- u8 *compare;
- compare = malloc(length);
- do{
- if(program_byte(d, address, data, length) == NG){
- break;
- }
- d->read(address, length, compare);
- writemiss = memcmp(compare, data, length);
- if(retry > 20){
- printf("%s retry error\n", __FUNCTION__);
- break;
- }
- retry++;
- }while(writemiss != 0);
- free(compare);
+ program_byte(d, address, m->data, length);
+// dprintf("write %s 0x%06x done\n", m->name, (int) m->offset);
}
-
-static void w29c020_init(const struct flash_order *d)
+static void am29f040_init(const struct flash_order *d)
{
-/*
-page write mode ¤Ç¤Ï¤È¤¯¤Ë¤Ê¤·
-*/
+ flash_erase_chip_02aa(d);
}
-static void w29c020_write(const struct flash_order *d, long address, long length, const u8 *data)
+static void am29f040_write(const struct flash_order *d, long address, long length, const struct memory *m)
{
- int retry = 0;
- {
- long a = address;
- long i = length;
- const u8 *dd;
- u8 *cmp;
-
- dd = data;
- cmp = malloc(d->pagesize);
- while(i != 0){
- int result = program_pagewrite(d, a, dd, d->pagesize);
- if(result == NG){
- printf("%s: write error\n", __FUNCTION__);
- free(cmp);
+ const u8 *data;
+ data = m->data;
+ while(length != 0){
+ if(*data != 0xff){
+ command_set(d, PROTECT_DISABLE);
+ d->flash_write(address, *data);
+ if(toggle_check_d2d5d6(d, address) == NG){
+ dprintf("%s NG\n", __FUNCTION__);
return;
}
- d->read(a, d->pagesize, cmp);
- if(memcmp(cmp, dd, d->pagesize) == 0){
- a += d->pagesize;
- dd += d->pagesize;
- i -= d->pagesize;
- }else{
- if(retry >= 0x100){
- break;
- }
- retry++;
- }
}
- free(cmp);
+ address++;
+ data++;
+ length--;
}
+}
- printf("write ok. retry %d\n", retry);
- compare(d, address, data, length);
- Sleep(10);
+static void init_nop(const struct flash_order *d)
+{
+/*
+page write mode ¤Ç¤Ï¤È¤¯¤Ë¤Ê¤·
+*/
}
-static void w29c040_write(const struct flash_order *d, long address, long length, const u8 *data)
+static void w29c040_write(const struct flash_order *d, long address, long length, const struct memory *m)
{
u8 *cmp;
int ngblock = 0;
+ int retry = 0;
+ assert(d->pagesize != 0);
cmp = malloc(d->pagesize);
do{
long a = address;
long i = length;
+ long offset = m->offset;
const u8 *dd;
- dd = data;
+ dd = m->data;
ngblock = 0;
while(i != 0){
d->read(a, d->pagesize, cmp);
if(memcmp(cmp, dd, d->pagesize) != 0){
ngblock++;
- printf("write %x\n", (int) a);
+ dprintf("write %s 0x%06x\n", m->name, (int) offset);
int result = program_pagewrite(d, a, dd, d->pagesize);
if(result == NG){
printf("%s: write error\n", __FUNCTION__);
}
a += d->pagesize;
dd += d->pagesize;
+ offset += d->pagesize;
i -= d->pagesize;
}
- printf("ngblock %d\n", ngblock);
+ dprintf("%s 0x%06x, ngblock %d\n", m->name, (int) m->offset, ngblock);
+ if(retry >= 3 && ngblock >= 16){
+ dprintf("skip\n");
+ break;
+ }
+ else if(retry > 12){
+ dprintf("skip\n");
+ break;
+ }
+ retry++;
fflush(stdout);
}while(ngblock != 0);
free(cmp);
- compare(d, address, data, length);
- Sleep(10);
+}
+
+static void sram_write(const struct flash_order *d, long address, long length, const struct memory *m)
+{
+ const u8 *data;
+ data = m->data;
+ while(length != 0){
+ d->flash_write(address, *data);
+ address++;
+ data++;
+ length--;
+ }
+}
+
+static void dummy_write(const struct flash_order *d, long address, long length, const struct memory *m)
+{
}
/*
¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
*/
+//0x80 °Ê¹ß¤ÏËÜÅö¤Î¥Ç¥Ð¥¤¥¹½ÅÊ£¤·¤Ê¤¤¤È»×¤¦. 狼 JEDEC ¤Î¤È¤³¤ò¤·¤é¤Ù¤Æ.
+static const struct flash_driver DRIVER_SRAM256K = {
+ .name = "SRAM256K",
+ .capacity = 0x8000,
+ .pagesize = 0,
+ .id_manufacurer = FLASH_ID_DEVICE_SRAM,
+ .id_device = FLASH_ID_DEVICE_SRAM,
+ .productid_check = productid_sram,
+#if DEBUG==1
+ .erase = sram_erase,
+#endif
+ .init = init_nop,
+ .write = sram_write
+};
+
+static const struct flash_driver DRIVER_DUMMY = {
+ .name = "dummy",
+ .capacity = 0x40000,
+ .pagesize = 0,
+ .id_manufacurer = FLASH_ID_DEVICE_DUMMY,
+ .id_device = FLASH_ID_DEVICE_DUMMY,
+ .productid_check = productid_sram,
+#if DEBUG==1
+ .erase = sram_erase,
+#endif
+ .init = init_nop,
+ .write = dummy_write
+};
+
static const struct flash_driver DRIVER_W29C020 = {
.name = "W29C020",
.capacity = 0x40000,
.id_device = 0x45,
.productid_check = productid_check,
#if DEBUG==1
- .erase = flash_erase,
+ .erase = flash_erase_chip_2aaa,
#endif
- .init = w29c020_init,
- .write = w29c020_write
+ .init = init_nop,
+ .write = w29c040_write
};
static const struct flash_driver DRIVER_W29C040 = {
.id_device = 0x46,
.productid_check = productid_check,
#if DEBUG==1
- .erase = flash_erase,
+ .erase = flash_erase_chip_2aaa,
#endif
- .init = w29c020_init,
+ .init = init_nop,
.write = w29c040_write
};
.id_device = 0xae,
.productid_check = productid_check,
#if DEBUG==1
- .erase = flash_erase,
+ .erase = flash_erase_chip_2aaa,
#endif
.init = w49f002_init,
.write = w49f002_write
};
+/*
+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 = 0x40000,
+ .pagesize = 0,
+ .id_manufacurer = 0x1c,
+ .id_device = 0x92,
+ .productid_check = productid_check,
+#if DEBUG==1
+ .erase = flash_erase_chip_02aa,
+#endif
+ .init = am29f040_init,
+ .write = am29f040_write
+};
+
+static const struct flash_driver DRIVER_AM29F040B = {
+ .name = "AM29F040B",
+ .capacity = 0x80000,
+ .pagesize = 0,
+ .id_manufacurer = 0x01,
+ .id_device = 0xa4,
+ .productid_check = productid_check,
+#if DEBUG==1
+ .erase = flash_erase_chip_02aa,
+#endif
+ .init = am29f040_init,
+ .write = am29f040_write
+};
+
static const struct flash_driver *DRIVER_LIST[] = {
- &DRIVER_W29C020, &DRIVER_W29C040, &DRIVER_W49F002,
+ &DRIVER_W29C020, &DRIVER_W29C040,
+ &DRIVER_W49F002, &DRIVER_EN29F002T, &DRIVER_AM29F040B,
+ &DRIVER_SRAM256K,
+ &DRIVER_DUMMY,
NULL
};