OSDN Git Service

test 用コードを unagi.c から分離
[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 "flashmemory.h"
32 /*
33 driver for Winbond W29C020, W49F002
34 */
35 /*
36 ----memory detail----
37 VRC6 CPU memory bank
38 cpu address|rom address    |page|task
39 $8000-$bfff|0x00000-0x03fff|0   |write (0x2aaa & 0x3fff) + 0x8000
40 $c000-$dfff|0x04000-0x05fff|2   |write (0x5555 & 0x1fff) + 0xc000
41 $e000-$efff|0x3e000-0x3ffff|fix |boot area
42
43 MMC3 CPU memory bank
44 cpu address|rom address    |page|task
45 $8000-$9fff|0x02000-0x03fff|1   |write (0x2aaa & 0x1fff) + 0x8000
46 $a000-$bfff|0x04000-0x05fff|2   |write (0x5555 & 0x1fff) + 0xa000
47 $c000-$efff|ËöÈø           |fix |boot area
48
49 generic CPU memory bank
50 cpu address|rom address    |page|task
51 $8000-$9fff|0x02000-0x03fff|1   |write (0x2aaa & 0x1fff) + 0x8000
52 $a000-$bfff|0x04000-0x05fff|2   |write (0x5555 & 0x1fff) + 0xa000
53 $c000-$dfff|n * 0x2000     |n   |write area
54 $e000-$efff|ËöÈø           |fix |boot area, Ì¤»ÈÍÑ
55
56 generic PPU memory bank
57 ppu address|rom address    |page|task
58 $0000-$03ff|0x02800-0x02bff|0x0a|write (0x2aaa & 0x03ff) + 0
59 $0400-$07ff|0x05400-0x057ff|0x15|write (0x5555 & 0x03ff) + 0x400
60 $0800-$0fff|̤»ÈÍÑ
61 $1000-$1fff|n * 0x0400     |n   |write area
62 */
63 /*
64 JEDEC flash memory command
65 http://www.sst.com/downloads/software_driver/SST49LF002A.txt
66 */
67 struct flash_task{
68         long address, data;
69 };
70 enum{
71         flash_task_end = 0x46494649
72 };
73 static const struct flash_task PRODUCTID_ENTRY[] = {
74         {0x5555, 0xaa},
75         {0x2aaa, 0x55},
76         {0x5555, 0x90},
77         {flash_task_end, 0}
78 };
79 static const struct flash_task PRODUCTID_EXIT[] = {
80         {0x5555, 0xaa},
81         {0x2aaa, 0x55},
82         {0x5555, 0xf0},
83         {flash_task_end, 0}
84 };
85 static const struct flash_task PROTECT_DISABLE[] = {
86         {0x5555, 0xaa},
87         {0x2aaa, 0x55},
88         {0x5555, 0xa0},
89         {flash_task_end, 0}
90 };
91 static const struct flash_task PROTECT_ENABLE[] = {
92         {0x5555, 0xaa},
93         {0x2aaa, 0x55},
94         {0x5555, 0x80},
95         {0x5555, 0xaa},
96         {0x2aaa, 0x55},
97         {0x5555, 0x20},
98         {flash_task_end, 0}
99 };
100 //boot lock lockout enable ¤ò¤¤¤ì¤Ê¤¤¤È¥Ð¥ó¥¯ÀÚ¤êÂؤ¨¤ò¤¹¤ë¤È
101 //ÀèƬ¤Î0x100byte¤°¤é¤¤¤¬½ñ¤­´¹¤¨¤é¤ì¤ë?
102 static const struct flash_task BOOTBLOCK_FIRST[] = {
103         {0x5555, 0xaa},
104         {0x2aaa, 0x55},
105         {0x5555, 0x80},
106         {0x5555, 0xaa},
107         {0x2aaa, 0x55},
108         {0x5555, 0x40},
109         {0x0000, 0},
110         {flash_task_end, 0}
111 };
112 static const struct flash_task ERASE[] = {
113         {0x5555, 0xaa},
114         {0x2aaa, 0x55},
115         {0x5555, 0x80},
116         {0x5555, 0xaa},
117         {0x2aaa, 0x55},
118         {0x5555, 0x10},
119         {flash_task_end, 0}
120 };
121
122 static void task_set(const struct flash_order *d, const struct flash_task *t)
123 {
124         while(t->address != flash_task_end){
125                 long logical_address = 0;
126                 switch(t->address){
127                 case 0:
128                         logical_address = d->task_0000;
129                         break;
130                 case 0x2aaa:
131                         logical_address = d->task_2aaa;
132                         break;
133                 case 0x5555:
134                         logical_address = d->task_5555;
135                         break;
136                 default:
137                         assert(0);
138                 }
139                 d->flash_write(logical_address, t->data);
140                 t++;
141         }
142 }
143
144 /*
145 ---- product ID check ----
146 */
147 static int productid_check(const struct flash_order *d, const struct flash_driver *f)
148 {
149         u8 data[3];
150         task_set(d, PRODUCTID_ENTRY);
151         d->read(d->task_0000, 3, data);
152         task_set(d, PRODUCTID_EXIT);
153         if(f->id_manufacurer != data[0]){
154                 return NG;
155         }
156         if(f->id_device != data[1]){
157                 return NG;
158         }
159         return OK;
160 }
161
162 /*
163 ---- toggle check ----
164 databit6
165 */
166 const int CHECK_RETRY_MAX = 0x10000;
167 static int toggle_check(const struct flash_order *d, long address)
168 {
169         u8 predata;
170         int retry = 0;
171         d->read(address, 1, &predata); //read DQ6
172         predata &= 0x40;
173         while(retry < CHECK_RETRY_MAX){
174                 u8 data;
175                 d->read(address, 1, &data); //read DQ6 again
176                 data &= 0x40;
177                 if(predata == data){
178                         return OK;
179                 }
180                 predata = data;
181                 retry++;
182         }
183         return NG;
184 }
185
186 /*
187 ---- polling check ----
188 databit7
189 */
190 static int polling_check(const struct flash_order *d, long address, u8 truedata)
191 {
192         int retry = 0;
193         
194         truedata &= 0x80;
195         while(retry < CHECK_RETRY_MAX){
196                 u8 data;
197                 d->read(address, 1, &data);
198                 data &= 0x80;
199                 if(truedata == data){
200                         return OK;
201                 }
202                 retry++;
203         }
204         return NG;
205 }
206
207 /*
208 ---- erase ----
209 */
210 static void flash_erase(const struct flash_order *d)
211 {
212         task_set(d, ERASE);
213         toggle_check(d, d->task_2aaa);
214         //Sleep(200); //Tec 0.2 sec
215 }
216
217 /*
218 ---- program ----
219 */
220 static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
221 {
222         while(length != 0){
223                 if(*data != 0xff){
224                         task_set(d, PROTECT_DISABLE);
225                         d->flash_write(address, *data);
226                         if(toggle_check(d, address) == NG){
227                                 if(DEBUG == 1){
228                                         printf("%s NG\n", __FUNCTION__);
229                                 }
230                                 return NG;
231                         }
232                         if(0){
233                         u8 putdata;
234                         d->read(address, 1, &putdata);
235                         if(putdata != *data){
236                                 printf("%s %06x retry\n", __FUNCTION__, (int) address);
237                                 continue;
238                         }
239                         }
240                 }
241                 if((DEBUG == 1) && (address & 0x1f) == 0){
242                         printf("%s %06x\n", __FUNCTION__, (int) address);
243                         fflush(stdout);
244                 }
245                 address++;
246                 data++;
247                 length--;
248         }
249         return OK;
250 }
251
252 static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
253 {
254         const long toggle_address = address;
255         task_set(d, PROTECT_DISABLE);
256         while(length != 0){
257                 d->flash_write(address, *data);
258                 address++;
259                 data++;
260                 length--;
261         }
262         Sleep(15);
263         int ret = toggle_check(d, toggle_address);
264         if(0){
265                 data--;
266                 address -= 1;
267                 polling_check(d, address - 1, *data);
268         }
269
270         //task_set(d, PROTECT_ENABLE);
271         //Sleep(15);
272         return ret;
273 }
274
275 /*
276 ---- block compare ----
277 */
278 static void compare(const struct flash_order *d, long address, const u8 *data, long length)
279 {
280         u8 *romdata, *r;
281         int count = 0;
282         romdata = malloc(length);
283         d->read(address, length, romdata);
284         r = romdata;
285         while(length != 0){
286                 if(*r != *data){
287                         char safix = ' ';
288                         if((count & 7) == 7){
289                                 safix = '\n';
290                         }
291                         count++;
292                         printf("%06x%c", (int)address, safix);
293                 }
294                 r++;
295                 data++;
296                 address++;
297                 length--;
298         }
299         free(romdata);
300 }
301
302 /*
303 ¸ÇÍ­¥Ç¥Ð¥¤¥¹¥É¥é¥¤¥Ð
304 */
305 static void w49f002_write(const struct flash_order *d)
306 {
307         program_byte(d, d->address, d->data, d->length);
308         compare(d, d->address, d->data, d->length);
309 }
310
311 static void w29c020_write(const struct flash_order *d)
312 {
313         const long pagesize = 0x80;
314         int retry = 0;
315         {
316                 long a = d->address;
317                 long i = d->length;
318                 const u8 *dd;
319                 u8 *cmp;
320
321                 dd = d->data;
322                 cmp = malloc(pagesize);
323                 while(i != 0){
324                         int result = program_pagewrite(d, a, dd, pagesize);
325                         if(result == NG){
326                                 printf("%s: write error\n", __FUNCTION__);
327                                 free(cmp);
328                                 return;
329                         }
330                         d->read(a, pagesize, cmp);
331                         if(memcmp(cmp, dd, pagesize) == 0){
332                                 a += pagesize;
333                                 dd += pagesize;
334                                 i -= pagesize;
335                         }else{
336                                 retry++;
337                         }
338                 }
339                 free(cmp);
340         }
341
342         printf("write ok. retry %d\n", retry);
343         compare(d, d->address, d->data, d->length);
344         task_set(d, BOOTBLOCK_FIRST);
345         Sleep(10);
346 }
347
348 /*
349 ¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
350 */
351 static const struct flash_driver DRIVER_W29C020 = {
352         name: "W29C020",
353         capacity: 0x40000,
354         id_manufacurer: 0xda,
355         id_device: 0x45,
356         productid_check: productid_check,
357         erase: flash_erase,
358         write: w29c020_write
359 };
360
361 static const struct flash_driver DRIVER_W49F002 = {
362         name: "W49F002",
363         capacity: 0x40000,
364         id_manufacurer: 0xda,
365         id_device: 0xae,
366         productid_check: productid_check,
367         erase: flash_erase,
368         write: w49f002_write
369 };
370
371 static const struct flash_driver *DRIVER_LIST[] = {
372         &DRIVER_W29C020, &DRIVER_W49F002,
373         NULL
374 };
375
376 const struct flash_driver *flash_driver_get(const char *name)
377 {
378         const struct flash_driver **d;
379         d = DRIVER_LIST;
380         while(*d != NULL){
381                 if(strcmp(name, (*d)->name) == 0){
382                         return *d;
383                 }
384                 d++;
385         }
386         return NULL;
387 }