OSDN Git Service

kazzo 0.1.3 release
[unagi/old-svn-converted.git] / kazzo / tag / 0.1.3 / firmware / flashmemory.c
1 #include <stdint.h>
2 //#include <avr/interrupt.h>
3 #include "kazzo_task.h"
4 #include "bus_access.h"
5
6 //---- global variable ----
7 struct flash_seqence{
8         void (*const writer)(uint16_t address, uint16_t length, const uint8_t *data);
9         void (*const programmer)(const struct flash_order *t);
10         void (*const reader)(uint16_t address, uint16_t length, uint8_t *data);
11         enum compare_status (*const compare)(uint16_t address, uint16_t length, const uint8_t *data);
12         enum status{
13                 IDLE = KAZZO_TASK_FLASH_IDLE, 
14                 ERASE, ERASE_WAIT,
15                 PROGRAM, TOGGLE_FIRST, TOGGLE_CHECK
16         } status, request;
17         uint16_t command_000x, command_2aaa, command_5555;
18         uint8_t retry_enable;
19         uint16_t address, length, program_unit;
20         const uint8_t *data;
21         uint8_t toggle, retry_count;
22         struct flash_order program_command[FLASH_PROGRAM_ORDER];
23 };
24 static struct flash_seqence seqence_cpu = {
25         .status = IDLE, .reader = cpu_read, 
26         .writer = cpu_write_flash, .programmer = cpu_write_flash_order,
27         .compare = cpu_compare
28 };
29 static struct flash_seqence seqence_ppu = {
30         .status = IDLE, .reader = ppu_read, 
31         .writer = ppu_write, .programmer = ppu_write_order,
32         .compare = ppu_compare
33 };
34
35 //---- task registration ----
36 uint8_t flash_cpu_status(void)
37 {
38         return seqence_cpu.status;
39 }
40 uint8_t flash_ppu_status(void)
41 {
42         return seqence_ppu.status;
43 }
44 void flash_both_idle(void)
45 {
46         seqence_cpu.status = IDLE;
47         seqence_ppu.status = IDLE;
48 }
49 static inline uint16_t unpack_short_le(const uint8_t *t)
50 {
51         uint16_t r = t[0];
52         r |= t[1] << 8;
53         return r;
54 }
55 static void config_set(const uint8_t *data, uint16_t length, struct flash_seqence *t)
56 {
57         t->command_000x = unpack_short_le(data);
58         data += sizeof(uint16_t);
59         t->command_2aaa = unpack_short_le(data);
60         data += sizeof(uint16_t);
61         t->command_5555 = unpack_short_le(data);
62         data += sizeof(uint16_t);
63         t->program_unit = unpack_short_le(data);
64         data += sizeof(uint16_t);
65         if(length < 9){ //support client 0.6.0
66                 t->retry_enable = 0;
67         }else{
68                 t->retry_enable = *data;
69         }
70
71         t->program_command[0].address = t->command_5555;
72         t->program_command[0].data = 0xaa;
73         t->program_command[1].address = t->command_2aaa;
74         t->program_command[1].data = 0x55;
75         t->program_command[2].address = t->command_5555;
76         t->program_command[2].data = 0xa0;
77 };
78 void flash_cpu_config(const uint8_t *data, uint16_t length)
79 {
80         config_set(data, length, &seqence_cpu);
81 }
82 void flash_ppu_config(const uint8_t *data, uint16_t length)
83 {
84         config_set(data, length, &seqence_ppu);
85 }
86
87 static void program_assign(enum status status, uint16_t address, uint16_t length, const uint8_t *data, struct flash_seqence *t)
88 {
89         if(0 && (t->program_unit != 1) && (t->status == PROGRAM)){ //W29C040 ¤ÎºÆ½ñ¤­¹þ¤ß²ó¿ô¤ò¸º¤é¤·¤Æ¤ß¤ë
90                 t->status = TOGGLE_FIRST;
91         }else{
92                 t->status = status;
93         }
94         t->request = status;
95         t->address = address;
96         t->length = length;
97         t->data = data;
98         t->retry_count = 0;
99 }
100 void flash_cpu_program(uint16_t address, uint16_t length, const uint8_t *data)
101 {
102         program_assign(PROGRAM, address, length, data, &seqence_cpu);
103 }
104 void flash_ppu_program(uint16_t address, uint16_t length, const uint8_t *data)
105 {
106         program_assign(PROGRAM, address, length, data, &seqence_ppu);
107 }
108 #define NULL (0)
109 void flash_cpu_erase(uint16_t address)
110 {
111         //length ¤Ë unit ¤òÅϤ·¤Æ toggle check ¸å IDLE ¤Ë¤Ê¤ë¤è¤¦¤Ë¤¹¤ë
112         program_assign(ERASE, address, seqence_cpu.program_unit, NULL, &seqence_cpu);
113 }
114 void flash_ppu_erase(uint16_t address)
115 {
116         program_assign(ERASE, address, seqence_ppu.program_unit, NULL, &seqence_ppu);
117 }
118
119 //---- command write ----
120 struct flash_command{
121         enum {C2AAA, C5555, END} address;
122         uint8_t data;
123 };
124 static void command_execute(const struct flash_command *c, const struct flash_seqence *const t)
125 {
126         while(c->address != END){
127                 uint16_t addr = 0;
128                 switch(c->address){
129                 case C2AAA:
130                         addr = t->command_2aaa;
131                         break;
132                 case C5555:
133                         addr = t->command_5555;
134                         break;
135                 case END:
136                         return;
137                 }
138                 t->writer(addr, 1, &c->data);
139                 c++;
140         }
141 }
142 static void program(const struct flash_seqence *t)
143 {
144 /*      static const struct flash_command c[] = {
145                 {C5555, 0xaa}, {C2AAA, 0x55}, {C5555, 0xa0}, {END, 0}
146         };
147         command_execute(c, t);*/
148         t->programmer(t->program_command);
149         t->writer(t->address, t->program_unit, t->data);
150 }
151
152 static void erase(const struct flash_seqence *t)
153 {
154         static const struct flash_command c[] = {
155                 {C5555, 0xaa}, {C2AAA, 0x55}, {C5555, 0x80}, 
156                 {C5555, 0xaa}, {C2AAA, 0x55}, {C5555, 0x10}, 
157                 {END, 0}
158         };
159         command_execute(c, t);
160 }
161
162 static void device_get(const struct flash_seqence *t, uint8_t d[2])
163 {
164         static const struct flash_command entry[] = {
165                 {C5555, 0xaa}, {C2AAA, 0x55}, {C5555, 0x90}, {END, 0}
166         };
167         static const struct flash_command exit[] = {
168                 {C5555, 0xaa}, {C2AAA, 0x55}, {C5555, 0xf0}, {END, 0}
169         };
170         command_execute(entry, t);
171         t->reader(t->command_000x, 1, d);
172         command_execute(entry, t);
173         t->reader(t->command_000x + 1, 1, d + 1);
174         command_execute(exit, t);
175 }
176 void flash_cpu_device_get(uint8_t d[2])
177 {
178         device_get(&seqence_cpu, d);
179 }
180 void flash_ppu_device_get(uint8_t d[2])
181 {
182         device_get(&seqence_ppu, d);
183 }
184 //---- status read ----
185 static void toggle_first(struct flash_seqence *t)
186 {
187         t->reader(t->address, 1, &t->toggle);
188         t->toggle &= 0x40;
189 }
190 static void toggle_check(struct flash_seqence *t)
191 {
192         uint8_t d;
193         t->reader(t->address, 1, &d);
194         if(t->toggle == (d & 0x40)){
195                 if((t->retry_enable != 0) && (t->request == PROGRAM) && (t->retry_count < 20)){
196                         if(t->compare(t->address, t->program_unit, t->data) == NG){
197                                 t->retry_count += 1;
198                                 t->status = PROGRAM;
199                                 return;
200                         }
201                 }
202                 t->retry_count = 0;
203                 t->address += t->program_unit;
204                 t->data += t->program_unit;
205                 t->length -= t->program_unit;
206                 if((t->length == 0) || (t->request == ERASE)){
207                         t->status = IDLE;
208                 }else{
209                         t->status = PROGRAM;
210                 }
211         }
212         t->toggle = d & 0x40;
213         if(0 && (d & 0x20)){ //polling DQ5, AM29F040B only
214                 uint8_t d0, d1;
215                 t->reader(t->address, 1, &d0);
216                 t->reader(t->address, 1, &d1);
217                 if((d0 & 0x40) == (d1 & 0x40)){
218                         t->address += t->program_unit;
219                         t->data += t->program_unit;
220                         t->length -= t->program_unit;
221                         if((t->length == 0) || (t->request == ERASE)){
222                                 t->status = IDLE;
223                         }else{
224                                 t->status = PROGRAM;
225                         }
226                 }
227         }
228 }
229
230 static void erase_wait(struct flash_seqence *t)
231 {
232         uint8_t d;
233         t->reader(t->address, 1, &d);
234         if(d == 0xff){
235                 t->status = IDLE;
236         }
237 }
238 //---- task execute ----
239 static void process(struct flash_seqence *s)
240 {
241         switch(s->status){
242         case IDLE:
243                 break;
244         case ERASE:
245                 erase(s);
246                 s->status = ERASE_WAIT;
247                 break;
248         case ERASE_WAIT:
249                 erase_wait(s);
250                 break;
251         case PROGRAM:
252                 if((s->program_unit != 1) || (*(s->data) != 0xff)){
253                         program(s);
254                 }
255                 s->status = TOGGLE_FIRST;
256                 break;
257         case TOGGLE_FIRST:
258                 toggle_first(s);
259                 s->status = TOGGLE_CHECK;
260                 break;
261         case TOGGLE_CHECK:
262                 toggle_check(s); //status is updated by function
263                 break;
264         }
265
266 }
267 void flash_process(void)
268 {
269         //for CPU and PPU dual programming
270         process(&seqence_cpu);
271         process(&seqence_ppu);
272 }