1 /*
2 * Builder - builds a ZCode interpreter
3 * Copyright (C) 2000 Andrew Hunter
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * Yea, it's ugly. Hopefully not quite as ugly as doing the whole
22 * thing by hand, though...
23 *
24 * For those of you who can't be bothered reading the theory, it's
25 * basically that all the effort used here to produce the specialised
26 * interpreter is not required at runtime. The length of this file
27 * should indicate that that turns out to be quite a lot.
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "../config.h"
35 #undef VERSION
36
37 #include "operation.h"
38 #ifndef APPLE_IS_ARBITRARY
39 # include "gram.h"
40 #else
41 # include "gram.tab.h"
42 #endif
43
44 extern int yyline;
45 extern oplist zmachine;
46 extern int yyparse();
47
48 static char* filename;
49
50 #ifndef HAVE_COMPUTED_GOTOS
51 static int used_opcodes[256];
52 #endif
53
sortops(const void * un,const void * deux)54 static int sortops(const void* un, const void* deux)
55 {
56 operation* one;
57 operation* two;
58
59 one = (operation*) un;
60 two = (operation*) deux;
61
62 if (one->type > two->type)
63 return 1;
64 else if (one->type < two->type)
65 return -1;
66 else if (one->value > two->value)
67 return 1;
68 else if (one->value < two->value)
69 return -1;
70 else
71 return 0;
72 }
73
74 /* The various sections of code that make up an interpreter */
75 #ifndef HAVE_COMPUTED_GOTOS
76 static char* header =
77 "/*\n * Interpreter automatically generated for version %i\n * Do not alter this file\n */\n\n switch (instr)\n {\n";
78
79 static char* notimpl = " /* %s not implemented */\n";
80 #endif
81
82 #define VERSIONS \
83 if (versions != -1) \
84 { \
85 fprintf(dest, "_"); \
86 for (z = 1; z<32; z++) \
87 { \
88 if (versions&(1<<z)) \
89 fprintf(dest, "%i", z); \
90 } \
91 }
92
93 #ifndef HAVE_COMPUTED_GOTOS
output_opname(FILE * dest,char * opname,int versions)94 static void output_opname(FILE* dest,
95 char* opname,
96 int versions)
97 {
98 int z;
99
100 fprintf(dest, "goto op_%s", opname);
101 VERSIONS;
102 fprintf(dest, ";\n");
103 }
104 #endif
105
106 #ifndef HAVE_COMPUTED_GOTOS
output_interpreter(FILE * dest,int version)107 void output_interpreter(FILE* dest,
108 int version)
109 {
110 int vmask;
111 int x,y;
112 int pcadd;
113
114 for (x=0; x<256; x++)
115 used_opcodes[x] = 0;
116
117 vmask = 1<<version;
118 fprintf(dest, header, version);
119
120 for (x=0; x<zmachine.numops; x++)
121 {
122 operation* op;
123
124 op = zmachine.op[x];
125 if ((op->versions&vmask && op->versions != -1) || (version==-1
126 && op->versions==-1))
127 {
128 switch (op->type)
129 {
130 /* All possible 0OP bytes*/
131 case zop:
132 pcadd = 1;
133 fprintf(dest, " case 0x%x: /* %s */\n",
134 op->value|0xb0, op->name);
135
136 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
137 op->name);
138 used_opcodes[op->value|0xb0] = 1;
139
140 if (op->flags.isstore)
141 {
142 fprintf(dest, " st = GetCode(pc+%i);\n", pcadd);
143 pcadd++;
144 }
145 if (op->flags.isbranch)
146 {
147 fprintf(dest, " tmp = GetCode(pc+%i);\n", pcadd);
148 fprintf(dest, " branch = tmp&0x3f;\n");
149 fprintf(dest, " padding=0;\n");
150 fprintf(dest, " if (!(tmp&0x40))\n");
151 fprintf(dest, " {\n");
152 fprintf(dest, " padding = 1;\n");
153 fprintf(dest, " if (branch&0x20)\n");
154 fprintf(dest, " branch -= 64;\n");
155 fprintf(dest, " branch <<= 8;\n");
156 fprintf(dest, " branch |= GetCode(pc+%i);\n",
157 pcadd+1);
158 fprintf(dest, " }\n");
159 fprintf(dest, " negate = tmp&0x80;\n");
160 pcadd++;
161 }
162 if (op->flags.isstring)
163 {
164 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"(String instruction) - decoding the string at #%%x: \", pc+%i);\n#endif\n", pcadd);
165 fprintf(dest, " string = zscii_to_unicode(&GetCode(pc+%i), &padding);\n", pcadd);
166 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\">%%s<\\n\", string);\n#endif\n");
167 }
168
169 if (op->flags.isbranch || op->flags.isstring)
170 fprintf(dest, " pc += %i+padding;\n", pcadd);
171 else
172 fprintf(dest, " pc += %i;\n", pcadd);
173
174 fprintf(dest, " ");
175 output_opname(dest, op->name, op->versions);
176 fprintf(dest, "\n");
177 break;
178
179 /* All possible 1OP bytes */
180 case unop:
181 for (y=0; y<3; y++)
182 {
183 pcadd = 1;
184 fprintf(dest, " case 0x%x: /* %s */\n",
185 op->value|0x80|(y<<4), op->name);
186
187 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
188 op->name);
189 used_opcodes[op->value|0x80|(y<<4)] = 1;
190
191 switch (y)
192 {
193 case 0:
194 fprintf(dest, " arg1 = (GetCode(pc+%i)<<8)|GetCode(pc+%i);\n", pcadd, pcadd+1);
195 pcadd+=2;
196 break;
197
198 case 1:
199 fprintf(dest, " arg1 = GetCode(pc+%i);\n",
200 pcadd);
201 pcadd++;
202 break;
203
204 case 2:
205 fprintf(dest, " arg1 = GetVar(GetCode(pc+%i));\n",
206 pcadd);
207 pcadd++;
208 break;
209 }
210
211 if (op->flags.isstore)
212 {
213 fprintf(dest, " st = GetCode(pc+%i);\n", pcadd);
214 pcadd++;
215 }
216 if (op->flags.isbranch)
217 {
218 fprintf(dest, " tmp = GetCode(pc+%i);\n", pcadd);
219 fprintf(dest, " branch = tmp&0x3f;\n");
220 fprintf(dest, " padding=0;\n");
221 fprintf(dest, " if (!(tmp&0x40))\n");
222 fprintf(dest, " {\n");
223 fprintf(dest, " padding = 1;\n");
224 fprintf(dest, " if (branch&0x20)\n");
225 fprintf(dest, " branch -= 64;\n");
226 fprintf(dest, " branch <<= 8;\n");
227 fprintf(dest, " branch |= GetCode(pc+%i);\n",
228 pcadd+1);
229 fprintf(dest, " }\n");
230 fprintf(dest, " negate = tmp&0x80;\n");
231 pcadd++;
232 }
233 if (op->flags.isstring)
234 {
235 fprintf(dest, " /* Implement me */\n");
236 }
237
238 if (op->flags.isbranch || op->flags.isstring)
239 fprintf(dest, " pc += %i+padding;\n", pcadd);
240 else
241 fprintf(dest, " pc += %i;\n", pcadd);
242
243 fprintf(dest, " ");
244 output_opname(dest, op->name, op->versions);
245
246 fprintf(dest, "\n");
247 }
248 break;
249
250 /* All possible 2OP bytes */
251 case binop:
252 for (y=0; y<4; y++)
253 {
254 pcadd = 1;
255 fprintf(dest, " case 0x%x: /* %s */\n",
256 op->value|(y<<5), op->name);
257
258 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
259 op->name);
260 used_opcodes[op->value|(y<<5)] = 1;
261
262 if (op->flags.reallyvar)
263 fprintf(dest, " argblock.n_args = 2;\n");
264 if (y&2)
265 fprintf(dest, " arg1 = GetVar(GetCode(pc+1));\n");
266 else
267 fprintf(dest, " arg1 = GetCode(pc+1);\n");
268 if (y&1)
269 fprintf(dest, " arg2 = GetVar(GetCode(pc+2));\n");
270 else
271 fprintf(dest, " arg2 = GetCode(pc+2);\n");
272 pcadd+=2;
273
274 if (op->flags.isstore)
275 {
276 fprintf(dest, " st = GetCode(pc+%i);\n", pcadd);
277 pcadd++;
278 }
279 if (op->flags.isbranch)
280 {
281 fprintf(dest, " tmp = GetCode(pc+%i);\n", pcadd);
282 fprintf(dest, " branch = tmp&0x3f;\n");
283 fprintf(dest, " padding=0;\n");
284 fprintf(dest, " if (!(tmp&0x40))\n");
285 fprintf(dest, " {\n");
286 fprintf(dest, " padding = 1;\n");
287 fprintf(dest, " if (branch&0x20)\n");
288 fprintf(dest, " branch -= 64;\n");
289 fprintf(dest, " branch <<= 8;\n");
290 fprintf(dest, " branch |= GetCode(pc+%i);\n",
291 pcadd+1);
292 fprintf(dest, " }\n");
293 fprintf(dest, " negate = tmp&0x80;\n");
294 pcadd++;
295 }
296
297 if (op->flags.isbranch || op->flags.isstring)
298 fprintf(dest, " pc += %i+padding;\n", pcadd);
299 else
300 fprintf(dest, " pc += %i;\n", pcadd);
301
302 fprintf(dest, " ");
303 output_opname(dest, op->name, op->versions);
304
305 fprintf(dest, "\n");
306 }
307
308 /*
309 * But that's not all, folks (yes, those zany guys at
310 * infocom had a *fifth* way to encode 2OPs. Which
311 * itself has 13 ways of representing its operands.
312 * Lucky me). This is all an evil plan to give me
313 * something better to do.
314 */
315 fprintf(dest, " case 0x%x: /* %s - variable form */\n",
316 op->value|0xc0, op->name);
317
318 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s (var form)\\n\");\n#endif\n",
319 op->name);
320 used_opcodes[op->value|0xc0] = 1;
321
322 pcadd = 4;
323 #if 0
324 fprintf(dest, " padding = 0;\n");
325 fprintf(dest, " switch (GetCode(pc+1))\n");
326 fprintf(dest, " {\n");
327 #define ARGTYPE(i) (i==0?"Large constant":(i==1?"Small constant":(i==2?"Variable":(i==3?"Omitted":"All messed up"))))
328 for (y=0; y<4; y++)
329 {
330 for (z=3; ((z>=0&&y!=3)|(z==3&&y==3)); z--)
331 {
332 int padding;
333
334 padding = 0;
335 fprintf(dest, " case %i: /* arg1 - %s, arg2 - %s */\n",
336 (y<<6)|(z<<4)|0xf, ARGTYPE(y), ARGTYPE(z));
337 switch (y)
338 {
339 case 0:
340 fprintf(dest, " arg1 = (GetCode(pc+2)<<8)|GetCode(pc+3);\n");
341 padding++;
342 break;
343
344 case 1:
345 fprintf(dest, " arg1 = GetCode(pc+2);\n");
346 break;
347
348 case 2:
349 fprintf(dest, " arg1 = GetVar(GetCode(pc+2));\n");
350 break;
351
352 case 3:
353 fprintf(dest, " arg1 = 0;\n");
354 padding--;
355 break;
356 }
357 switch (z)
358 {
359 case 0:
360 fprintf(dest, " arg2 = (GetCode(pc+%i)<<8)|GetCode(pc+%i);\n",
361 padding+3, padding+4);
362 padding++;
363 break;
364
365 case 1:
366 fprintf(dest, " arg2 = GetCode(pc+%i);\n",
367 padding+3);
368 break;
369
370 case 2:
371 fprintf(dest, " arg2 = GetVar(GetCode(pc+%i));\n",
372 padding+3);
373 break;
374
375 case 3:
376 fprintf(dest, " arg2 = 0;\n");
377 padding--;
378 break;
379 }
380 if (y==3)
381 fprintf(dest, " omit = 0;\n");
382 else if (z==3)
383 fprintf(dest, " omit = 1;\n");
384 else
385 fprintf(dest, " omit = 2;\n");
386
387 fprintf(dest, " padding = %i;\n", padding);
388 fprintf(dest, " goto loop;\n");
389 }
390 }
391 fprintf(dest, " default:\n");
392 fprintf(dest, " zmachine_fatal(\"Invalid argument types for 2OP %s\");\n", op->name);
393 fprintf(dest, " }\n");
394 #else
395
396 fprintf(dest, " padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock)-2;\n");
397 #endif
398
399 if (op->flags.isstore)
400 {
401 fprintf(dest, " st = GetCode(pc+%i+padding);\n", pcadd);
402 pcadd++;
403 }
404 if (op->flags.isbranch)
405 {
406 fprintf(dest, " tmp = GetCode(pc+%i+padding);\n", pcadd);
407 fprintf(dest, " branch = tmp&0x3f;\n");
408 fprintf(dest, " if (!(tmp&0x40))\n");
409 fprintf(dest, " {\n");
410 fprintf(dest, " padding++;\n");
411 fprintf(dest, " if (branch&0x20)\n");
412 fprintf(dest, " branch -= 64;\n");
413 fprintf(dest, " branch <<= 8;\n");
414 fprintf(dest, " branch |= GetCode(pc+%i+padding);\n",
415 pcadd);
416 fprintf(dest, " }\n");
417 fprintf(dest, " negate = tmp&0x80;\n");
418 pcadd++;
419 }
420
421 fprintf(dest, " pc += %i+padding;\n", pcadd);
422 fprintf(dest, " ");
423 output_opname(dest, op->name, op->versions);
424 fprintf(dest, "\n");
425 break;
426
427 case varop:
428 fprintf(dest, " case 0x%x: /* %s */\n",
429 op->value|0xe0, op->name);
430 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
431 op->name);
432 used_opcodes[op->value|0xe0] = 1;
433 pcadd = 2;
434 if (op->flags.islong)
435 {
436 fprintf(dest, " padding = zmachine_decode_doubleop(stack, &GetCode(pc+1), &argblock);\n");
437 pcadd++;
438 }
439 else
440 fprintf(dest, " padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock);\n");
441
442 if (op->flags.isstore)
443 {
444 fprintf(dest, " st = GetCode(pc+%i+padding);\n", pcadd);
445 pcadd++;
446 }
447 if (op->flags.isbranch)
448 {
449 fprintf(dest, " tmp = GetCode(pc+%i+padding);\n", pcadd);
450 fprintf(dest, " branch = tmp&0x3f;\n");
451 fprintf(dest, " if (!(tmp&0x40))\n");
452 fprintf(dest, " {\n");
453 fprintf(dest, " padding++;\n");
454 fprintf(dest, " if (branch&0x20)\n");
455 fprintf(dest, " branch -= 64;\n");
456 fprintf(dest, " branch <<= 8;\n");
457 fprintf(dest, " branch |= GetCode(pc+%i+padding);\n",
458 pcadd);
459 fprintf(dest, " }\n");
460 fprintf(dest, " negate = tmp&0x80;\n");
461 pcadd++;
462 }
463
464 fprintf(dest, " pc += %i+padding;\n", pcadd);
465 fprintf(dest, " ");
466 output_opname(dest, op->name, op->versions);
467 fprintf(dest, "\n");
468 break;
469
470 case extop:
471 /* Dealt with later */
472 break;
473 }
474 }
475 else
476 {
477 fprintf(dest, notimpl, op->name);
478 }
479 }
480
481 if (version != -1) /* Extops do not exist generally */
482 {
483 fprintf(dest, " case 0x%x: /* Extended ops */\n", 190);
484 fprintf(dest, " switch (GetCode(pc+1))\n");
485 fprintf(dest, " {\n");
486
487 for (x=0; x<zmachine.numops; x++)
488 {
489 operation* op;
490
491 op = zmachine.op[x];
492
493 if (op->type == extop && op->versions&vmask)
494 {
495 fprintf(dest, " case 0x%x: /* %s */\n", op->value, op->name);
496 fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"ExtOp: %s\\n\");\n#endif\n", op->name);
497 pcadd = 3;
498 if (op->flags.islong)
499 {
500 fprintf(dest, " padding = zmachine_decode_doubleop(stack, &GetCode(pc+2), &argblock);\n");
501 pcadd++;
502 }
503 else
504 fprintf(dest, " padding = zmachine_decode_varop(stack, &GetCode(pc+2), &argblock);\n");
505
506 if (op->flags.isstore)
507 {
508 fprintf(dest, " st = GetCode(pc+%i+padding);\n", pcadd);
509 pcadd++;
510 }
511 if (op->flags.isbranch)
512 {
513 fprintf(dest, " tmp = GetCode(pc+%i+padding);\n", pcadd);
514 fprintf(dest, " branch = tmp&0x3f;\n");
515 fprintf(dest, " if (!(tmp&0x40))\n");
516 fprintf(dest, " {\n");
517 fprintf(dest, " padding++;\n");
518 fprintf(dest, " if (branch&0x20)\n");
519 fprintf(dest, " branch -= 64;\n");
520 fprintf(dest, " branch <<= 8;\n");
521 fprintf(dest, " branch |= GetCode(pc+%i+padding);\n",
522 pcadd);
523 fprintf(dest, " }\n");
524 fprintf(dest, " negate = tmp&0x80;\n");
525 pcadd++;
526 }
527
528 fprintf(dest, " pc+=%i+padding;\n", pcadd);
529 fprintf(dest, " ");
530 output_opname(dest, op->name, op->versions);
531 fprintf(dest, "\n");
532 }
533 }
534 fprintf(dest, " default:\n");
535 if (version != -1)
536 {
537 fprintf(dest, " zmachine_fatal(\"Unknown extended opcode: %%x\", GetCode(pc+1));\n");
538 }
539 else
540 {
541 fprintf(dest, " break;\n");
542 }
543 fprintf(dest, " }\n");
544 }
545
546 fprintf(dest, " default:\n");
547 if (version != -1)
548 {
549 fprintf(dest, " zmachine_fatal(\"Unknown opcode: %%x\", GetCode(pc));\n");
550 }
551 else
552 {
553 fprintf(dest, " goto version;\n");
554 }
555 fprintf(dest, " }\n");
556
557 fprintf(dest, " /* Unused opcodes are:\n * ");
558 for (x=0; x<256; x++)
559 {
560 if (used_opcodes[x] == 0)
561 fprintf(dest, "%02x ", x);
562 }
563 fprintf(dest, "\n */\n");
564 }
565 #else
566 #define DECODE_FLAGS(opf) \
567 if (opf.isbranch) \
568 strcat(name, "b"); \
569 if (opf.isstore) \
570 strcat(name, "s"); \
571 if (opf.isstring) \
572 strcat(name, "S"); \
573 if (opf.islong) \
574 strcat(name, "l"); \
575 if (opf.reallyvar) \
576 strcat(name, "v");
577
decode_name(enum optype type,opflags fl)578 char* decode_name(enum optype type, opflags fl)
579 {
580 static char name[256];
581 const char* prefix;
582
583 switch(type)
584 {
585 case zop:
586 prefix = "zop";
587 break;
588
589 case unop:
590 prefix = "unop";
591 break;
592
593 case binop:
594 prefix = "binop";
595 break;
596
597 case varop:
598 prefix = "varop";
599 break;
600
601 case extop:
602 prefix = "extop";
603 break;
604
605 default:
606 prefix = "unk";
607 }
608
609 sprintf(name, "%s", prefix);
610 DECODE_FLAGS(fl);
611
612 return name;
613 }
614
output_interpreter(FILE * dest,int version)615 void output_interpreter(FILE* dest,
616 int version)
617 {
618 /*
619 * The 'interpreter', such as it is now, is just two tables of goto
620 * addresses... We do need to work out the decode codepoints, though.
621 */
622 int x, y;
623 int vmask;
624 int pcadd;
625
626 char* decode_table[256];
627 char* exec_table[256];
628 char* decode_ext_table[256];
629 char* exec_ext_table[256];
630
631 vmask = 1<<version;
632
633 for (x=0; x<256; x++)
634 {
635 decode_table[x] = exec_table[x] = decode_ext_table[x] =
636 exec_ext_table[x] = "badop";
637 }
638
639 /* Instruction decoders */
640 /*
641 * I'm basing this largely on my old code, hence the rather unusual way
642 * of enumerating these things. This technique at least guarantees
643 * no deadcode...
644 */
645 fprintf(dest, "#ifndef TABLES_ONLY\n");
646 for (x=0; x<zmachine.numops; x++)
647 {
648 operation* op;
649
650 op = zmachine.op[x];
651
652 if (op->versions&vmask)
653 {
654 char* name;
655 char* opname;
656
657 name = decode_name(op->type, op->flags);
658 fprintf(dest, "#ifndef D_%s\n", name);
659 fprintf(dest, "#define D_%s\n", name);
660
661 opname = malloc(strlen(op->name) + 10);
662 sprintf(opname, "op_%s", op->name);
663 if (op->versions != -1)
664 {
665 int z;
666 strcat(opname, "_");
667 for (z = 1; z<10; z++)
668 {
669 char s[2];
670
671 s[0] = 48+z; s[1] = 0;
672 if (op->versions&(1<<z))
673 strcat(opname, s);
674 }
675 }
676
677 switch (op->type)
678 {
679 case zop:
680 pcadd = 1;
681 fprintf(dest, " %s:\n", name);
682
683 decode_table[op->value|0xb0] = malloc(strlen(name)+1);
684 strcpy(decode_table[op->value|0xb0], name);
685
686 exec_table[op->value|0xb0] = opname;
687
688 if (op->flags.isstore)
689 {
690 fprintf(dest, " st = GetCode(pc+%i);\n", pcadd);
691 pcadd++;
692 }
693 if (op->flags.isbranch)
694 {
695 fprintf(dest, " tmp = GetCode(pc+%i);\n", pcadd);
696 fprintf(dest, " branch = tmp&0x3f;\n");
697 fprintf(dest, " padding=0;\n");
698 fprintf(dest, " if (!(tmp&0x40))\n");
699 fprintf(dest, " {\n");
700 fprintf(dest, " padding = 1;\n");
701 fprintf(dest, " if (branch&0x20)\n");
702 fprintf(dest, " branch -= 64;\n");
703 fprintf(dest, " branch <<= 8;\n");
704 fprintf(dest, " branch |= GetCode(pc+%i);\n",
705 pcadd+1);
706 fprintf(dest, " }\n");
707 fprintf(dest, " negate = tmp&0x80;\n");
708 pcadd++;
709 }
710 if (op->flags.isstring)
711 {
712 fprintf(dest, " string = zscii_to_unicode(&GetCode(pc+%i), &padding);\n", pcadd);
713 }
714
715 if (op->flags.isbranch || op->flags.isstring)
716 fprintf(dest, " pc += %i+padding;\n", pcadd);
717 else
718 fprintf(dest, " pc += %i;\n", pcadd);
719
720 fprintf(dest, " goto *exec[instr];\n");
721 fprintf(dest, "\n");
722 break;
723
724 case unop:
725 for (y=0; y<3; y++)
726 {
727 pcadd = 1;
728 fprintf(dest, " %s_%i:\n", name, y);
729
730 decode_table[op->value|0x80|(y<<4)] = malloc(strlen(name)+4);
731 sprintf(decode_table[op->value|0x80|(y<<4)], "%s_%i", name, y);
732
733 exec_table[op->value|0x80|(y<<4)] = opname;
734
735 switch (y)
736 {
737 case 0:
738 fprintf(dest, " arg1 = (GetCode(pc+%i)<<8)|GetCode(pc+%i);\n", pcadd, pcadd+1);
739 pcadd+=2;
740 break;
741
742 case 1:
743 fprintf(dest, " arg1 = GetCode(pc+%i);\n",
744 pcadd);
745 pcadd++;
746 break;
747
748 case 2:
749 fprintf(dest, " arg1 = GetVar(GetCode(pc+%i));\n",
750 pcadd);
751 pcadd++;
752 break;
753 }
754
755 if (op->flags.isstore)
756 {
757 fprintf(dest, " st = GetCode(pc+%i);\n", pcadd);
758 pcadd++;
759 }
760 if (op->flags.isbranch)
761 {
762 fprintf(dest, " tmp = GetCode(pc+%i);\n", pcadd);
763 fprintf(dest, " branch = tmp&0x3f;\n");
764 fprintf(dest, " padding=0;\n");
765 fprintf(dest, " if (!(tmp&0x40))\n");
766 fprintf(dest, " {\n");
767 fprintf(dest, " padding = 1;\n");
768 fprintf(dest, " if (branch&0x20)\n");
769 fprintf(dest, " branch -= 64;\n");
770 fprintf(dest, " branch <<= 8;\n");
771 fprintf(dest, " branch |= GetCode(pc+%i);\n",
772 pcadd+1);
773 fprintf(dest, " }\n");
774 fprintf(dest, " negate = tmp&0x80;\n");
775 pcadd++;
776 }
777 if (op->flags.isstring)
778 {
779 fprintf(dest, " /* Implement me */\n");
780 }
781
782 if (op->flags.isbranch || op->flags.isstring)
783 fprintf(dest, " pc += %i+padding;\n", pcadd);
784 else
785 fprintf(dest, " pc += %i;\n", pcadd);
786
787 fprintf(dest, " goto *exec[instr];\n");
788 fprintf(dest, "\n");
789 }
790 break;
791
792 case binop:
793 for (y=0; y<4; y++)
794 {
795 fprintf(dest, " %s_%i:\n", name, y);
796
797 decode_table[op->value|(y<<5)] = malloc(strlen(name)+4);
798 sprintf(decode_table[op->value|(y<<5)],
799 "%s_%i", name, y);
800
801 exec_table[op->value|(y<<5)] = opname;
802
803 pcadd = 1;
804
805 if (op->flags.reallyvar)
806 fprintf(dest, " argblock.n_args = 2;\n");
807 if (y&2)
808 fprintf(dest, " arg1 = GetVar(GetCode(pc+1));\n");
809 else
810 fprintf(dest, " arg1 = GetCode(pc+1);\n");
811 if (y&1)
812 fprintf(dest, " arg2 = GetVar(GetCode(pc+2));\n");
813 else
814 fprintf(dest, " arg2 = GetCode(pc+2);\n");
815 pcadd+=2;
816
817 if (op->flags.isstore)
818 {
819 fprintf(dest, " st = GetCode(pc+%i);\n", pcadd);
820 pcadd++;
821 }
822 if (op->flags.isbranch)
823 {
824 fprintf(dest, " tmp = GetCode(pc+%i);\n", pcadd);
825 fprintf(dest, " branch = tmp&0x3f;\n");
826 fprintf(dest, " padding=0;\n");
827 fprintf(dest, " if (!(tmp&0x40))\n");
828 fprintf(dest, " {\n");
829 fprintf(dest, " padding = 1;\n");
830 fprintf(dest, " if (branch&0x20)\n");
831 fprintf(dest, " branch -= 64;\n");
832 fprintf(dest, " branch <<= 8;\n");
833 fprintf(dest, " branch |= GetCode(pc+%i);\n",
834 pcadd+1);
835 fprintf(dest, " }\n");
836 fprintf(dest, " negate = tmp&0x80;\n");
837 pcadd++;
838 }
839
840 if (op->flags.isbranch || op->flags.isstring)
841 fprintf(dest, " pc += %i+padding;\n", pcadd);
842 else
843 fprintf(dest, " pc += %i;\n", pcadd);
844
845 fprintf(dest, " goto *exec[instr];\n");
846 }
847
848 fprintf(dest, " %s_var:\n", name);
849 pcadd = 4;
850 fprintf(dest, " padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock)-2;\n");
851
852 decode_table[op->value|0xc0] = malloc(strlen(name)+5);
853 sprintf(decode_table[op->value|0xc0], "%s_var", name);
854
855 exec_table[op->value|0xc0] = opname;
856
857 if (op->flags.isstore)
858 {
859 fprintf(dest, " st = GetCode(pc+%i+padding);\n", pcadd);
860 pcadd++;
861 }
862 if (op->flags.isbranch)
863 {
864 fprintf(dest, " tmp = GetCode(pc+%i+padding);\n", pcadd);
865 fprintf(dest, " branch = tmp&0x3f;\n");
866 fprintf(dest, " if (!(tmp&0x40))\n");
867 fprintf(dest, " {\n");
868 fprintf(dest, " padding++;\n");
869 fprintf(dest, " if (branch&0x20)\n");
870 fprintf(dest, " branch -= 64;\n");
871 fprintf(dest, " branch <<= 8;\n");
872 fprintf(dest, " branch |= GetCode(pc+%i+padding);\n",
873 pcadd);
874 fprintf(dest, " }\n");
875 fprintf(dest, " negate = tmp&0x80;\n");
876 pcadd++;
877 }
878
879 fprintf(dest, " pc += %i+padding;\n", pcadd);
880 fprintf(dest, " goto *exec[instr];\n");
881 break;
882
883 case varop:
884 fprintf(dest, " %s:\n", name);
885
886 decode_table[op->value|0xe0] = malloc(strlen(name)+1);
887 strcpy(decode_table[op->value|0xe0], name);
888
889 exec_table[op->value|0xe0] = opname;
890
891 pcadd = 2;
892 if (op->flags.islong)
893 {
894 fprintf(dest, " padding = zmachine_decode_doubleop(stack, &GetCode(pc+1), &argblock);\n");
895 pcadd++;
896 }
897 else
898 fprintf(dest, " padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock);\n");
899
900 if (op->flags.isstore)
901 {
902 fprintf(dest, " st = GetCode(pc+%i+padding);\n", pcadd);
903 pcadd++;
904 }
905 if (op->flags.isbranch)
906 {
907 fprintf(dest, " tmp = GetCode(pc+%i+padding);\n", pcadd);
908 fprintf(dest, " branch = tmp&0x3f;\n");
909 fprintf(dest, " if (!(tmp&0x40))\n");
910 fprintf(dest, " {\n");
911 fprintf(dest, " padding++;\n");
912 fprintf(dest, " if (branch&0x20)\n");
913 fprintf(dest, " branch -= 64;\n");
914 fprintf(dest, " branch <<= 8;\n");
915 fprintf(dest, " branch |= GetCode(pc+%i+padding);\n",
916 pcadd);
917 fprintf(dest, " }\n");
918 fprintf(dest, " negate = tmp&0x80;\n");
919 pcadd++;
920 }
921
922 fprintf(dest, " pc += %i+padding;\n", pcadd);
923 fprintf(dest, " goto *exec[instr];\n");
924 break;
925
926 case extop:
927 fprintf(dest, " %s:\n", name);
928
929 decode_ext_table[op->value] = malloc(strlen(name)+1);
930 strcpy(decode_ext_table[op->value], name);
931
932 exec_ext_table[op->value] = opname;
933
934 pcadd = 3;
935 if (op->flags.islong)
936 {
937 fprintf(dest, " padding = zmachine_decode_doubleop(stack, &GetCode(pc+2), &argblock);\n");
938 pcadd++;
939 }
940 else
941 fprintf(dest, " padding = zmachine_decode_varop(stack, &GetCode(pc+2), &argblock);\n");
942
943 if (op->flags.isstore)
944 {
945 fprintf(dest, " st = GetCode(pc+%i+padding);\n", pcadd);
946 pcadd++;
947 }
948 if (op->flags.isbranch)
949 {
950 fprintf(dest, " tmp = GetCode(pc+%i+padding);\n", pcadd);
951 fprintf(dest, " branch = tmp&0x3f;\n");
952 fprintf(dest, " if (!(tmp&0x40))\n");
953 fprintf(dest, " {\n");
954 fprintf(dest, " padding++;\n");
955 fprintf(dest, " if (branch&0x20)\n");
956 fprintf(dest, " branch -= 64;\n");
957 fprintf(dest, " branch <<= 8;\n");
958 fprintf(dest, " branch |= GetCode(pc+%i+padding);\n",
959 pcadd);
960 fprintf(dest, " }\n");
961 fprintf(dest, " negate = tmp&0x80;\n");
962 pcadd++;
963 }
964
965 fprintf(dest, " pc+=%i+padding;\n", pcadd);
966 fprintf(dest, " goto *exec_ext[instr];\n");
967 break;
968 }
969
970 fprintf(dest, "#endif\n");
971 }
972 }
973
974 decode_table[190] = "execute_ext_op";
975
976 fprintf(dest, "#else\n");
977 /* Output the tables */
978 if (version > 0)
979 {
980 fprintf (dest, " static const void* decode_v%i[256] = {", version);
981 for (x=0; x<256; x++)
982 {
983 if ((x&0x3) == 0)
984 fprintf(dest, "\n ");
985 fprintf(dest, "&&%s,\t", decode_table[x]);
986 }
987 fprintf(dest, "\n };\n");
988
989 fprintf (dest, " static const void* decode_ext_v%i[256] = {", version);
990 for (x=0; x<256; x++)
991 {
992 if ((x&0x3) == 0)
993 fprintf(dest, "\n ");
994 fprintf(dest, "&&%s,\t", decode_ext_table[x]);
995 }
996 fprintf(dest, "\n };\n");
997
998 fprintf (dest, " static const void* exec_v%i[256] = {", version);
999 for (x=0; x<256; x++)
1000 {
1001 if ((x&0x3) == 0)
1002 fprintf(dest, "\n ");
1003 fprintf(dest, "&&%s,\t", exec_table[x]);
1004 }
1005 fprintf(dest, "\n };\n");
1006
1007 fprintf (dest, " static const void* exec_ext_v%i[256] = {", version);
1008 for (x=0; x<256; x++)
1009 {
1010 if ((x&0x3) == 0)
1011 fprintf(dest, "\n ");
1012 fprintf(dest, "&&%s,\t", exec_ext_table[x]);
1013 }
1014 fprintf(dest, "\n };\n");
1015 }
1016 fprintf(dest, "#endif\n");
1017 }
1018 #endif
1019
output_operations(FILE * dest,int ver)1020 void output_operations(FILE* dest,
1021 int ver)
1022 {
1023 int x, z;
1024 int versions, vmask;
1025
1026 vmask = 1<<ver;
1027
1028 for (x=0; x<zmachine.numops; x++)
1029 {
1030 operation* op;
1031
1032 op = zmachine.op[x];
1033
1034 versions = op->versions;
1035 if ((op->versions&vmask && op->versions != -1) ||
1036 (ver==-1 && op->versions == -1))
1037 {
1038 fprintf(dest, "#ifndef ZCODE_OP_%s", op->name);
1039 VERSIONS;
1040 fprintf(dest, "\n");
1041 fprintf(dest, "# define ZCODE_OP_%s", op->name);
1042 VERSIONS;
1043 fprintf(dest, "\n");
1044
1045 fprintf(dest, " op_%s", op->name);
1046 VERSIONS;
1047 fprintf(dest, ":\n");
1048
1049 if (op->code == NULL)
1050 fprintf(dest, " zmachine_warning(\"%s not implemented\");\n", op->name);
1051 else
1052 {
1053 fprintf(dest, " {\n");
1054 fprintf(dest, "#line %i \"%s\"\n", op->codeline, filename);
1055 fprintf(dest, "%s\n", op->code);
1056 fprintf(dest, " }\n");
1057 }
1058
1059 fprintf(dest, " goto loop;\n\n");
1060 fprintf(dest, "#endif\n");
1061 }
1062 }
1063 }
1064
1065 extern FILE* yyin;
1066
main(int argc,char ** argv)1067 int main(int argc, char** argv)
1068 {
1069 if (argc==4)
1070 {
1071 FILE* output;
1072
1073 if (!(yyin = fopen(filename=argv[3], "r")))
1074 {
1075 fprintf(stderr, "Couldn't open input file\n");
1076 return 1;
1077 }
1078
1079 printf("Zoom interpreter builder");
1080 #ifndef HAVE_COMPUTED_GOTOS
1081 printf(" (using giant switch statement)\n");
1082 #else
1083 printf(" (using computed GOTOs)\n");
1084 #endif
1085
1086 yyline = 1;
1087 zmachine.numops = 0;
1088 zmachine.op = NULL;
1089 yyparse();
1090
1091 qsort(zmachine.op, zmachine.numops-1, sizeof(operation*), sortops);
1092
1093 if ((output = fopen(argv[1], "w")))
1094 {
1095 output_interpreter(output, atoi(argv[2]));
1096 fprintf(output, "#ifndef TABLES_ONLY\n");
1097 output_operations(output, atoi(argv[2]));
1098 fprintf(output, "#endif\n");
1099 fclose(output);
1100 }
1101 else
1102 {
1103 fprintf(stderr, "Couldn't output open file\n");
1104 return 1;
1105 }
1106 }
1107 else
1108 {
1109 fprintf(stderr, "Incorrect arguments\n");
1110 return 1;
1111 }
1112
1113 return 0;
1114 }
1115