OSDN Git Service

flashmemory の引数を struct flash_order に変更
[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 "driver_master.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 static const struct flash_task ERASE[] = {
101         {0x5555, 0xaa},
102         {0x2aaa, 0x55},
103         {0x5555, 0x80},
104         {0x5555, 0xaa},
105         {0x2aaa, 0x55},
106         {0x5555, 0x10},
107         {flash_task_end, 0}
108 };
109
110 static void task_set(const struct flash_order *d, const struct flash_task *t)
111 {
112         while(t->address != flash_task_end){
113                 long cpu_address = 0;
114                 switch(t->address){
115                 case 0x2aaa:
116                         cpu_address = d->task_2aaa;
117                         break;
118                 case 0x5555:
119                         cpu_address = d->task_5555;
120                         break;
121                 default:
122                         assert(0);
123                 }
124                 d->flash_write(cpu_address, t->data);
125                 t++;
126         }
127 }
128
129 /*
130 ---- product ID check ----
131 */
132 static int productid_check(const struct flash_order *d, const struct flash_driver *f)
133 {
134         u8 data[3];
135         task_set(d, PRODUCTID_ENTRY);
136         d->read(d->task_0000, 3, data);
137         task_set(d, PRODUCTID_EXIT);
138         if(f->id_manufacurer != data[0]){
139                 return NG;
140         }
141         if(f->id_device != data[1]){
142                 return NG;
143         }
144         return OK;
145 }
146
147 /*
148 ---- toggle check ----
149 databit6
150 */
151 const int CHECK_RETRY_MAX = 0x10000;
152 static int toggle_check(const struct flash_order *d, long address)
153 {
154         u8 predata;
155         int retry = 0;
156         d->read(address, 1, &predata); //read DQ6
157         predata &= 0x40;
158         while(retry < CHECK_RETRY_MAX){
159                 u8 data;
160                 d->read(address, 1, &data); //read DQ6 again
161                 data &= 0x40;
162                 if(predata == data){
163                         return OK;
164                 }
165                 predata = data;
166                 retry++;
167         }
168         return NG;
169 }
170
171 /*
172 ---- polling check ----
173 databit7
174 */
175 static int polling_check(const struct flash_order *d, long address, u8 truedata)
176 {
177         int retry = 0;
178         
179         truedata &= 0x80;
180         while(retry < CHECK_RETRY_MAX){
181                 u8 data;
182                 d->read(address, 1, &data);
183                 data &= 0x80;
184                 if(truedata == data){
185                         return OK;
186                 }
187                 retry++;
188         }
189         return NG;
190 }
191
192 /*
193 ---- erase ----
194 */
195 static void flash_erase(const struct flash_order *d)
196 {
197         task_set(d, ERASE);
198         toggle_check(d, d->task_2aaa);
199         //Sleep(200); //Tec 0.2 sec
200 }
201
202 /*
203 ---- program ----
204 */
205 static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
206 {
207         while(length != 0){
208                 if(*data != 0xff){
209                         task_set(d, PROTECT_DISABLE);
210                         d->flash_write(address, *data);
211                         if(toggle_check(d, address) == NG){
212                                 if(DEBUG == 1){
213                                         printf("%s NG\n", __FUNCTION__);
214                                 }
215                                 return NG;
216                         }
217                         if(0){
218                         u8 putdata;
219                         d->read(address, 1, &putdata);
220                         if(putdata != *data){
221                                 printf("%s %06x retry\n", __FUNCTION__, (int) address);
222                                 continue;
223                         }
224                         }
225                 }
226                 if((DEBUG == 1) && (address & 0x1f) == 0){
227                         printf("%s %06x\n", __FUNCTION__, (int) address);
228                         fflush(stdout);
229                 }
230                 address++;
231                 data++;
232                 length--;
233         }
234         return OK;
235 }
236
237 static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
238 {
239         task_set(d, PROTECT_DISABLE);
240         while(length != 0){
241                 d->flash_write(address, *data);
242                 address++;
243                 data++;
244                 length--;
245         }
246         Sleep(1);
247         return toggle_check(d, d->address);
248 }
249
250 /*
251 ---- block compare ----
252 */
253 static void compare(const struct flash_order *d, long address, const u8 *data, long length)
254 {
255         u8 *romdata, *r;
256         romdata = malloc(length);
257         d->read(address, length, romdata);
258         r = romdata;
259         while(length != 0){
260                 if(*r != *data){
261                         printf("%06x\n", (int)address);
262                 }
263                 r++;
264                 data++;
265                 address++;
266                 length--;
267         }
268         free(romdata);
269 }
270
271 /*
272 ¸ÇÍ­¥Ç¥Ð¥¤¥¹¥É¥é¥¤¥Ð
273 */
274 static void w49f002_write(const struct flash_order *d)
275 {
276         program_byte(d, d->address, d->data, d->length);
277         compare(d, d->address, d->data, d->length);
278 }
279
280 static void w29c020_write(const struct flash_order *d)
281 {
282         {
283                 const long pagesize = 0x80;
284                 long a = d->address;
285                 long i = d->length;
286                 const u8 *dd;
287                 dd = d->data;
288                 while(i >= 0){
289                         int result = program_pagewrite(d, a, dd, d->length);
290                         if(result == NG){
291                                 return;
292                         }
293                         a += pagesize;
294                         dd += pagesize;
295                         i -= pagesize;
296                 }
297         }
298         compare(d, d->address, d->data, d->length);
299 }
300
301 /*
302 ¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
303 */
304 static const struct flash_driver DRIVER_W29C020 = {
305         name: "W29C020",
306         capacity: 0x40000,
307         id_manufacurer: 0xda,
308         id_device: 0x45,
309         productid_check: productid_check,
310         erase: flash_erase,
311         write: w29c020_write
312 };
313
314 static const struct flash_driver DRIVER_W49F002 = {
315         name: "W49F002",
316         capacity: 0x40000,
317         id_manufacurer: 0xda,
318         id_device: 0xae,
319         productid_check: productid_check,
320         erase: flash_erase,
321         write: w49f002_write
322 };
323
324 static const struct flash_driver *DRIVER_LIST[] = {
325         &DRIVER_W29C020, &DRIVER_W49F002,
326         NULL
327 };
328
329 const struct flash_driver *flash_driver_get(const char *name)
330 {
331         const struct flash_driver **d;
332         d = DRIVER_LIST;
333         while(*d != NULL){
334                 if(strcmp(name, (*d)->name) == 0){
335                         return *d;
336                 }
337                 d++;
338         }
339         return NULL;
340 }