OSDN Git Service

device として SRAM を追加
[unagi/old-svn-converted.git] / client / trunk / flashmemory.c
1 /*
2 famicom ROM cartridge utility - unagi
3 flash memory driver
4
5 Copyright (C) 2008  sato_tiff
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21 flashmemory.c ¤À¤±¤Î·Ù¹ð
22 ¤³¤Î¥½¡¼¥¹¥³¡¼¥É¤ò»²¹Í¡¢Å¾ÍѤ·¤Æ¥·¥§¥¢¥¦¥§¥¢¤Ê¤É¤ÇÍø±×¤òÆÀ¤Ê¤¤¤³¤È¡£
23 ȽÌÀ¤·¤¿¾ì¹ç¤Ï LGPL ¤¬Å¬ÍѤµ¤ì¡¢³ºÅö²Õ½ê¤Î¥½¡¼¥¹¤ò¸ø³«¤¹¤ëɬÍפ¬¤¢¤ë¡£
24 */
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <windows.h>
30 #include "type.h"
31 #include "header.h"
32 #include "flashmemory.h"
33 /*
34 driver for Winbond W29C020, W49F002
35 */
36 /*
37 JEDEC flash memory command
38 http://www.sst.com/downloads/software_driver/SST49LF002A.txt
39 */
40 struct flash_task{
41         long address, data;
42 };
43 enum{
44         ADDRESS_0000 = 0,
45         ADDRESS_2AAA = 0x2aaa,
46         ADDRESS_5555 = 0x5555,
47         FLASH_COMMAND_END
48 };
49 static const struct flash_task PRODUCTID_ENTRY[] = {
50         {ADDRESS_5555, 0xaa},
51         {ADDRESS_2AAA, 0x55},
52         {ADDRESS_5555, 0x90},
53         {FLASH_COMMAND_END, 0}
54 };
55 static const struct flash_task PRODUCTID_EXIT[] = {
56         {ADDRESS_5555, 0xaa},
57         {ADDRESS_2AAA, 0x55},
58         {ADDRESS_5555, 0xf0},
59         {FLASH_COMMAND_END, 0}
60 };
61 static const struct flash_task PROTECT_DISABLE[] = {
62         {ADDRESS_5555, 0xaa},
63         {ADDRESS_2AAA, 0x55},
64         {ADDRESS_5555, 0xa0},
65         {FLASH_COMMAND_END, 0}
66 };
67 static const struct flash_task PROTECT_ENABLE[] = {
68         {ADDRESS_5555, 0xaa},
69         {ADDRESS_2AAA, 0x55},
70         {ADDRESS_5555, 0x80},
71         {ADDRESS_5555, 0xaa},
72         {ADDRESS_2AAA, 0x55},
73         {ADDRESS_5555, 0x20},
74         {FLASH_COMMAND_END, 0}
75 };
76 static const struct flash_task ERASE[] = {
77         {ADDRESS_5555, 0xaa},
78         {ADDRESS_2AAA, 0x55},
79         {ADDRESS_5555, 0x80},
80         {ADDRESS_5555, 0xaa},
81         {ADDRESS_2AAA, 0x55},
82         {ADDRESS_5555, 0x10},
83         {FLASH_COMMAND_END, 0}
84 };
85
86 static const struct flash_task PP[] = {
87         {ADDRESS_5555, 0xaa},
88         {ADDRESS_2AAA, 0x55},
89         {ADDRESS_5555, 0x80},
90         {ADDRESS_5555, 0xaa},
91         {ADDRESS_2AAA, 0x55},
92         {ADDRESS_5555, 0x60},
93         {FLASH_COMMAND_END, 0}
94 };
95
96 static void command_set(const struct flash_order *d, const struct flash_task *t)
97 {
98         while(t->address != FLASH_COMMAND_END){
99                 long logical_address = 0;
100                 switch(t->address){
101                 case ADDRESS_0000: //bank ¤Ë¤è¤Ã¤Æ¤ÏÀßÄê¤Ç¤­¤Ê¤¤¤«¤â?
102                         logical_address = d->command_0000;
103                         break;
104                 case ADDRESS_2AAA:
105                         logical_address = d->command_2aaa;
106                         break;
107                 case ADDRESS_5555:
108                         logical_address = d->command_5555;
109                         break;
110                 default:
111                         assert(0); //unknown task address
112                 }
113                 d->flash_write(logical_address, t->data);
114                 t++;
115         }
116 }
117
118 /*
119 ---- product ID check ----
120 */
121 static int productid_check(const struct flash_order *d, const struct flash_driver *f)
122 {
123         u8 data[3];
124         command_set(d, PRODUCTID_ENTRY);
125         d->read(d->command_0000, 3, data);
126         command_set(d, PRODUCTID_EXIT);
127         if(f->id_manufacurer != data[0]){
128                 return NG;
129         }
130         if(f->id_device != data[1]){
131                 return NG;
132         }
133         return OK;
134 }
135
136 static int productid_sram(const struct flash_order *d, const struct flash_driver *f)
137 {
138         return OK;
139 }
140 /*
141 ---- toggle check ----
142 databit6
143 */
144 const int CHECK_RETRY_MAX = 0x10000;
145 static int toggle_check(const struct flash_order *d, long address)
146 {
147         u8 predata;
148         int retry = 0;
149         d->read(address, 1, &predata); //read DQ6
150         predata &= 0x40;
151         while(retry < CHECK_RETRY_MAX){
152                 u8 data;
153                 d->read(address, 1, &data); //read DQ6 again
154                 data &= 0x40;
155                 if(predata == data){
156                         return OK;
157                 }
158                 predata = data;
159                 retry++;
160         }
161         return NG;
162 }
163
164 /*
165 ---- polling check ----
166 databit7
167 */
168 static int polling_check(const struct flash_order *d, long address, u8 truedata)
169 {
170         int retry = 0;
171         
172         truedata &= 0x80;
173         while(retry < CHECK_RETRY_MAX){
174                 u8 data;
175                 d->read(address, 1, &data);
176                 data &= 0x80;
177                 if(truedata == data){
178                         return OK;
179                 }
180                 retry++;
181         }
182         return NG;
183 }
184
185 static void bootblock_lockout(const struct flash_order *d)
186 {
187         u8 dummy[3];
188         command_set(d, PP);
189         d->read(0x8000 ,3, dummy);
190         printf("%02x %02x %02x \n", dummy[0], dummy[1], dummy[2]);
191         d->read(0xfff2 ,1, dummy);
192         command_set(d, PRODUCTID_EXIT);
193 }
194 /*
195 ---- erase ----
196 */
197 static void flash_erase(const struct flash_order *d)
198 {
199         if(0) bootblock_lockout(d);
200         command_set(d, ERASE);
201         toggle_check(d, d->command_2aaa);
202         Sleep(200); //Tec 0.2 sec
203 }
204
205 static void sram_erase(const struct flash_order *d)
206 {
207         //bank ÀÚ¤êÂؤ¨¤¬È¼¤¦¤Î¤Ç¼ÂÁõ¤Ç¤­¤Ê¤¤
208 }
209
210 /*
211 ---- program ----
212 */
213 static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
214 {
215         int retry = 0;
216         while(length != 0){
217                 if(*data != 0xff){
218                         fflush(stdout);
219                         command_set(d, PROTECT_DISABLE);
220                         d->flash_write(address, *data);
221                         if(toggle_check(d, address) == NG){
222                                 if(DEBUG == 1){
223                                         printf("%s NG\n", __FUNCTION__);
224                                 }
225                                 return NG;
226                         }
227                 }
228                 u8 dummy;
229                 d->read(address, 1, &dummy);
230                 if(*data == dummy){
231                         address++;
232                         data++;
233                         length--;
234                         retry = 0;
235                 }else if(retry > 8){
236                         printf("%s %06x error\n", __FUNCTION__, (int) address);
237                         address++;
238                         data++;
239                         length--;
240                         retry = 0;
241                 }else{
242                         retry++;
243                 }
244         }
245         return OK;
246 }
247
248 static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
249 {
250         const long toggle_address = address ;
251         command_set(d, PROTECT_DISABLE);
252         while(length != 0){
253                 d->flash_write(address, *data);
254                 address++;
255                 data++;
256                 length--;
257         }
258         Sleep(15);
259         int ret = toggle_check(d, toggle_address);
260         if(0){
261                 data--;
262                 address -= 1;
263                 polling_check(d, address - 1, *data);
264         }
265
266         //command_set(d, PROTECT_ENABLE);
267         //Sleep(15);
268         return ret;
269 }
270
271 /*
272 ---- block compare ----
273 */
274 static void compare(const struct flash_order *d, long address, const u8 *data, long length)
275 {
276         u8 *romdata, *r;
277         int count = 0;
278         romdata = malloc(length);
279         d->read(address, length, romdata);
280         r = romdata;
281         while(length != 0){
282                 if(*r != *data){
283                         char safix = ' ';
284                         if((count & 7) == 7){
285                                 safix = '\n';
286                         }
287                         count++;
288                         printf("%06x%c", (int)address, safix);
289                 }
290                 r++;
291                 data++;
292                 address++;
293                 length--;
294         }
295         free(romdata);
296 }
297
298 /*
299 ¸ÇÍ­¥Ç¥Ð¥¤¥¹¥É¥é¥¤¥Ð
300 */
301 static void w49f002_init(const struct flash_order *d)
302 {
303 /*
304 byte program mode ¤Ç¤Ï 1->0 ¤Ë¤¹¤ë¤À¤±¡£ 0->1 ¤Ï erase ¤Î¤ß¡£
305 ¤è¤Ã¤Æ½é´ü²½»þ¤Ë¤Ï erase ¤ò¼Â¹Ô¤¹¤ë
306 */
307         flash_erase(d);
308 }
309
310 static void w49f002_write(const struct flash_order *d, long address, long length, const struct memory *m)
311 {
312         program_byte(d, address, m->data, length);
313 }
314
315
316 static void init_nop(const struct flash_order *d)
317 {
318 /*
319 page write mode ¤Ç¤Ï¤È¤¯¤Ë¤Ê¤·
320 */
321 }
322
323 static void w29c020_write(const struct flash_order *d, long address, long length, const struct memory *m)
324 {
325         int retry = 0;
326         assert(d->pagesize != 0);
327         {
328                 long a = address;
329                 long i = length;
330                 const u8 *dd;
331                 u8 *cmp;
332
333                 dd = m->data;
334                 cmp = malloc(d->pagesize);
335                 while(i != 0){
336                         int result = program_pagewrite(d, a, dd, d->pagesize);
337                         if(result == NG){
338                                 printf("%s: write error\n", __FUNCTION__);
339                                 free(cmp);
340                                 return;
341                         }
342                         d->read(a, d->pagesize, cmp);
343                         if(memcmp(cmp, dd, d->pagesize) == 0){
344                                 a += d->pagesize;
345                                 dd += d->pagesize;
346                                 i -= d->pagesize;
347                         }else{
348                                 if(retry >= 0x100){
349                                         break;
350                                 }
351                                 retry++;
352                         }
353                 }
354                 free(cmp);
355         }
356
357         printf("write ok. retry %d\n", retry);
358         compare(d, address, m->data, length);
359         Sleep(10);
360 }
361
362 static void w29c040_write(const struct flash_order *d, long address, long length, const struct memory *m)
363 {
364         u8 *cmp;
365         int ngblock = 0;
366         int retry = 0;
367         assert(d->pagesize != 0);
368         cmp = malloc(d->pagesize);
369         do{
370                 long a = address;
371                 long i = length;
372                 long offset = m->offset;
373                 const u8 *dd;
374
375                 dd = m->data;
376                 ngblock = 0;
377                 while(i != 0){
378                         d->read(a, d->pagesize, cmp);
379                         if(memcmp(cmp, dd, d->pagesize) != 0){
380                                 ngblock++;
381                                 printf("write %s 0x%06x\n", m->name, (int) offset);
382                                 int result = program_pagewrite(d, a, dd, d->pagesize);
383                                 if(result == NG){
384                                         printf("%s: write error\n", __FUNCTION__);
385                                         free(cmp);
386                                         return;
387                                 }
388                         }
389                         a += d->pagesize;
390                         dd += d->pagesize;
391                         offset += d->pagesize;
392                         i -= d->pagesize;
393                 }
394                 printf("%s 0x%06x, ngblock %d\n", m->name, (int) offset, ngblock);
395                 if(retry >= 3 && ngblock >= 16){
396                         printf("skip\n");
397                         break;
398                 }
399                 else if(retry > 12){
400                         printf("skip\n");
401                         break;
402                 }
403                 retry++;
404                 fflush(stdout);
405         }while(ngblock != 0);
406
407         free(cmp);
408 //      compare(d, address, data, length);
409 //      Sleep(10);
410 }
411
412 static void sram_write(const struct flash_order *d, long address, long length, const struct memory *m)
413 {
414         const u8 *data;
415         data = m->data;
416         while(length != 0){
417                 d->flash_write(address, *data);
418                 address++;
419                 data++;
420                 length--;
421         }
422 }
423
424 /*
425 ¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
426 */
427 enum{
428         ID_SRAM = 0
429 };
430 static const struct flash_driver DRIVER_SRAM256K = {
431         .name = "SRAM256K",
432         .capacity = 0x8000,
433         .pagesize = 0,
434         .id_manufacurer = ID_SRAM,
435         .id_device = ID_SRAM,
436         .productid_check = productid_sram,
437 #if DEBUG==1
438         .erase = sram_erase,
439 #endif
440         .init = init_nop,
441         .write = sram_write
442 };
443
444 static const struct flash_driver DRIVER_W29C020 = {
445         .name = "W29C020",
446         .capacity = 0x40000,
447         .pagesize = 0x80,
448         .id_manufacurer = 0xda,
449         .id_device = 0x45,
450         .productid_check = productid_check,
451 #if DEBUG==1
452         .erase = flash_erase,
453 #endif
454         .init = init_nop,
455         .write = w29c020_write
456 };
457
458 static const struct flash_driver DRIVER_W29C040 = {
459         .name = "W29C040",
460         .capacity = 0x80000,
461         .pagesize = 0x100,
462         .id_manufacurer = 0xda,
463         .id_device = 0x46,
464         .productid_check = productid_check,
465 #if DEBUG==1
466         .erase = flash_erase,
467 #endif
468         .init = init_nop,
469         .write = w29c040_write
470 };
471
472 static const struct flash_driver DRIVER_W49F002 = {
473         .name = "W49F002",
474         .capacity = 0x40000,
475         .pagesize = 0,
476         .id_manufacurer = 0xda,
477         .id_device = 0xae,
478         .productid_check = productid_check,
479 #if DEBUG==1
480         .erase = flash_erase,
481 #endif
482         .init = w49f002_init,
483         .write = w49f002_write
484 };
485
486 static const struct flash_driver *DRIVER_LIST[] = {
487         &DRIVER_W29C020, &DRIVER_W29C040, &DRIVER_W49F002,
488         &DRIVER_SRAM256K, 
489         NULL
490 };
491
492 const struct flash_driver *flash_driver_get(const char *name)
493 {
494         const struct flash_driver **d;
495         d = DRIVER_LIST;
496         while(*d != NULL){
497                 if(strcmp(name, (*d)->name) == 0){
498                         return *d;
499                 }
500                 d++;
501         }
502         return NULL;
503 }