OSDN Git Service

PPU_PROGRAM syntax を追加.
[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 /*
137 ---- toggle check ----
138 databit6
139 */
140 const int CHECK_RETRY_MAX = 0x10000;
141 static int toggle_check(const struct flash_order *d, long address)
142 {
143         u8 predata;
144         int retry = 0;
145         d->read(address, 1, &predata); //read DQ6
146         predata &= 0x40;
147         while(retry < CHECK_RETRY_MAX){
148                 u8 data;
149                 d->read(address, 1, &data); //read DQ6 again
150                 data &= 0x40;
151                 if(predata == data){
152                         return OK;
153                 }
154                 predata = data;
155                 retry++;
156         }
157         return NG;
158 }
159
160 /*
161 ---- polling check ----
162 databit7
163 */
164 static int polling_check(const struct flash_order *d, long address, u8 truedata)
165 {
166         int retry = 0;
167         
168         truedata &= 0x80;
169         while(retry < CHECK_RETRY_MAX){
170                 u8 data;
171                 d->read(address, 1, &data);
172                 data &= 0x80;
173                 if(truedata == data){
174                         return OK;
175                 }
176                 retry++;
177         }
178         return NG;
179 }
180
181 static void bootblock_lockout(const struct flash_order *d)
182 {
183         u8 dummy[3];
184         command_set(d, PP);
185         d->read(0x8000 ,3, dummy);
186         printf("%02x %02x %02x \n", dummy[0], dummy[1], dummy[2]);
187         d->read(0xfff2 ,1, dummy);
188         command_set(d, PRODUCTID_EXIT);
189 }
190 /*
191 ---- erase ----
192 */
193 static void flash_erase(const struct flash_order *d)
194 {
195         if(0) bootblock_lockout(d);
196         command_set(d, ERASE);
197         toggle_check(d, d->command_2aaa);
198         Sleep(200); //Tec 0.2 sec
199 }
200
201 /*
202 ---- program ----
203 */
204 static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
205 {
206         while(length != 0){
207                 if(*data != 0xff){
208                         u8 dummy;
209                         d->read(address, 1, &dummy);
210                         if(*data != dummy){
211                                 printf("%s %06x\n", __FUNCTION__, (int) address);
212                                 fflush(stdout);
213                                 command_set(d, PROTECT_DISABLE);
214                                 d->flash_write(address, *data);
215                                 if(toggle_check(d, address) == NG){
216                                         if(DEBUG == 1){
217                                                 printf("%s NG\n", __FUNCTION__);
218                                         }
219                                         return NG;
220                                 }
221                                 Sleep(1);
222                         }
223                 }
224                 address++;
225                 data++;
226                 length--;
227         }
228         return OK;
229 }
230
231 static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
232 {
233         const long toggle_address = address ;
234         command_set(d, PROTECT_DISABLE);
235         while(length != 0){
236                 d->flash_write(address, *data);
237                 address++;
238                 data++;
239                 length--;
240         }
241         Sleep(15);
242         int ret = toggle_check(d, toggle_address);
243         if(0){
244                 data--;
245                 address -= 1;
246                 polling_check(d, address - 1, *data);
247         }
248
249         //command_set(d, PROTECT_ENABLE);
250         //Sleep(15);
251         return ret;
252 }
253
254 /*
255 ---- block compare ----
256 */
257 static void compare(const struct flash_order *d, long address, const u8 *data, long length)
258 {
259         u8 *romdata, *r;
260         int count = 0;
261         romdata = malloc(length);
262         d->read(address, length, romdata);
263         r = romdata;
264         while(length != 0){
265                 if(*r != *data){
266                         char safix = ' ';
267                         if((count & 7) == 7){
268                                 safix = '\n';
269                         }
270                         count++;
271                         printf("%06x%c", (int)address, safix);
272                 }
273                 r++;
274                 data++;
275                 address++;
276                 length--;
277         }
278         free(romdata);
279 }
280
281 /*
282 ¸ÇÍ­¥Ç¥Ð¥¤¥¹¥É¥é¥¤¥Ð
283 */
284 static void w49f002_init(const struct flash_order *d)
285 {
286 /*
287 byte program mode ¤Ç¤Ï 1->0 ¤Ë¤¹¤ë¤À¤±¡£ 0->1 ¤Ï erase ¤Î¤ß¡£
288 ¤è¤Ã¤Æ½é´ü²½»þ¤Ë¤Ï erase ¤ò¼Â¹Ô¤¹¤ë
289 */
290         flash_erase(d);
291 }
292
293 static void w49f002_write(const struct flash_order *d, long address, long length, const struct memory *m)
294 {
295         int writemiss = 0;
296         int retry = 0;
297         const u8 *data;
298         u8 *compare;
299         
300         data = m->data;
301         compare = malloc(length);
302         do{
303                 if(program_byte(d, address, data, length) == NG){
304                         break;
305                 }
306                 d->read(address, length, compare);
307                 writemiss = memcmp(compare, data, length);
308                 if(retry > 20){
309                         printf("%s retry error\n", __FUNCTION__);
310                         break;
311                 }
312                 retry++;
313         }while(writemiss != 0);
314         free(compare);
315 }
316
317
318 static void w29c020_init(const struct flash_order *d)
319 {
320 /*
321 page write mode ¤Ç¤Ï¤È¤¯¤Ë¤Ê¤·
322 */
323 }
324
325 static void w29c020_write(const struct flash_order *d, long address, long length, const struct memory *m)
326 {
327         int retry = 0;
328         {
329                 long a = address;
330                 long i = length;
331                 const u8 *dd;
332                 u8 *cmp;
333
334                 dd = m->data;
335                 cmp = malloc(d->pagesize);
336                 while(i != 0){
337                         int result = program_pagewrite(d, a, dd, d->pagesize);
338                         if(result == NG){
339                                 printf("%s: write error\n", __FUNCTION__);
340                                 free(cmp);
341                                 return;
342                         }
343                         d->read(a, d->pagesize, cmp);
344                         if(memcmp(cmp, dd, d->pagesize) == 0){
345                                 a += d->pagesize;
346                                 dd += d->pagesize;
347                                 i -= d->pagesize;
348                         }else{
349                                 if(retry >= 0x100){
350                                         break;
351                                 }
352                                 retry++;
353                         }
354                 }
355                 free(cmp);
356         }
357
358         printf("write ok. retry %d\n", retry);
359         compare(d, address, m->data, length);
360         Sleep(10);
361 }
362
363 static void w29c040_write(const struct flash_order *d, long address, long length, const struct memory *m)
364 {
365         u8 *cmp;
366         int ngblock = 0;
367         int retry = 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 /*
413 ¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
414 */
415 static const struct flash_driver DRIVER_W29C020 = {
416         .name = "W29C020",
417         .capacity = 0x40000,
418         .pagesize = 0x80,
419         .id_manufacurer = 0xda,
420         .id_device = 0x45,
421         .productid_check = productid_check,
422 #if DEBUG==1
423         .erase = flash_erase,
424 #endif
425         .init = w29c020_init,
426         .write = w29c020_write
427 };
428
429 static const struct flash_driver DRIVER_W29C040 = {
430         .name = "W29C040",
431         .capacity = 0x80000,
432         .pagesize = 0x100,
433         .id_manufacurer = 0xda,
434         .id_device = 0x46,
435         .productid_check = productid_check,
436 #if DEBUG==1
437         .erase = flash_erase,
438 #endif
439         .init = w29c020_init,
440         .write = w29c040_write
441 };
442
443 static const struct flash_driver DRIVER_W49F002 = {
444         .name = "W49F002",
445         .capacity = 0x40000,
446         .pagesize = 0,
447         .id_manufacurer = 0xda,
448         .id_device = 0xae,
449         .productid_check = productid_check,
450 #if DEBUG==1
451         .erase = flash_erase,
452 #endif
453         .init = w49f002_init,
454         .write = w49f002_write
455 };
456
457 static const struct flash_driver *DRIVER_LIST[] = {
458         &DRIVER_W29C020, &DRIVER_W29C040, &DRIVER_W49F002,
459         NULL
460 };
461
462 const struct flash_driver *flash_driver_get(const char *name)
463 {
464         const struct flash_driver **d;
465         d = DRIVER_LIST;
466         while(*d != NULL){
467                 if(strcmp(name, (*d)->name) == 0){
468                         return *d;
469                 }
470                 d++;
471         }
472         return NULL;
473 }