OSDN Git Service

コマンドラインオプションの充実化
[unagi/old-svn-converted.git] / client / trunk / script.c
1 /*
2 famicom ROM cartridge dump program - unagi
3 script engine
4
5 todo: 
6 * Ê̤ÎÆɤ߽Ф·¥Ï¡¼¥É¤ËÂбþ¤·¤¿¤È¤­¤Ï cpu_read ¤Ê¤É¤ò´Ø¿ô¥Ý¥¤¥ó¥¿¤Ë¤Þ¤È¤á¤¿ struct ¤òÍÑ°Õ¤·¤Æ¼Â¹Ô¤¹¤ë
7 * ÊÑ¿ô´ÉÍý¤Î¥°¥í¡¼¥Ð¥ëÃͤò¡¢logical_test(), excute() ¥í¡¼¥«¥ë¤Ë¤·¤¿¤¤
8 * RAM ¥¢¥¯¥»¥¹¤¬¤Ç¤­¼¡Âè¡¢RAM Æɤ߽Ф·¥¹¥¯¥ê¥×¥È¤âÀ߷פ¹¤ë
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include "type.h"
14 #include "file.h"
15 #include "driver_master.h"
16 #include "giveio.h"
17 #include "textutil.h"
18 #include "header.h"
19 #include "script.h"
20
21 #define OP_PPU_WRITE_ENABLE (0)
22 /*
23 MAPPER num
24 MIRROR [HV]
25 CPU_ROMSIZE num
26 CPU_RAMSIZE num
27 PPU_ROMSIZE num
28 DUMP_START
29 CPU_READ address size
30 CPU_WRITE address data -> ÊÑ¿ôŸ³«+±é»»»Ò»ÈÍѲÄǽ
31 PPU_READ address size
32 STEP_START variable start end step -> for(i=start;i<end;i+=step)
33 STEP_END
34 DUMP_END
35 */
36 struct script_syntax{
37         const char *name;
38         int script_opcode;
39         int argc, compare;
40         int argv_type[4];
41 };
42 enum{
43         SYNTAX_ARGVTYPE_NULL,
44         SYNTAX_ARGVTYPE_VALUE,
45         SYNTAX_ARGVTYPE_HV,
46         SYNTAX_ARGVTYPE_EXPRESSION,
47         SYNTAX_ARGVTYPE_VARIABLE
48 };
49 enum{
50         SYNTAX_COMPARE_EQ,
51         SYNTAX_COMPARE_GT
52 };
53 enum{
54         SCRIPT_OPCODE_MAPPER,
55         SCRIPT_OPCODE_MIRROR,
56         SCRIPT_OPCODE_CPU_ROMSIZE,
57         SCRIPT_OPCODE_CPU_RAMSIZE,
58         SCRIPT_OPCODE_PPU_ROMSIZE,
59         SCRIPT_OPCODE_DUMP_START,
60         SCRIPT_OPCODE_CPU_READ,
61         SCRIPT_OPCODE_CPU_WRITE,
62         SCRIPT_OPCODE_CPU_RAMRW,
63         SCRIPT_OPCODE_PPU_RAMTEST,
64         SCRIPT_OPCODE_PPU_READ,
65         SCRIPT_OPCODE_PPU_WRITE,
66         SCRIPT_OPCODE_STEP_START,
67         SCRIPT_OPCODE_STEP_END,
68         SCRIPT_OPCODE_DUMP_END,
69         SCRIPT_OPCODE_COMMENT,
70         SCRIPT_OPCODE_NUM
71 };
72 static const char OPSTR_CPU_ROMSIZE[] = "CPU_ROMSIZE";
73 static const char OPSTR_CPU_RAMSIZE[] = "CPU_RAMSIZE";
74 static const char OPSTR_PPU_ROMSIZE[] = "PPU_ROMSIZE";
75 static const char OPSTR_CPU_RAMRW[] = "CPU_RAMRW";
76 static const struct script_syntax SCRIPT_SYNTAX[] = {
77         {"MAPPER", SCRIPT_OPCODE_MAPPER, 1, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
78         {"MIRROR", SCRIPT_OPCODE_MIRROR, 1, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_HV, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
79         {OPSTR_CPU_ROMSIZE, SCRIPT_OPCODE_CPU_ROMSIZE, 1, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
80         {OPSTR_CPU_RAMSIZE, SCRIPT_OPCODE_CPU_RAMSIZE, 1, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
81         {OPSTR_PPU_ROMSIZE, SCRIPT_OPCODE_PPU_ROMSIZE, 1, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
82         {"DUMP_START", SCRIPT_OPCODE_DUMP_START, 0, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
83         {"CPU_READ", SCRIPT_OPCODE_CPU_READ, 2, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
84         {"CPU_WRITE", SCRIPT_OPCODE_CPU_WRITE, 2, SYNTAX_COMPARE_GT, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_EXPRESSION, SYNTAX_ARGVTYPE_EXPRESSION, SYNTAX_ARGVTYPE_EXPRESSION}},
85         {OPSTR_CPU_RAMRW, SCRIPT_OPCODE_CPU_RAMRW, 2, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
86         {"PPU_RAMTEST", SCRIPT_OPCODE_PPU_RAMTEST, 0, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
87         {"PPU_READ", SCRIPT_OPCODE_PPU_READ, 2, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
88 #if OP_PPU_WRITE_ENABLE==1
89         {"PPU_WRITE", SCRIPT_OPCODE_PPU_WRITE, 2, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
90 #endif
91         {"STEP_START", SCRIPT_OPCODE_STEP_START, 4, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_VARIABLE, SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE, SYNTAX_ARGVTYPE_VALUE}},
92         {"STEP_END", SCRIPT_OPCODE_STEP_END, 0, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}},
93         {"DUMP_END", SCRIPT_OPCODE_DUMP_END, 0, SYNTAX_COMPARE_EQ, {SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL, SYNTAX_ARGVTYPE_NULL}}
94 };
95
96 //ÊÑ¿ô´ÉÍý
97 struct variable_manage{
98         char name;
99         long start,end,step;
100         long val;
101         const struct script *Continue;
102 };
103
104 enum{
105         STEP_MAX = 2,
106         VARIABLE_MAX = STEP_MAX
107 };
108
109 static const struct variable_manage VARIABLE_INIT = {
110         '\0', 0, 0, 0, 0,
111         NULL
112 };
113 static struct variable_manage variable_bank[VARIABLE_MAX];
114 static int variable_num = 0;
115
116 static void variable_init_single(int num)
117 {
118         memcpy(&variable_bank[num], &VARIABLE_INIT, sizeof(struct variable_manage));
119 }
120
121 static void variable_init_all(void)
122 {
123         int i;
124         variable_num = 0;
125         for(i = 0; i < VARIABLE_MAX; i++){
126                 variable_init_single(i);
127         }
128 }
129
130 static int variable_get(char name, long *val)
131 {
132         int i;
133         struct variable_manage *v;
134         v = variable_bank;
135         for(i = 0; i < variable_num; i++){
136                 if(v->name == name){
137                         *val = v->val;
138                         return OK;
139                 }
140                 v++;
141         }
142         return NG;
143 }
144
145 //ÊÑ¿ôŸ³«
146 static int expression_calc(const struct st_expression *e, long *val)
147 {
148         long left, right;
149         if(e->left.type == EXPRESSION_TYPE_VARIABLE){
150                 if(variable_get(e->left.variable, &left) == NG){
151                         return NG;
152                 }
153         }else{
154                 left = e->left.value;
155         }
156         if(e->operator == OPERATOR_NONE){
157                 *val = left;
158                 return OK;
159         }
160         if(e->right.type == EXPRESSION_TYPE_VARIABLE){
161                 if(variable_get(e->right.variable, &right) == NG){
162                         return NG;
163                 }
164         }else{
165                 right = e->right.value;
166         }
167         switch(e->operator){
168         case OPERATOR_PLUS:
169                 *val = left + right;
170                 break;
171         case OPERATOR_SHIFT_LEFT:
172                 *val = left >> right;
173                 //*val &= 1;
174                 break;
175         case OPERATOR_SHIFT_RIGHT:
176                 *val = left << right;
177                 break;
178         case OPERATOR_AND:
179                 *val = left & right;
180                 break;
181         case OPERATOR_OR:
182                 *val = left | right;
183                 break;
184         case OPERATOR_XOR:
185                 *val = left ^ right;
186                 break;
187         }
188         
189         return OK;
190 }
191
192 static int step_new(char name, long start, long end, long step, const struct script *Continue)
193 {
194         if(variable_num >= VARIABLE_MAX){
195                 return NG; //ÊÑ¿ôÄêµÁ¤¬Â¿¤¹¤®
196         }
197         struct variable_manage *v;
198         int i;
199         v = variable_bank;
200         for(i = 0; i < variable_num; i++){
201                 if(v->name == name){
202                         return NG; //ÊÑ¿ô̾½ÅÊ£
203                 }
204                 v++;
205         }
206         v = variable_bank;
207         v += variable_num;
208         v->name = name;
209         v->start = start;
210         v->end = end;
211         v->step = step;
212         v->val = start;
213         v->Continue = Continue;
214         variable_num++;
215         return OK;
216 }
217
218 static const struct script *step_end(const struct script *Break)
219 {
220         //¸½ºß¤Î¥ë¡¼¥×¤ÎÂоÝÊÑ¿ô¤òÆÀ¤ë
221         struct variable_manage *v;
222         v = variable_bank;
223         v += (variable_num - 1);
224         //ÊÑ¿ô¹¹¿·
225         v->val += v->step;
226         if(v->val < v->end){
227                 return v->Continue;
228         }
229         //¥ë¡¼¥×¤¬½ª¤ï¤Ã¤¿¤Î¤Ç¤½¤ÎÊÑ¿ô¤òÇË´þ¤¹¤ë
230         variable_init_single(variable_num - 1);
231         variable_num--;
232         return Break;
233 }
234
235 static int syntax_check_expression(char **word, int word_num, struct st_expression *e)
236 {
237         if(word_num == 0){
238                 return NG;
239         }
240         //left
241         if(value_get(word[0], &(e->left.value)) == OK){
242                 e->left.type = EXPRESSION_TYPE_VALUE;
243         }else{
244                 e->left.type = EXPRESSION_TYPE_VARIABLE;
245                 e->left.variable = word[0][0];
246         }
247         word_num--;
248         if(word_num == 0){
249                 e->operator = OPERATOR_NONE;
250                 return OK;
251         }
252         //operator
253         e->operator = operator_get(word[1]);
254         if(e->operator == OPERATOR_ERROR){
255                 return NG;
256         }
257         word_num--;
258         if(word_num == 0){
259                 return NG;
260         }
261         //right
262         if(value_get(word[2], &(e->right.value)) == OK){
263                 e->right.type = EXPRESSION_TYPE_VALUE;
264         }else{
265                 e->right.type = EXPRESSION_TYPE_VARIABLE;
266                 e->right.variable = word[2][0];
267         }
268         return OK;
269 }
270
271 static const char SYNTAX_ERROR_PREFIX[] = "syntax error:";
272
273 static int syntax_check_phase(char **word, int word_num, struct script *s)
274 {
275         int i = sizeof(SCRIPT_SYNTAX) / sizeof(SCRIPT_SYNTAX[0]);
276         const struct script_syntax *syntax;
277         syntax = SCRIPT_SYNTAX;
278         while(i != 0){
279                 if(strcmp(syntax->name, word[0]) == 0){
280                         int j;
281                         
282                         s->opcode = syntax->script_opcode;
283                         {
284                                 int compare = 0;
285                                 switch(syntax->compare){
286                                 case SYNTAX_COMPARE_EQ:
287                                         compare = (syntax->argc == (word_num - 1));
288                                         break;
289                                 case SYNTAX_COMPARE_GT:
290                                         compare = (syntax->argc <= (word_num - 1));
291                                         break;
292                                 }
293                                 if(!compare){
294                                         printf("%s parameter number not much %s\n", SYNTAX_ERROR_PREFIX, word[0]);
295                                         return 1;
296                                 }
297                         }
298                         for(j = 0; j < syntax->argc; j++){
299                                 switch(syntax->argv_type[j]){
300                                 case SYNTAX_ARGVTYPE_NULL:
301                                         printf("%s ARGV_NULL select\n", SYNTAX_ERROR_PREFIX);
302                                         return 1;
303                                 case SYNTAX_ARGVTYPE_VALUE:
304                                         if(value_get(word[j + 1], &(s->value[j])) == NG){
305                                                 printf("%s value error %s %s\n", SYNTAX_ERROR_PREFIX, word[0], word[j+1]);
306                                                 return 1;
307                                         }
308                                         break;
309                                 case SYNTAX_ARGVTYPE_HV:
310                                         switch(word[j + 1][0]){
311                                         case 'H':
312                                         case 'h':
313                                                 s->value[j] = MIRROR_HORIZONAL;
314                                                 break;
315                                         case 'V':
316                                         case 'v':
317                                                 s->value[j] = MIRROR_VERTICAL;
318                                                 break;
319                                         case 'A':
320                                         case 'a':
321                                                 s->value[j] = MIRROR_PROGRAMABLE;
322                                                 break;
323                                         default:
324                                                 printf("%s unknown scroll mirroring type %s\n", SYNTAX_ERROR_PREFIX, word[j+1]);
325                                                 return 1;
326                                         }
327                                         break;
328                                 case SYNTAX_ARGVTYPE_EXPRESSION:
329                                         s->value[j] = VALUE_EXPRESSION;
330                                         //Ì¿Îá̾¤Îñ¸ì¤Èñ¸ì¿ô¤ò½ü³°¤·¤ÆÅϤ¹
331                                         if(syntax_check_expression(&word[j+1], word_num - 2, &s->expression) == NG){
332                                                 printf("%s expression error\n", SYNTAX_ERROR_PREFIX);
333                                                 return 1;
334                                         }
335                                         //²ÄÊѤ˰ú¿ô¤ò¼è¤ë¤Î¤Ç¤³¤³¤Ç½ª¤ï¤ê
336                                         return 0;
337                                 case SYNTAX_ARGVTYPE_VARIABLE:{
338                                         const char v = word[j+1][0];
339                                         if((v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z')){
340                                                 s->value[j] = VALUE_VARIABLE;
341                                                 s->variable = v;
342                                         }else{
343                                                 printf("%s variable must use [A-Za-z] %s\n", SYNTAX_ERROR_PREFIX, word[j+1]);
344                                                 return 1;
345                                         }
346                                         }break;
347                                 }
348                         }
349                         return 0;
350                 }
351                 syntax++;
352                 i--;
353         }
354         printf("%s unknown opcode %s\n", SYNTAX_ERROR_PREFIX, word[0]);
355         return 1;
356 }
357
358 static int syntax_check(char **text, int text_num, struct script *s)
359 {
360         int error = 0;
361         int i;
362         variable_init_all();
363         for(i = 0; i < text_num; i++){
364                 char *word[TEXT_MAXWORD];
365                 const int n = word_load(text[i], word);
366                 if(word[0][0] == '#'){
367                         s->opcode = SCRIPT_OPCODE_COMMENT;
368                 }else{
369                         error += syntax_check_phase(word, n, s);
370                 }
371                 s++;
372         }
373         return error;
374 }
375
376 /*
377 logical_check() ÍÑ¥µ¥Ö´Ø¿ô¤È¥Ç¡¼¥¿
378 */
379 static const char LOGICAL_ERROR_PREFIX[] = "logical error:";
380
381 static inline void logical_print_illgalarea(const char *area, long address)
382 {
383         printf("%s illgal %s area $%06x\n", LOGICAL_ERROR_PREFIX, area, (int) address);
384 }
385
386 static inline void logical_print_illgallength(const char *area, long length)
387 {
388         printf("%s illgal %s length $%04x\n", LOGICAL_ERROR_PREFIX, area, (int) length);
389 }
390
391 static inline void logical_print_overdump(const char *area, long start, long end)
392 {
393         printf("%s %s area over dump $%06x-$%06x\n", LOGICAL_ERROR_PREFIX, area, (int)start ,(int)end);
394 }
395
396 static inline void logical_print_access(const char *area, const char *rw, long addr, long len)
397 {
398         printf("%s %s $%04x $%02x\n", area, rw, (int) addr, (int) len);
399 }
400
401 static inline void logical_print_byteerror(const char *area, long data)
402 {
403         printf("%s write data byte range over, %s $%x\n", LOGICAL_ERROR_PREFIX, area, (int) data);
404 }
405
406 static int dump_length_conform(const char *name, long logicallength, long configlength)
407 {
408         if(configlength != logicallength){
409                 printf("%s %s dump length error\n", LOGICAL_ERROR_PREFIX, name);
410                 printf("%s: 0x%06x, dump length: 0x%06x\n", name, (int) configlength, (int) logicallength);
411                 return 1;
412         }
413         return 0;
414 }
415 static inline int is_region_cpurom(long address)
416 {
417         return (address >= 0x8000) && (address < 0x10000);
418 }
419
420 static inline int is_region_cpuram(long address)
421 {
422         return (address >= 0x6000) && (address < 0x8000);
423 }
424
425 static inline int is_region_ppurom(long address)
426 {
427         return (address >= 0) && (address < 0x2000);
428 }
429
430 static inline int is_data_byte(long data)
431 {
432         return (data >= 0) && (data < 0x100);
433 }
434
435 //¤³¤ì¤À¤± is ·Ï¤Ç <= ±é»»»Ò¤ò»ÈÍѤ·¤Æ¤¤¤ë¤Î¤ÇÃí°Õ
436 static inline int is_range(long data, long start, long end)
437 {
438         return (data >= start) && (data <= end);
439 }
440 static const char STR_REGION_CPU[] = "cpu";
441 static const char STR_REGION_PPU[] = "ppu";
442 static const char STR_ACCESS_READ[] = "read";
443 static const char STR_ACCESS_WRITE[] = "write";
444
445 enum{
446         SETTING, DUMP, END
447 };
448 static int logical_check(const struct script *s, const struct st_config *c, struct romimage *r)
449 {
450         long cpu_romsize = 0, cpu_ramsize = 0, ppu_romsize = 0;
451         int setting = SETTING, error = 0;
452         //romimage init
453         variable_init_all();
454         while(s->opcode != SCRIPT_OPCODE_DUMP_END){
455                 //printf("opcode exec %s\n", SCRIPT_SYNTAX[s->opcode].name);
456                 if((setting == DUMP) && (s->opcode < SCRIPT_OPCODE_DUMP_START)){
457                         printf("%s config script include DUMPSTART area\n", LOGICAL_ERROR_PREFIX);
458                         error += 1;
459                 }
460                 switch(s->opcode){
461                 case SCRIPT_OPCODE_COMMENT:
462                         break;
463                 case SCRIPT_OPCODE_MAPPER:
464                         r->mappernum = s->value[0];
465                         break;
466                 case SCRIPT_OPCODE_MIRROR:
467                         r->mirror = s->value[0];
468                         break;
469                 case SCRIPT_OPCODE_CPU_ROMSIZE:
470                         r->cpu_rom.size = s->value[0];
471                         break;
472                 case SCRIPT_OPCODE_CPU_RAMSIZE:
473                         r->cpu_ram_read.size = s->value[0];
474                         r->cpu_ram_write.size = s->value[0];
475                         break;
476                 case SCRIPT_OPCODE_PPU_ROMSIZE:
477                         r->ppu_rom.size = s->value[0];
478                         break;
479                 case SCRIPT_OPCODE_DUMP_START:
480                         setting = DUMP;
481                         break;
482                 case SCRIPT_OPCODE_CPU_READ:{
483                         const long address = s->value[0];
484                         const long length = s->value[1];
485                         const long end = address + length - 1;
486                         //length filter. 0 ¤Ï¤À¤á
487                         if(!is_range(length, 1, 0x4000)){
488                                 logical_print_illgallength(STR_REGION_CPU, length);
489                                 error += 1;
490                         }
491                         //address filter
492                         else if(address < 0x6000 || address >= 0x10000){
493                                 logical_print_illgalarea(STR_REGION_CPU, address);
494                                 error += 1;
495                         }else if(end >= 0x10000){
496                                 logical_print_overdump(STR_REGION_CPU, address, end);
497                                 error += 1;
498                         }
499                         //$7fff-$8000¤òϢ³¤Ç¤Þ¤¿¤¬¤»¤Ê¤¤
500                         else if((address <= 0x7fff) && (end >= 0x8000)){
501                                 printf("%s address cannot over $7fff-$8000. divide CPU_READ.\n", LOGICAL_ERROR_PREFIX);
502                                 error += 1;
503                         }
504                         //dump length update
505                         if(is_region_cpuram(address)){
506                                 cpu_ramsize += length;
507                         }else if(is_region_cpurom(address)){
508                                 cpu_romsize += length;
509                         }
510                         setting = DUMP;
511                         }
512                         break;
513                 case SCRIPT_OPCODE_CPU_WRITE:{
514                         const long address = s->value[0];
515                         long data;
516                         if(expression_calc(&s->expression, &data) == NG){
517                                 printf("%s expression calc error\n", LOGICAL_ERROR_PREFIX);
518                                 error += 1;
519                         }
520                         if(address < 0x5000 || address >= 0x10000){
521                                 logical_print_illgalarea(STR_REGION_CPU, address);
522                                 error += 1;
523                         }else if(!is_data_byte(data)){
524                                 logical_print_byteerror(STR_REGION_CPU, data);
525                                 error += 1;
526                         }
527                         setting = DUMP;
528                         }
529                         break;
530                 case SCRIPT_OPCODE_CPU_RAMRW:{
531                         if(c->mode == MODE_ROM_DUMP){
532                                 printf("%s cannot use %s on ROMDUMP mode\n", LOGICAL_ERROR_PREFIX, OPSTR_CPU_RAMRW);
533                                 error += 1;
534                         }
535                         const long address = s->value[0];
536                         const long length = s->value[1];
537                         const long end = address + length - 1;
538                         //length filter. 0 ¤Ï¤À¤á
539                         if(!is_range(length, 1, 0x2000)){
540                                 logical_print_illgallength(STR_REGION_CPU, length);
541                                 error += 1;
542                         }
543                         //address filter
544                         else if(address < 0x6000 || address >= 0x8000){
545                                 logical_print_illgalarea(STR_REGION_CPU, address);
546                                 error += 1;
547                         }else if(end >= 0x8000){
548                                 logical_print_overdump(STR_REGION_CPU, address, end);
549                                 error += 1;
550                         }
551                         cpu_ramsize += length;
552                         if(c->mode == MODE_RAM_WRITE){
553                                 r->cpu_ram_write.data = buf_load_full(c->ramimage_write, &(r->cpu_ram_write.size));
554                                 if(r->cpu_ram_write.data == NULL){
555                                         printf("%s RAM image open error\n.", LOGICAL_ERROR_PREFIX);
556                                         error += 1;
557                                 }else if(r->cpu_ram_read.size != r->cpu_ram_write.size){
558                                         printf("%s RAM image size is not same.\n", LOGICAL_ERROR_PREFIX);
559                                         free(r->cpu_ram_write.data);
560                                         r->cpu_ram_write.data = NULL;
561                                         error += 1;
562                                 }
563                         }
564                         setting = DUMP;
565                         }
566                         break;
567                 case SCRIPT_OPCODE_PPU_RAMTEST:
568                         //logical check ¤Ç¤Ï¤Ê¤Ë¤â¤·¤Ê¤¤
569                         break;
570                 case SCRIPT_OPCODE_PPU_READ:{
571                         const long address = s->value[0];
572                         const long length = s->value[1];
573                         const long end = address + length - 1;
574                         //length filter. 0 ¤òÍÆǧ¤¹¤ë
575                         if(!is_range(length, 0, 0x2000)){
576                                 logical_print_illgallength(STR_REGION_PPU, length);
577                                 error += 1;
578                         }
579                         //address filter
580                         else if(!is_region_ppurom(address)){
581                                 logical_print_illgalarea(STR_REGION_PPU, address);
582                                 error += 1;
583                         }else if (end >= 0x2000){
584                                 logical_print_overdump(STR_REGION_PPU, address, end);
585                                 error += 1;
586                         }
587                         //dump length update
588                         if(is_region_ppurom(address)){
589                                 ppu_romsize += length;
590                         }
591                         setting = DUMP;
592                         }
593                         break;
594                 case SCRIPT_OPCODE_PPU_WRITE:{
595                         if(OP_PPU_WRITE_ENABLE==0){
596                                 break;
597                         }
598                         const long address = s->value[0];
599                         const long data = s->value[1];
600                         setting = DUMP;
601                         if(!is_region_ppurom(address)){
602                                 logical_print_illgalarea(STR_REGION_PPU, address);
603                                 error += 1;
604                         }else if(!is_data_byte(data)){
605                                 logical_print_byteerror(STR_REGION_PPU, data);
606                                 error += 1;
607                         }
608                         }
609                         break;
610                 case SCRIPT_OPCODE_STEP_START:{
611                         int i;
612                         {
613                                 const int v = s->value[1];
614                                 if((v < 0) || (v > 0xff)){
615                                         printf("%s step start must 0-0xff 0x%x\n", LOGICAL_ERROR_PREFIX, v);
616                                         error += 1;
617                                 }
618                         }
619                         for(i = 2; i <4; i++){
620                                 const int v = s->value[i];
621                                 if((v < 1) || (v > 0x100)){
622                                         printf("%s end or next must 1-0x100 0x%x\n", LOGICAL_ERROR_PREFIX, v);
623                                         error += 1;
624                                 }
625                         }
626                         //¥ë¡¼¥×¤ÎÌá¤êÀè¤Ï¤³¤ÎÌ¿Îá¤Î¼¡¤Ê¤Î¤Ç s[1]
627                         if(step_new(s->variable, s->value[1], s->value[2], s->value[3], &s[1]) == NG){
628                                 printf("%s step loop too much\n", LOGICAL_ERROR_PREFIX);
629                                 error += 1;
630                                 return error;
631                         }
632                         setting = DUMP;
633                         }break;
634                 case SCRIPT_OPCODE_DUMP_END:
635                         setting = END;
636                         break;
637                 }
638                 if(setting == END){
639                         break;
640                 }
641                 if(s->opcode == SCRIPT_OPCODE_STEP_END){
642                         if(variable_num == 0){
643                                 printf("%s loop closed, missing STEP_START\n", LOGICAL_ERROR_PREFIX);
644                                 return error + 1;
645                         }
646                         s = step_end(&s[1]);
647                         setting = DUMP;
648                 }else{
649                         s++;
650                 }
651         }
652         
653         //loop open conform
654         if(variable_num != 0){
655                 printf("%s loop opened, missing STEP_END\n", LOGICAL_ERROR_PREFIX);
656                 error += 1;
657         }
658         //dump length conform
659         error += dump_length_conform(OPSTR_CPU_ROMSIZE, cpu_romsize, r->cpu_rom.size);
660         error += dump_length_conform(OPSTR_CPU_RAMSIZE, cpu_ramsize, r->cpu_ram_read.size);
661         error += dump_length_conform(OPSTR_PPU_ROMSIZE, ppu_romsize, r->ppu_rom.size);
662         
663         //command line config override
664         if(c->mirror != CONFIG_OVERRIDE_UNDEF){
665                 r->mirror = c->mirror;
666         }
667         if(c->backupram != CONFIG_OVERRIDE_UNDEF){
668                 r->backupram = 1;
669         }
670         if(c->mapper != CONFIG_OVERRIDE_UNDEF){
671                 r->mappernum = c->mapper;
672         }
673         return error;
674 }
675
676 /*
677 execute() ÍÑ¥µ¥Ö´Ø¿ô¤È¥Ç¡¼¥¿
678 */
679 static int execute_connection_check(const struct driver *d)
680 {
681         int ret = OK;
682         const int testsize = 0x80;
683         int testcount = 3;
684         u8 *master, *reload;
685         master = malloc(testsize);
686         reload = malloc(testsize);
687
688         d->cpu_read(0xfee0, testsize, master);
689         
690         while(testcount != 0){
691                 d->cpu_read(0xfee0, testsize, reload);
692                 if(memcmp(master, reload, testsize) != 0){
693                         ret = NG;
694                         break;
695                 }
696                 testcount--;
697         }
698         
699         free(master);
700         free(reload);
701         return ret;
702 }
703
704 enum {PPU_TEST_RAM, PPU_TEST_ROM};
705 const u8 PPU_TEST_DATA[] = "PPU_TEST_DATA";
706 #if DEBUG==0
707 static 
708 #endif
709 int ppu_ramtest(const struct driver *d)
710 {
711         const int length = sizeof(PPU_TEST_DATA);
712         const long testaddr = 123;
713         //ppu ram data fill 0
714         {
715                 int i = length;
716                 long address = testaddr;
717                 while(i != 0){
718                         d->ppu_write(address++, 0);
719                         i--;
720                 }
721         }
722         
723         //ppu test data write
724         {
725                 const u8 *data;
726                 int i = length;
727                 long address = testaddr;
728                 data = PPU_TEST_DATA;
729                 while(i != 0){
730                         d->ppu_write(address++, (long) *data);
731                         data++;
732                         i--;
733                 }
734         }
735
736         u8 writedata[length];
737         d->ppu_read(testaddr, length, writedata);
738         if(memcmp(writedata, PPU_TEST_DATA, length) == 0){
739                 return PPU_TEST_RAM;
740         }
741         return PPU_TEST_ROM;
742 }
743
744 static void readbuffer_print(const struct memory *m, long length)
745 {
746         if(length >= 0x10){
747                 length = 0x10;
748         }
749         printf("%s 0x%05x:", m->name, m->offset);
750         int offset = 0;
751         const u8 *data;
752         data = m->data;
753         while(length != 0){
754                 char safix;
755                 switch(offset & 0xf){
756                 default:
757                         safix = ' ';
758                         break;
759                 case 0x7:
760                         safix = '-';
761                         break;
762                 case 0xf:
763                         safix = ';';
764                         break;
765                 }
766                 printf("%02x%c", (int) *data, safix);
767                 data++;
768                 offset++;
769                 length--;
770         }
771 }
772
773 static void checksum_print(const u8 *data, long length)
774 {
775         int sum = 0;
776         while(length != 0){
777                 sum += (int) *data;
778                 data++;
779                 length--;
780         }
781         printf(" 0x%06x\n", sum);
782         fflush(stdout);
783 }
784
785 static void read_result_print(const struct memory *m, long length)
786 {
787         readbuffer_print(m, length);
788         checksum_print(m->data, length);
789 }
790
791 const char EXECUTE_ERROR_PREFIX[] = "execute error:";
792 static void execute_cpu_ramrw(const struct driver *d, const struct memory *w, struct memory *r, int mode, long address, long length)
793 {
794         if(mode == MODE_RAM_WRITE){
795                 const u8 *writedata;
796                 long a = address;
797                 long l = length;
798                 writedata = w->data;
799                 while(l != 0){
800                         d->cpu_write(a++, *writedata);
801                         writedata += 1;
802                         l--;
803                 }
804         }
805         d->cpu_read(address, length, r->data);
806         if(mode == MODE_RAM_READ){
807                 return;
808         }
809         if(memcmp(r->data, w->data, length) == 0){
810                 printf("RAM data write success.\n");
811         }else{
812                 printf("RAM data write failed.\n");
813         }
814 }
815
816 static int execute(const struct script *s, const struct st_config *c, struct romimage *r)
817 {
818         const struct driver *d;
819         d = driver_get(c->driver);
820         if(d == NULL){
821                 printf("%s driver not found.\n", EXECUTE_ERROR_PREFIX);
822                 return NG;
823         }
824         const int gg = giveio_start();
825         switch(gg){
826         case GIVEIO_OPEN:
827         case GIVEIO_START:
828         case GIVEIO_WIN95:
829                 d->init();
830                 break;
831         default:
832         case GIVEIO_ERROR:
833                 printf("%s Can't Access Direct IO %d\n", EXECUTE_ERROR_PREFIX, gg);
834                 return NG;
835         }
836         if(execute_connection_check(d) == NG){
837                 printf("%s maybe connection error.\n", EXECUTE_ERROR_PREFIX);
838                 return NG;
839         }
840         struct memory cpu_rom, ppu_rom, cpu_ram_read, cpu_ram_write;
841         cpu_rom = r->cpu_rom;
842         ppu_rom = r->ppu_rom;
843         cpu_ram_read = r->cpu_ram_read;
844         cpu_ram_write = r->cpu_ram_write;
845         
846         variable_init_all();
847         while(s->opcode != SCRIPT_OPCODE_DUMP_END){
848                 int end = 1;
849                 switch(s->opcode){
850                 case SCRIPT_OPCODE_CPU_READ:{
851                         struct memory *m;
852                         const long addr = s->value[0];
853                         const long length = s->value[1];
854                         m = &cpu_rom;
855                         if(is_region_cpuram(addr)){
856                                 m = &cpu_ram_read;
857                         }
858                         d->cpu_read(addr, length, m->data);
859                         read_result_print(m, length);
860                         m->data += length;
861                         m->offset += length;
862                         }break;
863                 case SCRIPT_OPCODE_CPU_WRITE:{
864                         long data;
865                         expression_calc(&s->expression, &data);
866                         d->cpu_write(s->value[0], data);
867                         }
868                         break;
869                 case SCRIPT_OPCODE_CPU_RAMRW:{
870                         const long length = s->value[1];
871                         execute_cpu_ramrw(d, &cpu_ram_write, &cpu_ram_read, c->mode, s->value[0], length);
872                         read_result_print(&cpu_ram_read, length);
873                         cpu_ram_read.data += length;
874                         cpu_ram_read.offset += length;
875                         if(c->mode == MODE_RAM_WRITE){
876                                 cpu_ram_write.data += length;
877                                 cpu_ram_write.offset += length;
878                         }
879                         }
880                         break;
881                 case SCRIPT_OPCODE_PPU_RAMTEST:
882                         if(ppu_ramtest(d) == PPU_TEST_RAM){
883                                 printf("PPU_RAMTEST: charcter RAM found\n");
884                                 r->ppu_rom.size = 0;
885                                 end = 0;
886                         }
887                         break;
888                 case SCRIPT_OPCODE_PPU_READ:{
889                         const long address = s->value[0];
890                         const long length = s->value[1];
891                         if(length == 0){
892                                 /*for mmc2,4 protect.
893                                 ¤³¤Î¤È¤­¤Ï1byteÆɤ߹þ¤ó¤Ç¡¢¤½¤ÎÆâÍƤϥХåե¡¤Ë¤¤¤ì¤Ê¤¤*/
894                                 u8 dummy;
895                                 d->ppu_read(address, 1, &dummy);
896                         }else{
897                                 d->ppu_read(address, length, ppu_rom.data);
898                                 read_result_print(&ppu_rom, length);
899                         }
900                         ppu_rom.data += length;
901                         ppu_rom.offset += length;
902                         }
903                         break;
904                 case SCRIPT_OPCODE_PPU_WRITE:
905                         if(OP_PPU_WRITE_ENABLE == 1){
906                                 d->ppu_write(s->value[0], s->value[1]);
907                         }
908                         break;
909                 case SCRIPT_OPCODE_STEP_START:
910                         //¥ë¡¼¥×¤ÎÌá¤êÀè¤Ï¤³¤ÎÌ¿Îá¤Î¼¡¤Ê¤Î¤Ç &s[1]
911                         step_new(s->variable, s->value[1], s->value[2], s->value[3], &s[1]);
912                         break;
913                 case SCRIPT_OPCODE_DUMP_END:
914                         end = 0;
915                         break;
916                 }
917                 if(end == 0){
918                         break;
919                 }
920                 if(s->opcode == SCRIPT_OPCODE_STEP_END){
921                         s = step_end(++s);
922                 }else{
923                         s++;
924                 }
925         }
926         if(gg != GIVEIO_WIN95){
927                 giveio_stop(GIVEIO_STOP);
928         }
929         return OK;
930 }
931
932 void script_load(const struct st_config *c)
933 {
934         struct script *s;
935         {
936                 int scriptsize = 0;
937                 char *buf;
938                 
939                 buf = buf_load_full(c->script, &scriptsize);
940                 if(buf == NULL){
941                         printf("scriptfile open error\n");
942                         return;
943                 }
944                 char *text[TEXT_MAXLINE];
945                 const int text_num = text_load(buf, scriptsize, text);
946                 if(text_num == 0){
947                         printf("script line too much\n");
948                         free(buf);
949                         return;
950                 }
951                 s = malloc(sizeof(struct script) * (text_num + 1));
952                 //logical_check, execute ¶¦¤Ë s->opcode ¤¬ DUMP_END ¤Ë¤Ê¤ë¤Þ¤Ç³¤±¤ë¡£DUMP_END ¤ÎÆþ¤ì˺¤ìÍѤËËöÈø¤Îscript¤Ëɬ¤º DUMP_END ¤ò¤¤¤ì¤ë
953                 {
954                         struct script *k;
955                         k = s;
956                         k += text_num;
957                         k->opcode = SCRIPT_OPCODE_DUMP_END;
958                 }
959                 const int error = syntax_check(text, text_num, s);
960                 free(buf);
961                 if(error != 0){
962                         free(s);
963                         return;
964                 }
965         }
966         struct romimage r = {
967                 cpu_rom: {
968                         size: 0, offset: 0,
969                         data: NULL,
970                         name: STR_REGION_CPU
971                 },
972                 ppu_rom: {
973                         size: 0, offset: 0,
974                         data: NULL,
975                         name: STR_REGION_PPU
976                 },
977                 cpu_ram_read: {
978                         size: 0, offset: 0,
979                         data: NULL,
980                         name: STR_REGION_CPU
981                 },
982                 cpu_ram_write: {
983                         size: 0, offset: 0,
984                         data: NULL,
985                         name: STR_REGION_CPU
986                 },
987                 neshead: NULL,
988                 mappernum: 0,
989                 mirror: MIRROR_PROGRAMABLE
990         };
991         if(logical_check(s, c, &r) == 0){
992                 //dump RAM Îΰè¼èÆÀ
993                 if(nesbuffer_malloc(&r) == NG){
994                         free(s);
995                         if(r.cpu_ram_write.data != NULL){
996                                 free(r.cpu_ram_write.data);
997                         }
998                         return;
999                 }
1000                 //dump
1001                 if(execute(s, c, &r) == OK){
1002                         //À®²Ì½ÐÎÏ
1003                         switch(c->mode){
1004                         case MODE_ROM_DUMP:
1005                                 nesfile_create(&r, c->romimage);
1006                                 break;
1007                         case MODE_RAM_READ:
1008                                 backupram_create(&(r.cpu_ram_read), c->ramimage_read);
1009                                 break;
1010                         }
1011                 }
1012                 //dump RAM Îΰè²òÊü
1013                 nesbuffer_free(&r);
1014                 if(r.cpu_ram_write.data != NULL){
1015                         free(r.cpu_ram_write.data);
1016                 }
1017         }
1018         free(s);
1019 }