OSDN Git Service

vram mirroring の判定値を修正
[unagi/old-svn-converted.git] / client / trunk / anago / script_dump.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <squirrel.h>
5 #include <sqstdio.h>
6 #include <sqstdaux.h>
7 #include "type.h"
8 #include "file.h"
9 #include "widget.h"
10 #include "romimage.h"
11 #include "memory_manage.h"
12 #include "reader_master.h"
13 #include "squirrel_wrap.h"
14 #include "script_common.h"
15 #include "script_dump.h"
16
17 static SQInteger cpu_write(HSQUIRRELVM v)
18 {
19         struct dump_config *d;
20
21         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
22         if(SQ_FAILED(r)){
23                 return r;
24         }
25         cpu_write_execute(v, d->handle, d->cpu.access);
26         return 0;
27 }
28
29 //ここの printf は debug 用に残しておく
30 static void buffer_show(struct memory *t, long length)
31 {
32         int i;
33         const uint8_t *buf = t->data + t->offset;
34 #ifdef _UNICODE
35         wprintf(L"%s 0x%06x:", t->name, t->offset);
36 #else
37         printf("%s 0x%06x:", t->name, t->offset);
38 #endif
39         for(i = 0; i < 0x10; i++){
40                 wgChar dump[3+1];
41 #ifdef _UNICODE
42                 //wsprintf(dump, L"%02x", buf[i]);
43 #else
44                 sprintf(dump, "%02x", buf[i]);
45 #endif
46                 switch(i){
47                 case 7:
48                         dump[2] = wgT('-');
49                         break;
50                 case 0x0f:
51                         dump[2] = wgT('\0');
52                         break;
53                 default:
54                         dump[2] = wgT(' ');
55                         break;
56                 }
57                 dump[3] = wgT('\0');
58 #ifdef _UNICODE
59                 wprintf(L"%s", dump);
60 #else
61                 printf("%s", dump);
62 #endif
63         }
64         int sum = 0;
65         while(length != 0){
66                 sum += (int) *buf;
67                 buf++;
68                 length--;
69         }
70 #ifdef _UNICODE
71         wprintf(L":0x%06x\n", sum);
72 #else
73         printf(":0x%06x\n", sum);
74 #endif
75         fflush(stdout);
76 }
77
78 static SQInteger read_memory(HSQUIRRELVM v, const struct reader_handle *h, struct dump_memory_driver *t, bool progress)
79 {
80         long address, length;
81         SQRESULT r = qr_argument_get(v, 2, &address, &length);
82         if(SQ_FAILED(r)){
83                 return r;
84         }
85         assert(t->memory.attribute == MEMORY_ATTR_WRITE);
86         t->access->memory_read(h, &t->gauge, address, length == 0 ? 1: length, t->memory.data + t->memory.offset);
87         if((length != 0) && (progress == false)){
88                 buffer_show(&t->memory, length);
89         }
90         t->memory.offset += length;
91         return 0;
92 }
93
94 static SQInteger cpu_read(HSQUIRRELVM v)
95 {
96         struct dump_config *d;
97         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
98         if(SQ_FAILED(r)){
99                 return r;
100         }
101         r = read_memory(v, d->handle, &d->cpu, d->progress);
102         return r;
103 }
104
105 static SQInteger ppu_read(HSQUIRRELVM v)
106 {
107         struct dump_config *d;
108         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
109         if(SQ_FAILED(r)){
110                 return r;
111         }
112         r = read_memory(v, d->handle, &d->ppu, d->progress);
113         return r;
114 }
115
116 static SQInteger ppu_ramfind(HSQUIRRELVM v)
117 {
118         struct dump_config *d;
119         enum{
120                 testsize = 8,
121                 testaddress = 1234
122         };
123         static const uint8_t test_val[testsize] = {0xaa, 0x55, 0, 0xff, 0x46, 0x49, 0x07, 0x21};
124         static const uint8_t test_str[testsize] = "pputest";
125         uint8_t test_result[testsize];
126         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
127         struct dump_memory_driver *p = &d->ppu;
128
129         if(SQ_FAILED(r)){
130                 return r;
131         }
132         p->access->memory_write(d->handle, testaddress, testsize, test_val);
133         p->access->memory_read(d->handle, &GAUGE_DUMMY, testaddress, testsize, test_result);
134         if(memcmp(test_val, test_result, testsize) != 0){
135                 sq_pushbool(v, SQFalse);
136                 return 1;
137         }
138         p->access->memory_write(d->handle, testaddress, testsize, test_str);
139         p->access->memory_read(d->handle, &GAUGE_DUMMY, testaddress, testsize, test_result);
140         if(memcmp(test_str, test_result, testsize) != 0){
141                 sq_pushbool(v, SQFalse);
142                 return 1;
143         }
144         p->memory.offset = 0;
145         p->memory.size = 0;
146         sq_pushbool(v, SQTrue);
147         return 1;
148 }
149
150 static SQInteger return_true(HSQUIRRELVM v)
151 {
152         sq_pushbool(v, SQFalse);
153         return 1;
154 }
155
156 static void memory_new_init(struct dump_memory_driver *d)
157 {
158         d->memory.offset = 0;
159         d->memory.data = Malloc(d->memory.size);
160         d->gauge.range_set(d->gauge.bar, d->memory.size);
161         d->gauge.value_set(d->gauge.bar, d->gauge.label, 0);
162 }
163
164 //test 時/1度目の call で使用
165 static SQInteger memory_new(HSQUIRRELVM v)
166 {
167         struct dump_config *d;
168         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
169         if(SQ_FAILED(r)){
170                 return r;
171         }
172         r = qr_argument_get(v, 2, &d->cpu.memory.size, &d->ppu.memory.size);
173         if(SQ_FAILED(r)){
174                 return r;
175         }
176
177         memory_new_init(&d->cpu);
178         if(d->mode == MODE_ROM_DUMP){
179                 memory_new_init(&d->ppu);
180         }
181         return 0;
182 }
183
184 //dump 時/2度目の call で nesfile_save として使用
185 static SQInteger nesfile_save(HSQUIRRELVM v)
186 {
187         struct dump_config *d;
188         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
189         if(SQ_FAILED(r)){
190                 return r;
191         }
192         struct romimage image;
193         long mirrorfind;
194         r = qr_argument_get(v, 2, &image.mappernum, &mirrorfind);
195         if(SQ_FAILED(r)){
196                 return r;
197         }
198         image.cpu_rom = d->cpu.memory;
199         image.cpu_ram.data = NULL;
200         image.ppu_rom = d->ppu.memory;
201         image.mirror = MIRROR_PROGRAMABLE;
202         if(mirrorfind == 1){
203                 uint8_t c = d->control->vram_connection(d->handle);
204                 if(DEBUG == 1){
205                         d->log.append(d->log.object, wgT("vram connection %x\n"), c);
206                 }
207                 if(c == 0x0a){
208                         image.mirror = MIRROR_VERTICAL;
209                 }else{
210                         image.mirror = MIRROR_HORIZONAL;
211                 }
212         }
213         image.backupram = 0;
214         if(d->battery == true){
215                 image.backupram = 1;
216         }
217         d->crc = nesfile_create(&d->log, &image, d->target);
218         nesbuffer_free(&image, 0); //0 is MODE_xxx_xxxx
219         
220         d->cpu.memory.data = NULL;
221         d->ppu.memory.data = NULL;
222         return 0;
223 }
224
225 //dump 時/1度目の call で nesfile_save として使用
226 static SQInteger length_check(HSQUIRRELVM v)
227 {
228         struct dump_config *d;
229         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
230         if(SQ_FAILED(r)){
231                 return r;
232         }
233         bool cpu = true, ppu = true;
234         r = 0;
235         if(d->cpu.memory.size != d->cpu.read_count){
236                 cpu = false;
237         }
238         if(cpu == false){
239                 d->log.append(d->log.object, wgT("cpu_romsize is not connected 0x%06x/0x%06x\n"), (int) d->cpu.read_count, (int) d->cpu.memory.size);
240         }
241         if(d->ppu.memory.size != d->ppu.read_count){
242                 ppu = false;
243         }
244         if(ppu == false){
245                 d->log.append(d->log.object, wgT("ppu_romsize is not connected 0x%06x/0x%06x\n"), (int) d->ppu.read_count, (int) d->ppu.memory.size);
246         }
247         if(cpu == false || ppu == false){
248                 r = sq_throwerror(v, wgT("script logical error"));
249         }
250         return r;
251 }
252
253 static SQInteger read_count(HSQUIRRELVM v, const struct textcontrol *l, struct dump_memory_driver *t, const struct range *range_address, const struct range *range_length)
254 {
255         long address, length;
256         SQRESULT r = qr_argument_get(v, 2, &address, &length);
257         if(SQ_FAILED(r)){
258                 return r;
259         }
260         r = range_check(v, wgT("length"), length, range_length);
261         if(SQ_FAILED(r)){
262                 return r;
263         }
264         if((address < range_address->start) || ((address + length) > range_address->end)){
265                 l->append(l->object, wgT("address range must be 0x%06x to 0x%06x"), (int) range_address->start, (int) range_address->end);
266                 return sq_throwerror(v, wgT("script logical error"));;
267         }
268         t->read_count += length;
269         return 0;
270 }
271 static SQInteger cpu_read_count(HSQUIRRELVM v)
272 {
273         static const struct range range_address = {0x8000, 0x10000};
274         //length == 0 は 対象アドレスを呼んで、バッファにいれない。mmc2, mmc4 で使用する。
275         static const struct range range_length = {0x0000, 0x4000};
276         struct dump_config *d;
277         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
278         if(SQ_FAILED(r)){
279                 return r;
280         }
281         return read_count(v, &d->log, &d->cpu, &range_address, &range_length);
282 }
283
284 static SQInteger ppu_read_count(HSQUIRRELVM v)
285 {
286         static const struct range range_address = {0x0000, 0x2000};
287         static const struct range range_length = {0x0001, 0x2000};
288         struct dump_config *d;
289         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
290         if(SQ_FAILED(r)){
291                 return r;
292         }
293         return read_count(v, &d->log, &d->ppu, &range_address, &range_length);
294 }
295
296 static SQInteger memory_size_set(HSQUIRRELVM v)
297 {
298         struct dump_config *d;
299         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
300         if(SQ_FAILED(r)){
301                 return r;
302         }
303         r = qr_argument_get(v, 2, &d->cpu.memory.size, &d->ppu.memory.size);
304         return r;
305 }
306
307 static bool script_execute(HSQUIRRELVM v, struct dump_config *d)
308 {
309         bool ret = true;
310         if(SQ_FAILED(sqstd_dofile(v, wgT("dumpcore.nut"), SQFalse, SQTrue))){
311                 d->log.append(d->log.object, wgT("dump core script error\n"));
312                 ret = false;
313         }else{
314                 SQRESULT r = qr_call(
315                         v, wgT("dump"), (SQUserPointer) d, d->script, 
316                         3, d->mappernum, d->cpu.increase, d->ppu.increase
317                 );
318                 if(SQ_FAILED(r)){
319                         ret = false;
320                         Free(d->cpu.memory.data);
321                         Free(d->ppu.memory.data);
322                         d->cpu.memory.data = NULL;
323                         d->ppu.memory.data = NULL;
324                 }
325         }
326         return ret;
327 }
328
329 static void dump_memory_driver_init(struct dump_memory_driver *dd, enum memory_attribute at)
330 {
331         dd->memory.size = 0;
332         dd->memory.offset = 0;
333         dd->memory.attribute = at;
334         dd->memory.transtype = TRANSTYPE_FULL;
335         dd->memory.data = NULL;
336         dd->read_count = 0;
337 }
338
339 bool script_dump_execute(struct dump_config *d)
340 {
341         dump_memory_driver_init(&d->cpu, MEMORY_ATTR_WRITE);
342         d->cpu.memory.name = wgT("Program");
343         
344         dump_memory_driver_init(&d->ppu, MEMORY_ATTR_WRITE);
345         d->ppu.memory.name = wgT("Charcter");
346         
347         {
348                 HSQUIRRELVM v = qr_open(&d->log);
349                 qr_function_register_global(v, wgT("cpu_write"), cpu_write_check);
350                 qr_function_register_global(v, wgT("memory_new"), memory_size_set);
351                 qr_function_register_global(v, wgT("nesfile_save"), length_check);
352                 qr_function_register_global(v, wgT("cpu_read"), cpu_read_count);
353                 qr_function_register_global(v, wgT("ppu_read"), ppu_read_count);
354                 qr_function_register_global(v, wgT("ppu_ramfind"), return_true);
355                 if(script_execute(v, d) == false){
356                         qr_close(v);
357                         return false;
358                 }
359                 qr_close(v);
360         }
361
362         d->handle = d->control->open(d->except, &d->log);
363         if(d->handle == NULL){
364                 d->log.append(d->log.object, wgT("reader open error\n"));
365                 return false;
366         }
367         d->control->init(d->handle);
368         if(connection_check(d->handle, &d->log, d->cpu.access, d->ppu.access) == false){
369                 d->control->close(d->handle);
370                 return false;
371         }
372         {
373                 HSQUIRRELVM v = qr_open(&d->log); 
374                 qr_function_register_global(v, wgT("memory_new"), memory_new);
375                 qr_function_register_global(v, wgT("nesfile_save"), nesfile_save);
376                 qr_function_register_global(v, wgT("cpu_write"), cpu_write);
377                 qr_function_register_global(v, wgT("cpu_read"), cpu_read);
378                 qr_function_register_global(v, wgT("ppu_read"), ppu_read);
379                 qr_function_register_global(v, wgT("ppu_ramfind"), ppu_ramfind);
380                 script_execute(v, d);
381                 qr_close(v);
382         }
383         d->control->close(d->handle);
384         d->handle = NULL;
385         return true;
386 }
387
388 static bool workram_execute(HSQUIRRELVM v, struct dump_config *d)
389 {
390         bool ret = true;
391         if(SQ_FAILED(sqstd_dofile(v, wgT("dumpcore.nut"), SQFalse, SQTrue))){
392                 d->log.append(d->log.object, wgT("dump core script error\n"));
393                 ret = false;
394         }else{
395                 SQRESULT r = qr_call(
396                         v, wgT("workram_rw"), (SQUserPointer) d, d->script, 
397                         1, d->cpu.increase
398                 );
399                 if(SQ_FAILED(r)){
400                         ret = false;
401                         Free(d->cpu.memory.data);
402                         d->cpu.memory.data = NULL;
403 //                      Free(d->ppu.memory.data);
404 //                      d->ppu.memory.data = NULL;
405                 }
406         }
407         return ret;
408 }
409
410 static SQInteger cpu_ramrw_check(HSQUIRRELVM v)
411 {
412         static const struct range range_address = {0x6000, 0xdfff};
413         static const struct range range_length = {1, 0x2000};
414         struct dump_config *d;
415         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
416         if(SQ_FAILED(r)){
417                 return r;
418         }
419         return read_count(v, &d->log, &d->cpu, &range_address, &range_length);
420 }
421
422 static SQInteger ramimage_open(HSQUIRRELVM v)
423 {
424         struct dump_config *d;
425         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
426         if(SQ_FAILED(r)){
427                 return r;
428         }
429         if(buf_load(d->cpu.memory.data, d->target, d->cpu.memory.size) == NG){
430                 return r = sq_throwerror(v, wgT("RAM image open error"));
431         }
432         return 0;
433 }
434
435 static SQInteger memory_finalize(HSQUIRRELVM v)
436 {
437         struct dump_config *d;
438         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
439         if(SQ_FAILED(r)){
440                 return r;
441         }
442         if(d->mode == MODE_RAM_READ){
443                 buf_save(d->cpu.memory.data, d->target, d->cpu.memory.size);
444         }
445         Free(d->cpu.memory.data);
446         d->cpu.memory.data = NULL;
447 //      Free(d->ppu.memory.data);
448 //      d->ppu.memory.data = NULL;
449         
450         return 0;
451 }
452
453 static SQInteger cpu_write_ramimage(HSQUIRRELVM v)
454 {
455         struct dump_config *d;
456         SQRESULT r =  qr_userpointer_get(v, (SQUserPointer) &d);
457         if(SQ_FAILED(r)){
458                 return r;
459         }
460
461         long address, length;
462         uint8_t *cmp;
463         const uint8_t *writedata = d->cpu.memory.data;
464         writedata += d->cpu.memory.offset;
465         
466         r = qr_argument_get(v, 2, &address, &length);
467         if(SQ_FAILED(r)){
468                 return r;
469         }
470         cmp = Malloc(length);
471         assert(d->cpu.memory.attribute == MEMORY_ATTR_READ);
472         //&d->cpu.gauge, 
473         d->cpu.access->memory_write(
474                 d->handle, address, length, writedata
475         );
476         d->cpu.access->memory_read(
477                 d->handle, &d->cpu.gauge, address, length, cmp
478         );
479         d->cpu.memory.offset += length;
480
481         r = memcmp(cmp, writedata, length);
482         Free(cmp);
483         if(r != 0){
484                 r = sq_throwerror(v, wgT("memory write failed"));
485         }
486         return 0;
487 }
488
489 bool script_workram_execute(struct dump_config *d)
490 {
491         dump_memory_driver_init(&d->cpu, d->mode == MODE_RAM_READ ? MEMORY_ATTR_WRITE : MEMORY_ATTR_READ);
492         dump_memory_driver_init(&d->ppu, MEMORY_ATTR_NOTUSE);
493         d->cpu.memory.name = wgT("Workram");
494         d->ppu.memory.name = wgT("N/A");
495
496         {
497                 HSQUIRRELVM v = qr_open(&d->log);
498                 qr_function_register_global(v, wgT("memory_new"), memory_new);
499                 qr_function_register_global(v, wgT("cpu_write"), cpu_write_check);
500                 qr_function_register_global(v, wgT("cpu_ramrw"), cpu_ramrw_check);
501                 qr_function_register_global(v, wgT("memory_finalize"), length_check);
502                 if(workram_execute(v, d) == false){
503                         qr_close(v);
504                         return false;
505                 }
506                 qr_close(v);
507         }
508         
509         d->handle = d->control->open(d->except, &d->log);
510         if(d->handle == NULL){
511                 d->log.append(d->log.object, wgT("reader open error\n"));
512                 return false;
513         }
514         d->control->init(d->handle);
515         if(connection_check(d->handle, &d->log, d->cpu.access, d->ppu.access) == false){
516                 d->control->close(d->handle);
517                 return false;
518         }
519         {
520                 HSQUIRRELVM v = qr_open(&d->log); 
521                 qr_function_register_global(v, wgT("cpu_write"), cpu_write);
522                 switch(d->mode){
523                 case MODE_RAM_READ:
524                         qr_function_register_global(v, wgT("memory_new"), script_nop);
525                         qr_function_register_global(v, wgT("cpu_ramrw"), cpu_read);
526                         break;
527                 case MODE_RAM_WRITE:
528                         qr_function_register_global(v, wgT("memory_new"), ramimage_open);
529                         qr_function_register_global(v, wgT("cpu_ramrw"), cpu_write_ramimage);
530                         break;
531                 default:
532                         assert(0);
533                         break;
534                 }
535                 qr_function_register_global(v, wgT("memory_finalize"), memory_finalize);
536                 workram_execute(v, d);
537                 qr_close(v);
538         }
539         d->control->close(d->handle);
540         d->handle = NULL;
541         return true;
542 }