Bug fixes
[rodin/chimara.git] / interpreters / nitfol / decode.c
1 /*  Nitfol - z-machine interpreter using Glk for output.
2     Copyright (C) 1999  Evin Robertson
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
17
18     The author can be reached at nitfol@deja.com
19 */
20 #include "nitfol.h"
21
22 void decode(void)
23 {
24   unsigned optypes;
25   int maxoperands;
26
27   while(!exit_decoder) {
28     zbyte opcode = HIBYTE(PC);
29
30     oldPC = PC;
31
32 #ifdef DEBUGGING
33     if(do_check_watches)
34       check_watches();
35 #endif
36
37     PC++;
38
39 #ifndef NO_TICK
40     glk_tick();  /* tick tock hickery dock the mouse ran up the clock */
41 #endif
42     
43     /* Top bits decide opcode/operand encoding */
44     switch(opcode >> 4) {
45     case 0: case 1:                         /* long 2OP */
46       operand[0] = HIBYTE(PC);              /* small constant */
47       operand[1] = HIBYTE(PC+1);            /* small constant */
48       numoperands = 2; PC += 2;
49       opcode += OFFSET_2OP - 0x00;
50       break;
51
52
53     case 2: case 3:                         /* long 2OP */
54       operand[0] = HIBYTE(PC);              /* small constant */
55       operand[1] = get_var(HIBYTE(PC+1));   /* variable */
56       numoperands = 2; PC += 2;
57       opcode += OFFSET_2OP - 0x20;
58       break;
59
60
61     case 4: case 5:                         /* long 2OP */
62       operand[0] = get_var(HIBYTE(PC));     /* variable */
63       operand[1] = HIBYTE(PC+1);            /* small constant */
64       numoperands = 2; PC += 2;
65       opcode += OFFSET_2OP - 0x40;
66       break;
67
68
69     case 6: case 7:                         /* long 2OP */
70       operand[0] = get_var(HIBYTE(PC));     /* variable */
71       operand[1] = get_var(HIBYTE(PC+1));   /* variable */
72       numoperands = 2; PC += 2;
73       opcode += OFFSET_2OP - 0x60;
74       break;
75
76
77     case 8:                                 /* short 1OP */
78       operand[0] = HIWORD(PC);              /* large constant */
79       numoperands = 1; PC += ZWORD_SIZE;
80       opcode += OFFSET_1OP - 0x80;
81       break;
82
83
84     case 9:                                 /* short 1OP */
85       operand[0] = HIBYTE(PC);              /* small constant */
86       numoperands = 1; PC += 1;
87       opcode += OFFSET_1OP - 0x90;
88       break;
89
90
91     case 10:                                /* short 1OP */
92       operand[0] = get_var(HIBYTE(PC));     /* variable */
93       numoperands = 1; PC += 1;
94       opcode += OFFSET_1OP - 0xa0;
95       break;
96
97
98     case 11:                                /* short 0OP */
99       if(opcode != 0xbe) {
100         numoperands = 0;
101         opcode += OFFSET_0OP - 0xb0;
102         break;
103       }
104                                             /* EXTENDED */
105       opcode  = HIBYTE(PC);   /* Get the extended opcode */
106       optypes = HIBYTE(PC+1);
107       PC += 2;
108
109 #ifndef FAST
110       if(OFFSET_EXT + opcode > OFFSET_END) {
111         n_show_error(E_INSTR, "unknown extended opcode", opcode);
112         break;
113       }
114 #endif
115       
116       for(numoperands = 0; numoperands < 4; numoperands++) {
117         switch(optypes & (3 << 6)) {   /* Look at the highest two bits. */
118         case 0 << 6:
119           operand[numoperands] = HIWORD(PC); PC+=ZWORD_SIZE; break;
120         case 1 << 6:
121           operand[numoperands] = HIBYTE(PC); PC++; break;
122         case 2 << 6:
123           operand[numoperands] = get_var(HIBYTE(PC)); PC++; break;
124         default:
125           goto END_OF_EXTENDED;   /* inky says, "use the goto." */
126         }
127         optypes <<= 2;    /* Move the next two bits into position. */
128       }
129     END_OF_EXTENDED:
130       opcode += OFFSET_EXT;
131       break;
132
133     case 12: case 13: case 14: case 15:     /* variable operand count */
134       maxoperands = 4;
135       optypes = ((unsigned) HIBYTE(PC)) << 8; /* Shift left so our loop will */
136                                     /* be the same for both 4 and 8 operands */
137       PC++;
138   
139       if(opcode == 0xec || opcode == 0xfa) {  /* call_vs2 and call_vn2 */
140         maxoperands = 8;
141         optypes |= HIBYTE(PC);  /* Fill the bottom 8 bits */
142         PC++;
143       }
144       
145       for(numoperands = 0; numoperands < maxoperands; numoperands++) {
146         switch(optypes & (3 << 14)) {   /* Look at the highest two bits. */
147         case 0 << 14:
148           operand[numoperands] = HIWORD(PC); PC+=ZWORD_SIZE; break;
149         case 1 << 14:
150           operand[numoperands] = HIBYTE(PC); PC++; break;
151         case 2 << 14:
152           operand[numoperands] = get_var(HIBYTE(PC)); PC++; break;
153         default:
154           goto END_OF_VARIABLE;
155         }
156         optypes <<= 2;    /* Move the next two bits into position. */
157       }
158     END_OF_VARIABLE:
159       opcode += OFFSET_2OP - 0xc0;
160       break;
161     }
162     opcodetable[opcode]();
163   }
164 }