OSDN Git Service

build path を変更
[unagi/old-svn-converted.git] / client / trunk / anago / script_program.c
1 #include <assert.h>
2 #include <string.h>
3 #include <squirrel.h>
4 #include <sqstdio.h>
5 #include <sqstdaux.h>
6 #include <kazzo_task.h>
7 #include "type.h"
8 #include "widget.h"
9 #include "romimage.h"
10 #include "memory_manage.h"
11 #include "reader_master.h"
12 #include "squirrel_wrap.h"
13 #include "flash_device.h"
14 #include "script_common.h"
15 #include "script_program.h"
16
17 static SQInteger vram_mirrorfind(HSQUIRRELVM v)
18 {
19         struct program_config *d;
20         SQRESULT r = SQ_FAILED(qr_userpointer_get(v, (SQUserPointer) &d));
21         if(SQ_FAILED(r)){
22                 return r;
23         }
24         const uint8_t c = d->control->vram_connection(d->handle);
25         if(DEBUG == 1){
26                 d->log.append(d->log.object, wgT("vram connection %x\n"), c);
27         }
28         if((c == 0x0a || c == 0x05) && d->vram_mirroring == MIRROR_VERTICAL){
29                 return 0;
30         }else if((c == 0x0c || c == 0x09) && d->vram_mirroring == MIRROR_HORIZONAL){
31                 return 0;
32         }else{
33                 wgChar cartridge, image;
34                 switch(c){
35                 case 0x05: case 0x0a:
36                         image = wgT('V');
37                         break;
38                 case 0x09: case 0x0c:
39                         image = wgT('H');
40                         break;
41                 default:
42                         image = wgT('?');
43                         break;
44                 }
45                 if(d->vram_mirroring == MIRROR_HORIZONAL){
46                         cartridge = wgT('H');
47                 }else{
48                         cartridge = wgT('V');
49                 }
50                 d->log.append(d->log.object, wgT("warning: vram connection is unmmacted\n"));
51                 d->log.append(d->log.object, wgT("cartridge:%c romimage:%c\n"), cartridge, image);
52         }
53         return 0;
54 }
55 static SQInteger command_set(HSQUIRRELVM v, struct flash_memory_driver *t)
56 {
57         long command, address ,mask;
58         SQRESULT r = qr_argument_get(v, 3, &command, &address, &mask);
59         if(SQ_FAILED(r)){
60                 return r;
61         }
62         long d = command & (mask - 1);
63         d |= address;
64         switch(command){
65         case 0x0000:
66                 t->c000x = d;
67                 break;
68         case 0x02aa: case 0x2aaa:
69                 t->c2aaa = d;
70                 break;
71         case 0x0555: case 0x5555:
72                 t->c5555 = d;
73                 break;
74         default:
75                 return sq_throwerror(v, wgT("unknown command address"));
76         }
77         t->command_change = true;
78         return 0;
79 }
80 static SQInteger cpu_command(HSQUIRRELVM v)
81 {
82         struct program_config *d;
83         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
84         if(SQ_FAILED(r)){
85                 return r;
86         }
87         return command_set(v, &d->cpu);
88 }
89 static SQInteger ppu_command(HSQUIRRELVM v)
90 {
91         struct program_config *d;
92         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
93         if(SQ_FAILED(r)){
94                 return r;
95         }
96         return command_set(v, &d->ppu);
97 }
98
99 static SQInteger cpu_write(HSQUIRRELVM v)
100 {
101         struct program_config *d;
102         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
103         if(SQ_FAILED(r)){
104                 return r;
105         }
106         cpu_write_execute(v, d->handle, d->cpu.access);
107         return 0;
108 }
109
110 static SQInteger erase_set(HSQUIRRELVM v, const struct reader_handle *h, struct flash_memory_driver *t, struct textcontrol *log)
111 {
112         t->access->flash_config(h, t->c000x, t->c2aaa, t->c5555, t->flash.pagesize, t->flash.retry);
113         t->command_change = false;
114         if(t->flash.erase_require == true){
115                 t->access->flash_erase(h, t->c2aaa, false);
116                 t->gauge.label_set(t->gauge.label, wgT("erasing "));
117         }
118         return 0;
119 }
120 static SQInteger cpu_erase(HSQUIRRELVM v)
121 {
122         struct program_config *d;
123         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
124         if(SQ_FAILED(r)){
125                 return r;
126         }
127         return erase_set(v, d->handle, &d->cpu, &d->log);
128 }
129 static SQInteger ppu_erase(HSQUIRRELVM v)
130 {
131         struct program_config *d;
132         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
133         if(SQ_FAILED(r)){
134                 return r;
135         }
136         return erase_set(v, d->handle, &d->ppu, &d->log);
137 }
138 static SQInteger program_regist(HSQUIRRELVM v, const struct reader_handle *h, struct flash_memory_driver *t)
139 {
140         SQRESULT r = qr_argument_get(v, 2, &t->programming.address, &t->programming.length);
141         if(SQ_FAILED(r)){
142                 return r;
143         }
144         t->compare = t->programming;
145         t->compare.offset = t->memory.offset & (t->memory.size - 1);
146         if(t->command_change == true){
147                 t->access->flash_config(
148                         h, t->c000x, t->c2aaa, t->c5555, 
149                         t->flash.pagesize, t->flash.retry
150                 );
151                 t->command_change = false;
152         }
153         
154         return sq_suspendvm(v);
155 }
156
157 static void program_execute(const struct reader_handle *h, struct flash_memory_driver *t)
158 {
159         const long w = t->access->flash_program(
160                 h, &t->gauge, 
161                 t->programming.address, t->programming.length, 
162                 t->memory.data + t->memory.offset, false, 
163                 t->flash.erase_require
164         );
165         t->programming.address += w;
166         t->programming.length -= w;
167         t->memory.offset += w;
168         t->memory.offset &= t->memory.size - 1;
169         t->programming.offset += w;
170 }
171
172 static bool program_compare(const struct reader_handle *h, struct flash_memory_driver *t)
173 {
174         uint8_t *comparea = Malloc(t->compare.length);
175         bool ret = false;
176         if(t->flash.erase_require == true){
177                 memset(comparea, 0xff, t->compare.length);
178                 int doread = memcmp(comparea, t->memory.data + t->compare.offset, t->compare.length);
179                 if(0){
180                         memset(comparea, 0, t->compare.length);
181                         doread &= memcmp(comparea, t->memory.data + t->compare.offset, t->compare.length);
182                 }
183                 if(doread == 0){
184                         Free(comparea);
185                         return true;
186                 }
187         }
188         
189         t->access->memory_read(h, &GAUGE_DUMMY, t->compare.address, t->compare.length, comparea);
190         if(memcmp(comparea, t->memory.data + t->compare.offset, t->compare.length) == 0){
191                 ret = true;
192         }
193         Free(comparea);
194         return ret;
195 }
196 static SQInteger cpu_program_memory(HSQUIRRELVM v)
197 {
198         struct program_config *d;
199         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
200         if(SQ_FAILED(r)){
201                 return r;
202         }
203         return program_regist(v, d->handle, &d->cpu);
204 }
205 static SQInteger ppu_program_memory(HSQUIRRELVM v)
206 {
207         struct program_config *d;
208         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
209         if(SQ_FAILED(r)){
210                 return r;
211         }
212         return program_regist(v, d->handle, &d->ppu);
213 }
214
215 static long erase_timer_get(const struct reader_handle *h, struct flash_memory_driver *t)
216 {
217         if(
218                 (t->memory.transtype != TRANSTYPE_EMPTY) && 
219                 (t->flash.erase_require == true)
220         ){
221                 return t->flash.erase_wait;
222         }else{
223                 return 0;
224         }
225 }
226 static SQInteger erase_wait(HSQUIRRELVM v)
227 {
228         struct program_config *d;
229         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
230         if(SQ_FAILED(r)){
231                 return r;
232         }
233         if(0){
234                 long timer_wait = erase_timer_get(d->handle, &d->cpu);
235                 long timer_ppu = erase_timer_get(d->handle, &d->ppu);
236                 if(timer_wait < timer_ppu){
237                         timer_wait = timer_ppu;
238                 }
239                 wait(timer_wait);
240         }else{
241                 uint8_t s[2];
242                 do{
243                         wait(2);
244                         d->control->flash_status(d->handle, s);
245                 //本来の意図からではここの条件式は && ではなく || だが、先に erase が終わったデバイスが動かせるので残しておく
246                 }while((s[0] != KAZZO_TASK_FLASH_IDLE) && (s[1] != KAZZO_TASK_FLASH_IDLE));
247         }
248         return 0;
249 }
250
251 static void gauge_init(struct flash_memory_driver *t)
252 {
253         t->gauge.range_set(t->gauge.bar, t->programming.count);
254
255         t->gauge.value_set(t->gauge.bar, t->gauge.label, 0);
256 }
257
258 static bool program_memoryarea(HSQUIRRELVM co, const struct reader_handle *h, struct flash_memory_driver *t, bool compare, SQInteger *state, struct textcontrol *log)
259 {
260         if(t->programming.length == 0){
261                 if(t->programming.offset != 0 && compare == true){
262                         if(program_compare(h, t) == false){
263                                 log->append(log->object, wgT("%s memory compare failed, offset 0x%06x\n"), t->memory.name, t->programming.offset);
264                                 return false;
265                         }
266                 }
267
268                 sq_wakeupvm(co, SQFalse, SQFalse, SQTrue, SQFalse);
269                 *state = sq_getvmstate(co);
270         }else{
271                 program_execute(h, t);
272         }
273         return true;
274 }
275
276 static SQInteger program_main(HSQUIRRELVM v)
277 {
278         if(sq_gettop(v) != (1 + 3)){ //roottable, userpointer, co_cpu, co_ppu
279                 return sq_throwerror(v, wgT("argument number error"));
280         }
281         struct program_config *d;
282         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
283         if(SQ_FAILED(r)){
284                 return r;
285         }
286         HSQUIRRELVM co_cpu, co_ppu;
287         if(SQ_FAILED(sq_getthread(v, 3, &co_cpu))){
288                 return sq_throwerror(v, wgT("thread error"));
289         }
290         if(SQ_FAILED(sq_getthread(v, 4, &co_ppu))){
291                 return sq_throwerror(v, wgT("thread error"));
292         }
293         SQInteger state_cpu = sq_getvmstate(co_cpu);
294         SQInteger state_ppu = sq_getvmstate(co_ppu);
295         const long sleepms = d->compare == true ? 6 : 2; //W29C040 で compare をすると、error が出るので出ない値に調整 (やっつけ対応)
296         
297         while((state_cpu != SQ_VMSTATE_IDLE) || (state_ppu != SQ_VMSTATE_IDLE)){
298                 uint8_t s[2];
299                 wait(sleepms);
300                 d->control->flash_status(d->handle, s);
301                 if(state_cpu != SQ_VMSTATE_IDLE && s[0] == KAZZO_TASK_FLASH_IDLE){
302                         if(program_memoryarea(co_cpu, d->handle, &d->cpu, d->compare, &state_cpu, &d->log) == false){
303                                 //sq_pushbool(v, SQFalse);
304                                 return 0;
305                         }
306                 }
307                 if(state_ppu != SQ_VMSTATE_IDLE && s[1] == KAZZO_TASK_FLASH_IDLE){
308                         if(program_memoryarea(co_ppu, d->handle, &d->ppu, d->compare, &state_ppu, &d->log) == false){
309                                 //sq_pushbool(v, SQFalse);
310                                 return 0;
311                         }
312                 }
313         }
314         //sq_pushbool(v, SQTrue);
315         return 0;
316 }
317
318 static SQInteger program_count(HSQUIRRELVM v, struct flash_memory_driver *t, const struct range *range_address, const struct range *range_length, struct textcontrol *log)
319 {
320         SQRESULT r = qr_argument_get(v, 2, &t->programming.address, &t->programming.length);
321         if(SQ_FAILED(r)){
322                 return r;
323         }
324         r = range_check(v, wgT("length"), t->programming.length, range_length);
325         if(SQ_FAILED(r)){
326                 return r;
327         }
328         if((t->programming.address < range_address->start) || ((t->programming.address + t->programming.length) > range_address->end)){
329                 log->append(log->object, wgT("address range must be 0x%06x to 0x%06x"), (int) range_address->start, (int) range_address->end - 1);
330                 return sq_throwerror(v, wgT("script logical error"));
331         }
332         t->programming.count += t->programming.length;
333         return 0;
334 }
335 static SQInteger cpu_program_count(HSQUIRRELVM v)
336 {
337         static const struct range range_address = {0x8000, 0x10000};
338         static const struct range range_length = {0x0100, 0x4000};
339         struct program_config *d;
340         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
341         if(SQ_FAILED(r)){
342                 return r;
343         }
344         return program_count(v, &d->cpu, &range_address, &range_length, &d->log);
345 }
346
347 static SQInteger ppu_program_count(HSQUIRRELVM v)
348 {
349         static const struct range range_address = {0x0000, 0x2000};
350         static const struct range range_length = {0x0100, 0x2000};
351         struct program_config *d;
352         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
353         if(SQ_FAILED(r)){
354                 return r;
355         }
356         return program_count(v, &d->ppu, &range_address, &range_length, &d->log);
357 }
358
359 static bool script_execute(HSQUIRRELVM v, const wgChar *function, struct program_config *c)
360 {
361         bool ret = true;
362         if(SQ_FAILED(sqstd_dofile(v, _SC("programcore.nut"), SQFalse, SQTrue))){
363                 c->log.append(c->log.object, wgT("flash core script error\n"));
364                 ret = false;
365         }else{
366                 SQRESULT r = qr_call(
367                         v, function, (SQUserPointer) c, c->script,
368                         1 + 3 * 2, c->mappernum, 
369                         c->cpu.memory.transtype, c->cpu.memory.size, c->cpu.flash.capacity,
370                         c->ppu.memory.transtype, c->ppu.memory.size, c->cpu.flash.capacity
371                 );
372                 if(SQ_FAILED(r)){
373                         ret = false;
374                 }
375         }
376         return ret;
377 }
378
379 static bool zendan(struct program_config *c)
380 {
381 //script test run
382         {
383                 static const wgChar *functionname[] = {
384                         wgT("cpu_erase"), wgT("ppu_erase"),
385                         wgT("erase_wait"), wgT("program_main")
386                 };
387                 HSQUIRRELVM v = qr_open(&c->log);
388                 int i;
389                 for(i = 0; i < sizeof(functionname)/sizeof(wgChar *); i++){
390                         qr_function_register_global(v, functionname[i], script_nop);
391                 }
392                 qr_function_register_global(v, _SC("cpu_write"), cpu_write_check);
393                 qr_function_register_global(v, _SC("cpu_command"), cpu_command);
394                 qr_function_register_global(v, _SC("cpu_program"), cpu_program_count);
395                 
396                 qr_function_register_global(v, _SC("ppu_program"), ppu_program_count);
397                 qr_function_register_global(v, _SC("ppu_command"), ppu_command);
398                 qr_function_register_global(v, _SC("vram_mirrorfind"), vram_mirrorfind);
399                 
400                 if(script_execute(v, wgT("testrun"), c) == false){
401                         qr_close(v);
402                         return false;
403                 }
404                 qr_close(v);
405                 assert(c->cpu.memory.size != 0);
406
407                 if(c->cpu.programming.count % c->cpu.memory.size  != 0){
408                         c->log.append(c->log.object, wgT("logical error: cpu_programsize is not connected 0x%06x/0x%06x\n"), (int) c->cpu.programming.count, (int) c->cpu.memory.size);
409                         return false;
410                 }
411                 if(c->ppu.memory.size != 0){
412                         if(c->ppu.programming.count % c->ppu.memory.size != 0){
413                                 c->log.append(c->log.object, wgT("logical error: ppu_programsize is not connected 0x%06x/0x%06x\n"), (int) c->ppu.programming.count, (int) c->ppu.memory.size);
414                                 return false;
415                         }
416                 }
417         }
418 //script execute 
419         //SQBool ret;
420         c->cpu.command_change = true;
421         gauge_init(&c->cpu);
422         c->ppu.command_change = true;
423         gauge_init(&c->ppu);
424         {
425                 HSQUIRRELVM v = qr_open(&c->log); 
426                 qr_function_register_global(v, _SC("cpu_write"), cpu_write);
427                 qr_function_register_global(v, _SC("cpu_erase"), cpu_erase);
428                 qr_function_register_global(v, _SC("cpu_program"), cpu_program_memory);
429                 qr_function_register_global(v, _SC("cpu_command"), cpu_command);
430                 qr_function_register_global(v, _SC("ppu_erase"), ppu_erase);
431                 qr_function_register_global(v, _SC("ppu_program"), ppu_program_memory);
432                 qr_function_register_global(v, _SC("ppu_command"), ppu_command);
433                 qr_function_register_global(v, _SC("program_main"), program_main);
434                 qr_function_register_global(v, _SC("erase_wait"), erase_wait);
435                 qr_function_register_global(v, _SC("vram_mirrorfind"), script_nop);
436                 script_execute(v, wgT("program"), c);
437                 //assert(sq_gettype(v, -2) == OT_BOOL);
438                 //sq_getbool(v, -1, &ret);
439                 qr_close(v);
440         }
441         return true; //ret == SQTrue ? true : false;
442 }
443
444 static bool memory_image_init(const struct memory *from, struct flash_memory_driver *t, struct textcontrol *log)
445 {
446         t->memory.data = from->data;
447         t->memory.size = from->size;
448         t->memory.attribute = MEMORY_ATTR_READ;
449         t->command_change = true;
450         t->programming.count = 0;
451         t->programming.offset = 0;
452         if(t->memory.size == 0){
453                 t->memory.transtype = TRANSTYPE_EMPTY;
454         }
455         if(t->flash.capacity < from->size){
456                 log->append(log->object, t->memory.name);
457                 
458                 log->append(log->object, wgT(" image size is larger than target device"));
459                 return false;
460         }
461         return true;
462 }
463
464 bool script_program_execute(struct program_config *c)
465 {
466 //rom image load
467         struct romimage rom;
468         if(nesfile_load(&c->log, c->target, &rom) == false){
469                 c->log.append(c->log.object, wgT("ROM image open error"));
470                 return false;
471         }
472 //variable init
473         c->mappernum = rom.mappernum;
474         c->vram_mirroring = rom.mirror;
475         c->cpu.memory.name = wgT("Program Flash");
476         if(memory_image_init(&rom.cpu_rom, &c->cpu, &c->log) == false){
477                 nesbuffer_free(&rom, 0);
478                 return false;
479         }
480         c->ppu.memory.name = wgT("Charcter Flash");
481         if(memory_image_init(&rom.ppu_rom, &c->ppu, &c->log) == false){
482                 nesbuffer_free(&rom, 0);
483                 return false;
484         }
485 //reader initalize
486         c->handle = c->control->open(c->except, &c->log);
487         if(c->handle == NULL){
488                 c->log.append(c->log.object, wgT("reader open error\n"));
489                 nesbuffer_free(&rom, 0);
490                 return false;
491         }
492 //program start, reader finalize
493         if(connection_check(c->handle, &c->log, c->cpu.access, c->ppu.access) == false){
494                 nesbuffer_free(&rom, 0);
495                 c->control->close(c->handle);
496                 return false;
497         }
498         bool ret = zendan(c);
499         c->control->close(c->handle);
500         c->handle = NULL;
501         nesbuffer_free(&rom, 0);
502         return ret;
503 }