1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.zmpp.vm;
24
25 import org.zmpp.base.MemoryReadAccess;
26
27
28 /***
29 * This class represents instructions of type LONG, 2OP.
30 *
31 * @author Wei-ju Wu
32 * @version 1.0
33 */
34 public class LongInstruction extends AbstractInstruction {
35
36 /***
37 * List of opcodes. See Z-Machine Standards document 1.0 for
38 * explanations.
39 */
40 public static final int OP_JE = 0x01;
41 public static final int OP_JL = 0x02;
42 public static final int OP_JG = 0x03;
43 public static final int OP_DEC_CHK = 0x04;
44 public static final int OP_INC_CHK = 0x05;
45 public static final int OP_JIN = 0x06;
46 public static final int OP_TEST = 0x07;
47 public static final int OP_OR = 0x08;
48 public static final int OP_AND = 0x09;
49 public static final int OP_TEST_ATTR = 0x0a;
50 public static final int OP_SET_ATTR = 0x0b;
51 public static final int OP_CLEAR_ATTR = 0x0c;
52 public static final int OP_STORE = 0x0d;
53 public static final int OP_INSERT_OBJ = 0x0e;
54 public static final int OP_LOADW = 0x0f;
55 public static final int OP_LOADB = 0x10;
56 public static final int OP_GET_PROP = 0x11;
57 public static final int OP_GET_PROP_ADDR = 0x12;
58 public static final int OP_GET_NEXT_PROP = 0x13;
59 public static final int OP_ADD = 0x14;
60 public static final int OP_SUB = 0x15;
61 public static final int OP_MUL = 0x16;
62 public static final int OP_DIV = 0x17;
63 public static final int OP_MOD = 0x18;
64
65 /***
66 * The operand count.
67 */
68 private OperandCount operandCount;
69
70 /***
71 * Constructor.
72 *
73 * @param machineState a reference to a MachineState object
74 * @param opcode the instruction's opcode
75 */
76 public LongInstruction(Machine machineState, int opcode) {
77
78 super(machineState, opcode);
79 this.operandCount = OperandCount.C2OP;
80 }
81
82 /***
83 * Constructor.
84 *
85 * @param machineState the machine state
86 * @param operandCount the operand count
87 * @param opcode the opcode
88 */
89 public LongInstruction(Machine machineState,
90 OperandCount operandCount, int opcode) {
91
92 super(machineState, opcode);
93 this.operandCount = operandCount;
94 }
95
96 /***
97 * {@inheritDoc}
98 */
99 public void execute() {
100
101 switch (getOpcode()) {
102
103 case OP_JE:
104 je();
105 break;
106 case OP_JL:
107 jl();
108 break;
109 case OP_JG:
110 jg();
111 break;
112 case OP_JIN:
113 jin();
114 break;
115 case OP_DEC_CHK:
116 decChk();
117 break;
118 case OP_INC_CHK:
119 incChk();
120 break;
121 case OP_TEST:
122 test();
123 break;
124 case OP_OR:
125 or();
126 break;
127 case OP_AND:
128 and();
129 break;
130 case OP_TEST_ATTR:
131 testAttr();
132 break;
133 case OP_SET_ATTR:
134 setAttr();
135 break;
136 case OP_CLEAR_ATTR:
137 clearAttr();
138 break;
139 case OP_STORE:
140 store();
141 break;
142 case OP_INSERT_OBJ:
143 insertObj();
144 break;
145 case OP_LOADW:
146 loadw();
147 break;
148 case OP_LOADB:
149 loadb();
150 break;
151 case OP_GET_PROP:
152 getProp();
153 break;
154 case OP_GET_PROP_ADDR:
155 getPropAddr();
156 break;
157 case OP_GET_NEXT_PROP:
158 getNextProp();
159 break;
160 case OP_ADD:
161 add();
162 break;
163 case OP_SUB:
164 sub();
165 break;
166 case OP_MUL:
167 mul();
168 break;
169 case OP_DIV:
170 div();
171 break;
172 case OP_MOD:
173 mod();
174 break;
175 default:
176 throwInvalidOpcode();
177 }
178 }
179
180 /***
181 * {@inheritDoc}
182 */
183 public InstructionForm getInstructionForm() { return InstructionForm.LONG; }
184
185 /***
186 * {@inheritDoc}
187 */
188 public OperandCount getOperandCount() { return operandCount; }
189
190 /***
191 * {@inheritDoc}
192 */
193 public boolean storesResult() {
194
195 switch (getOpcode()) {
196 case OP_OR:
197 case OP_AND:
198 case OP_LOADW:
199 case OP_LOADB:
200 case OP_GET_PROP:
201 case OP_GET_PROP_ADDR:
202 case OP_GET_NEXT_PROP:
203 case OP_ADD:
204 case OP_SUB:
205 case OP_MUL:
206 case OP_DIV:
207 case OP_MOD:
208 return true;
209 default:
210 return false;
211 }
212 }
213
214 /***
215 * {@inheritDoc}
216 */
217 public boolean isBranch() {
218
219 switch (getOpcode()) {
220 case OP_JE:
221 case OP_JL:
222 case OP_JG:
223 case OP_DEC_CHK:
224 case OP_INC_CHK:
225 case OP_JIN:
226 case OP_TEST:
227 case OP_TEST_ATTR:
228 return true;
229 default:
230 return false;
231 }
232 }
233
234 private void je() {
235
236 boolean equalsFollowing = false;
237 short op1 = getValue(0);
238 if (getNumOperands() <= 1) {
239
240 getMachine().halt("je expects at least two operands, only " +
241 "one provided");
242 } else {
243
244 for (int i = 1; i < getNumOperands(); i++) {
245
246 if (op1 == getValue(i)) {
247
248 equalsFollowing = true;
249 break;
250 }
251 }
252 branchOnTest(equalsFollowing);
253 }
254 }
255
256 private void jl() {
257
258 short op1 = getValue(0);
259 short op2 = getValue(1);
260 branchOnTest(op1 < op2);
261 }
262
263 private void jg() {
264
265 short op1 = getValue(0);
266 short op2 = getValue(1);
267 branchOnTest(op1 > op2);
268 }
269
270 private void jin() {
271
272 int obj1 = getUnsignedValue(0);
273 int obj2 = getUnsignedValue(1);
274 ZObject zobj1 = getMachine().getObjectTree().getObject(obj1);
275 branchOnTest(zobj1.getParent() == obj2);
276 }
277
278 private void decChk() {
279
280 int varnum = getUnsignedValue(0);
281 short value = getValue(1);
282 short varValue = (short) (getMachine().getVariable(varnum) - 1);
283
284 getMachine().setVariable(varnum, varValue);
285 branchOnTest(varValue < value);
286 }
287
288 private void incChk() {
289
290 int varnum = getUnsignedValue(0);
291 short value = getValue(1);
292 short varValue = (short) (getMachine().getVariable(varnum) + 1);
293
294 getMachine().setVariable(varnum, varValue);
295 branchOnTest(varValue > value);
296 }
297
298 private void test() {
299
300 int op1 = getUnsignedValue(0);
301 int op2 = getUnsignedValue(1);
302 branchOnTest((op1 & op2) == op2);
303 }
304
305 private void or() {
306
307 int op1 = getUnsignedValue(0);
308 int op2 = getUnsignedValue(1);
309 storeResult((short) ((op1 | op2) & 0xffff));
310 nextInstruction();
311 }
312
313 private void and() {
314
315 int op1 = getUnsignedValue(0);
316 int op2 = getUnsignedValue(1);
317 storeResult((short) ((op1 & op2) & 0xffff));
318 nextInstruction();
319 }
320
321 private void add() {
322
323 short op1 = getValue(0);
324 short op2 = getValue(1);
325 storeResult((short) (op1 + op2));
326 nextInstruction();
327 }
328
329 private void sub() {
330
331 short op1 = getValue(0);
332 short op2 = getValue(1);
333 storeResult((short) (op1 - op2));
334 nextInstruction();
335 }
336
337 private void mul() {
338
339 short op1 = getValue(0);
340 short op2 = getValue(1);
341 storeResult((short)(op1 * op2));
342 nextInstruction();
343 }
344
345 private void div() {
346
347 short op1 = getValue(0);
348 short op2 = getValue(1);
349 storeResult((short) (op1 / op2));
350 nextInstruction();
351 }
352
353 private void mod() {
354
355 short op1 = getValue(0);
356 short op2 = getValue(1);
357 storeResult((short) (op1 % op2));
358 nextInstruction();
359 }
360
361 private void testAttr() {
362
363 int obj = getUnsignedValue(0);
364 int attr = getUnsignedValue(1);
365 ZObject zobj = getMachine().getObjectTree().getObject(obj);
366 branchOnTest(zobj.isAttributeSet(attr));
367 }
368
369 private void setAttr() {
370
371 int obj = getUnsignedValue(0);
372 int attr = getUnsignedValue(1);
373 ZObject zobj = getMachine().getObjectTree().getObject(obj);
374 zobj.setAttribute(attr);
375 nextInstruction();
376 }
377
378 private void clearAttr() {
379
380 int obj = getUnsignedValue(0);
381 int attr = getUnsignedValue(1);
382 ZObject zobj = getMachine().getObjectTree().getObject(obj);
383 zobj.clearAttribute(attr);
384 nextInstruction();
385 }
386
387 private void store() {
388
389 int varnum = getUnsignedValue(0);
390 short value = getValue(1);
391
392
393 if (varnum == 0) {
394
395 getMachine().setStackTopElement(value);
396
397 } else {
398
399 getMachine().setVariable(varnum, value);
400 }
401 nextInstruction();
402 }
403
404 private void insertObj() {
405
406 int obj = getUnsignedValue(0);
407 int dest = getUnsignedValue(1);
408 ObjectTree objectTree = getMachine().getObjectTree();
409 objectTree.insertObject(dest, obj);
410 nextInstruction();
411 }
412
413 private void loadw() {
414
415 int arrayAddress = getUnsignedValue(0);
416 int index = getUnsignedValue(1);
417 MemoryReadAccess memaccess = getMachine().getMemoryAccess();
418 storeResult(memaccess.readShort(arrayAddress + 2 * index));
419 nextInstruction();
420 }
421
422 private void loadb() {
423
424 int arrayAddress = getUnsignedValue(0);
425 int index = getUnsignedValue(1);
426 MemoryReadAccess memaccess = getMachine().getMemoryAccess();
427 storeResult((short) memaccess.readUnsignedByte(arrayAddress + index));
428 nextInstruction();
429 }
430
431 private void getProp() {
432
433 int obj = getUnsignedValue(0);
434 int property = getUnsignedValue(1);
435 ZObject zobj = getMachine().getObjectTree().getObject(obj);
436 int numBytes = zobj.getPropertySize(property);
437 short value;
438
439 if (!zobj.isPropertyAvailable(property)) {
440
441
442 value = getMachine().getObjectTree().getPropertyDefault(property);
443
444 } else if (numBytes == 1) {
445
446 value = zobj.getPropertyByte(property, 0);
447
448 } else {
449
450 byte byte1 = zobj.getPropertyByte(property, 0);
451 byte byte2 = zobj.getPropertyByte(property, 1);
452 value = (short) (byte1 << 8 | (byte2 & 0xff));
453 }
454 storeResult(value);
455 nextInstruction();
456 }
457
458 private void getPropAddr() {
459
460 int obj = getUnsignedValue(0);
461 int property = getUnsignedValue(1);
462
463 short value = 0;
464 ZObject zobj = getMachine().getObjectTree().getObject(obj);
465
466 if (zobj.isPropertyAvailable(property)) {
467
468 value = (short) (zobj.getPropertyAddress(property) & 0xffff);
469 }
470 storeResult(value);
471 nextInstruction();
472 }
473
474 private void getNextProp() {
475
476 int obj = getUnsignedValue(0);
477 int property = getUnsignedValue(1);
478 short value = 0;
479 ZObject zobj = getMachine().getObjectTree().getObject(obj);
480
481 if (property == 0 || zobj.isPropertyAvailable(property)) {
482
483 value = (short) (zobj.getNextProperty(property) & 0xffff);
484 storeResult(value);
485 nextInstruction();
486
487 } else {
488
489 getMachine().halt("the property [" + property + "] of object [" + obj
490 + "] does not exist");
491 }
492 }
493 }