Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
rarvm.c
Go to the documentation of this file.
1 /* Copyright 2015 the unarr project authors (see AUTHORS file).
2  License: LGPLv3 */
3 
4 /* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.c */
5 
6 #include "rarvm.h"
7 #include "../common/allocator.h"
8 
9 #include <stdlib.h>
10 #include <string.h>
11 
12 typedef struct RAROpcode_s RAROpcode;
13 
14 struct RAROpcode_s {
15  uint8_t instruction;
16  uint8_t bytemode;
17  uint8_t addressingmode1;
18  uint8_t addressingmode2;
19  uint32_t value1;
20  uint32_t value2;
21 };
22 
23 struct RARProgram_s {
25  uint32_t length;
26  uint32_t capacity;
27 };
28 
29 /* Program building */
30 
32 {
33  return calloc(1, sizeof(RARProgram));
34 }
35 
37 {
38  if (prog)
39  free(prog->opcodes);
40  free(prog);
41 }
42 
43 bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode)
44 {
45  if (instruction >= RARNumberOfInstructions)
46  return false;
47  if (bytemode && !RARInstructionHasByteMode(instruction))
48  return false;
49  if (prog->length + 1 >= prog->capacity) {
50  /* in my small file sample, 16 is the value needed most often */
51  uint32_t newCapacity = prog->capacity ? prog->capacity * 4 : 32;
52  RAROpcode *newCodes = calloc(newCapacity, sizeof(*prog->opcodes));
53  if (!newCodes)
54  return false;
55  memcpy(newCodes, prog->opcodes, prog->capacity * sizeof(*prog->opcodes));
56  free(prog->opcodes);
57  prog->opcodes = newCodes;
58  prog->capacity = newCapacity;
59  }
60  memset(&prog->opcodes[prog->length], 0, sizeof(prog->opcodes[prog->length]));
61  prog->opcodes[prog->length].instruction = instruction;
62  if (instruction == RARMovzxInstruction || instruction == RARMovsxInstruction)
63  prog->opcodes[prog->length].bytemode = 2; /* second argument only */
64  else if (bytemode)
65  prog->opcodes[prog->length].bytemode = (1 | 2);
66  else
67  prog->opcodes[prog->length].bytemode = 0;
68  prog->length++;
69  return true;
70 }
71 
72 bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2)
73 {
74  RAROpcode *opcode = &prog->opcodes[prog->length - 1];
75  int numoperands;
76 
77  if (addressingmode1 >= RARNumberOfAddressingModes || addressingmode2 >= RARNumberOfAddressingModes)
78  return false;
79  if (!prog->length || opcode->addressingmode1 || opcode->value1 || opcode->addressingmode2 || opcode->value2)
80  return false;
81 
82  numoperands = NumberOfRARInstructionOperands(opcode->instruction);
83  if (numoperands == 0)
84  return true;
85 
87  return false;
88  opcode->addressingmode1 = addressingmode1;
89  opcode->value1 = value1;
90 
91  if (numoperands == 2) {
93  return false;
94  opcode->addressingmode2 = addressingmode2;
95  opcode->value2 = value2;
96  }
97 
98  return true;
99 }
100 
102 {
103  return prog->length > 0 && RARInstructionIsUnconditionalJump(prog->opcodes[prog->length - 1].instruction);
104 }
105 
106 /* Execution */
107 
108 #define EXTMACRO_BEGIN do {
109 #ifdef _MSC_VER
110 #define EXTMACRO_END } __pragma(warning(push)) __pragma(warning(disable:4127)) while (0) __pragma(warning(pop))
111 #else
112 #define EXTMACRO_END } while (0)
113 #endif
114 
115 #define CarryFlag 1
116 #define ZeroFlag 2
117 #define SignFlag 0x80000000
118 
119 #define SignExtend(a) ((uint32_t)((int8_t)(a)))
120 
121 static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode);
122 static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data);
123 
124 #define GetOperand1() _RARGetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1)
125 #define GetOperand2() _RARGetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2)
126 #define SetOperand1(data) _RARSetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1, data)
127 #define SetOperand2(data) _RARSetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2, data)
128 
129 #define SetFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t result = (res); flags = (result == 0 ? ZeroFlag : (result & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END
130 #define SetByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t result = (res); flags = (result == 0 ? ZeroFlag : (SignExtend(result) & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END
131 #define SetFlags(res) SetFlagsWithCarry(res, 0)
132 
133 #define SetOperand1AndFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t r = (res); SetFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END
134 #define SetOperand1AndByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t r = (res); SetByteFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END
135 #define SetOperand1AndFlags(res) EXTMACRO_BEGIN uint32_t r = (res); SetFlags(r); SetOperand1(r); EXTMACRO_END
136 
137 #define NextInstruction() { opcode++; continue; }
138 #define Jump(offs) { uint32_t o = (offs); if (o >= prog->length) return false; opcode = &prog->opcodes[o]; continue; }
139 
141 {
142  RAROpcode *opcode = prog->opcodes;
143  uint32_t flags = 0;
144  uint32_t op1, op2, carry, i;
145  uint32_t counter = 0;
146 
147  if (!RARIsProgramTerminated(prog))
148  return false;
149 
150  while ((uint32_t)(opcode - prog->opcodes) < prog->length && counter++ < RARRuntimeMaxInstructions) {
151  switch (opcode->instruction) {
152  case RARMovInstruction:
154  NextInstruction();
155 
156  case RARCmpInstruction:
157  op1 = GetOperand1();
158  SetFlagsWithCarry(op1 - GetOperand2(), result > op1);
159  NextInstruction();
160 
161  case RARAddInstruction:
162  op1 = GetOperand1();
163  if (opcode->bytemode)
164  SetOperand1AndByteFlagsWithCarry((op1 + GetOperand2()) & 0xFF, result < op1);
165  else
166  SetOperand1AndFlagsWithCarry(op1 + GetOperand2(), result < op1);
167  NextInstruction();
168 
169  case RARSubInstruction:
170  op1 = GetOperand1();
171 #if 0 /* apparently not correctly implemented in the RAR VM */
172  if (opcode->bytemode)
173  SetOperand1AndByteFlagsWithCarry((op1 - GetOperand2()) & 0xFF, result > op1);
174  else
175 #endif
176  SetOperand1AndFlagsWithCarry(op1 - GetOperand2(), result > op1);
177  NextInstruction();
178 
179  case RARJzInstruction:
180  if ((flags & ZeroFlag))
181  Jump(GetOperand1());
182  NextInstruction();
183 
184  case RARJnzInstruction:
185  if (!(flags & ZeroFlag))
186  Jump(GetOperand1());
187  NextInstruction();
188 
189  case RARIncInstruction:
190  if (opcode->bytemode)
191  SetOperand1AndFlags((GetOperand1() + 1) & 0xFF);
192  else
194  NextInstruction();
195 
196  case RARDecInstruction:
197  if (opcode->bytemode)
198  SetOperand1AndFlags((GetOperand1() - 1) & 0xFF);
199  else
201  NextInstruction();
202 
203  case RARJmpInstruction:
204  Jump(GetOperand1());
205 
206  case RARXorInstruction:
208  NextInstruction();
209 
210  case RARAndInstruction:
212  NextInstruction();
213 
214  case RAROrInstruction:
216  NextInstruction();
217 
218  case RARTestInstruction:
220  NextInstruction();
221 
222  case RARJsInstruction:
223  if ((flags & SignFlag))
224  Jump(GetOperand1());
225  NextInstruction();
226 
227  case RARJnsInstruction:
228  if (!(flags & SignFlag))
229  Jump(GetOperand1());
230  NextInstruction();
231 
232  case RARJbInstruction:
233  if ((flags & CarryFlag))
234  Jump(GetOperand1());
235  NextInstruction();
236 
237  case RARJbeInstruction:
238  if ((flags & (CarryFlag | ZeroFlag)))
239  Jump(GetOperand1());
240  NextInstruction();
241 
242  case RARJaInstruction:
243  if (!(flags & (CarryFlag | ZeroFlag)))
244  Jump(GetOperand1());
245  NextInstruction();
246 
247  case RARJaeInstruction:
248  if (!(flags & CarryFlag))
249  Jump(GetOperand1());
250  NextInstruction();
251 
252  case RARPushInstruction:
253  vm->registers[7] -= 4;
255  NextInstruction();
256 
257  case RARPopInstruction:
259  vm->registers[7] += 4;
260  NextInstruction();
261 
262  case RARCallInstruction:
263  vm->registers[7] -= 4;
264  RARVirtualMachineWrite32(vm, vm->registers[7], (uint32_t)(opcode - prog->opcodes + 1));
265  Jump(GetOperand1());
266 
267  case RARRetInstruction:
268  if (vm->registers[7] >= RARProgramMemorySize)
269  return true;
270  i = RARVirtualMachineRead32(vm, vm->registers[7]);
271  vm->registers[7] += 4;
272  Jump(i);
273 
274  case RARNotInstruction:
276  NextInstruction();
277 
278  case RARShlInstruction:
279  op1 = GetOperand1();
280  op2 = GetOperand2();
281  SetOperand1AndFlagsWithCarry(op1 << op2, ((op1 << (op2 - 1)) & 0x80000000) != 0);
282  NextInstruction();
283 
284  case RARShrInstruction:
285  op1 = GetOperand1();
286  op2 = GetOperand2();
287  SetOperand1AndFlagsWithCarry(op1 >> op2, ((op1 >> (op2 - 1)) & 1) != 0);
288  NextInstruction();
289 
290  case RARSarInstruction:
291  op1 = GetOperand1();
292  op2 = GetOperand2();
293  SetOperand1AndFlagsWithCarry(((int32_t)op1) >> op2, ((op1 >> (op2 - 1)) & 1) != 0);
294  NextInstruction();
295 
296  case RARNegInstruction:
297  SetOperand1AndFlagsWithCarry(-(int32_t)GetOperand1(), result != 0);
298  NextInstruction();
299 
300  case RARPushaInstruction:
301  vm->registers[7] -= 32;
302  for (i = 0; i < 8; i++)
303  RARVirtualMachineWrite32(vm, vm->registers[7] + (7 - i) * 4, vm->registers[i]);
304  NextInstruction();
305 
306  case RARPopaInstruction:
307  for (i = 0; i < 8; i++)
308  vm->registers[i] = RARVirtualMachineRead32(vm, vm->registers[7] + (7 - i) * 4);
309  vm->registers[7] += 32;
310  NextInstruction();
311 
312  case RARPushfInstruction:
313  vm->registers[7] -= 4;
314  RARVirtualMachineWrite32(vm, vm->registers[7], flags);
315  NextInstruction();
316 
317  case RARPopfInstruction:
318  flags = RARVirtualMachineRead32(vm, vm->registers[7]);
319  vm->registers[7] += 4;
320  NextInstruction();
321 
322  case RARMovzxInstruction:
324  NextInstruction();
325 
326  case RARMovsxInstruction:
328  NextInstruction();
329 
330  case RARXchgInstruction:
331  op1 = GetOperand1();
332  op2 = GetOperand2();
333  SetOperand1(op2);
334  SetOperand2(op1);
335  NextInstruction();
336 
337  case RARMulInstruction:
339  NextInstruction();
340 
341  case RARDivInstruction:
342  op2 = GetOperand2();
343  if (op2 != 0)
344  SetOperand1(GetOperand1() / op2);
345  NextInstruction();
346 
347  case RARAdcInstruction:
348  op1 = GetOperand1();
349  carry = (flags & CarryFlag);
350  if (opcode->bytemode)
351  SetOperand1AndFlagsWithCarry((op1 + GetOperand2() + carry) & 0xFF, result < op1 || (result == op1 && carry)); /* does not correctly set sign bit */
352  else
353  SetOperand1AndFlagsWithCarry(op1 + GetOperand2() + carry, result < op1 || (result == op1 && carry));
354  NextInstruction();
355 
356  case RARSbbInstruction:
357  op1 = GetOperand1();
358  carry = (flags & CarryFlag);
359  if (opcode->bytemode)
360  SetOperand1AndFlagsWithCarry((op1 - GetOperand2() - carry) & 0xFF, result > op1 || (result == op1 && carry)); /* does not correctly set sign bit */
361  else
362  SetOperand1AndFlagsWithCarry(op1 - GetOperand2() - carry, result > op1 || (result == op1 && carry));
363  NextInstruction();
364 
365  case RARPrintInstruction:
366  /* TODO: ??? */
367  NextInstruction();
368  }
369  }
370 
371  return false;
372 }
373 
374 /* Memory and register access */
375 
376 static uint32_t _RARRead32(const uint8_t *b)
377 {
378  return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0];
379 }
380 
381 static void _RARWrite32(uint8_t *b, uint32_t n)
382 {
383  b[3] = (n >> 24) & 0xFF;
384  b[2] = (n >> 16) & 0xFF;
385  b[1] = (n >> 8) & 0xFF;
386  b[0] = n & 0xFF;
387 }
388 
389 void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8])
390 {
391  if (registers)
392  memcpy(vm->registers, registers, sizeof(vm->registers));
393  else
394  memset(vm->registers, 0, sizeof(vm->registers));
395 }
396 
397 uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address)
398 {
399  return _RARRead32(&vm->memory[address & RARProgramMemoryMask]);
400 }
401 
402 void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val)
403 {
404  _RARWrite32(&vm->memory[address & RARProgramMemoryMask], val);
405 }
406 
407 uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address)
408 {
409  return vm->memory[address & RARProgramMemoryMask];
410 }
411 
412 void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val)
413 {
414  vm->memory[address & RARProgramMemoryMask] = val;
415 }
416 
417 static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode)
418 {
419  if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) {
420  uint32_t result = vm->registers[addressingmode % 8];
421  if (bytemode)
422  result = result & 0xFF;
423  return result;
424  }
425  if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) {
426  if (bytemode)
427  return RARVirtualMachineRead8(vm, vm->registers[addressingmode % 8]);
428  return RARVirtualMachineRead32(vm, vm->registers[addressingmode % 8]);
429  }
430  if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) {
431  if (bytemode)
432  return RARVirtualMachineRead8(vm, value + vm->registers[addressingmode % 8]);
433  return RARVirtualMachineRead32(vm, value + vm->registers[addressingmode % 8]);
434  }
435  if (addressingmode == RARAbsoluteAddressingMode) {
436  if (bytemode)
437  return RARVirtualMachineRead8(vm, value);
438  return RARVirtualMachineRead32(vm, value);
439  }
440  /* if (addressingmode == RARImmediateAddressingMode) */
441  return value;
442 }
443 
444 static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data)
445 {
446  if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) {
447  if (bytemode)
448  data = data & 0xFF;
449  vm->registers[addressingmode % 8] = data;
450  }
451  else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) {
452  if (bytemode)
453  RARVirtualMachineWrite8(vm, vm->registers[addressingmode % 8], (uint8_t)data);
454  else
455  RARVirtualMachineWrite32(vm, vm->registers[addressingmode % 8], data);
456  }
457  else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) {
458  if (bytemode)
459  RARVirtualMachineWrite8(vm, value + vm->registers[addressingmode % 8], (uint8_t)data);
460  else
461  RARVirtualMachineWrite32(vm, value + vm->registers[addressingmode % 8], data);
462  }
463  else if (addressingmode == RARAbsoluteAddressingMode) {
464  if (bytemode)
465  RARVirtualMachineWrite8(vm, value, (uint8_t)data);
466  else
467  RARVirtualMachineWrite32(vm, value, data);
468  }
469 }
470 
471 /* Instruction properties */
472 
473 #define RAR0OperandsFlag 0
474 #define RAR1OperandFlag 1
475 #define RAR2OperandsFlag 2
476 #define RAROperandsFlag 3
477 #define RARHasByteModeFlag 4
478 #define RARIsUnconditionalJumpFlag 8
479 #define RARIsRelativeJumpFlag 16
480 #define RARWritesFirstOperandFlag 32
481 #define RARWritesSecondOperandFlag 64
482 #define RARReadsStatusFlag 128
483 #define RARWritesStatusFlag 256
484 
487  /*RARCmpInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
491  /*RARJnzInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
494  /*RARJmpInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
498  /*RARTestInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
500  /*RARJnsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
502  /*RARJbeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
504  /*RARJaeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
505  /*RARPushInstruction*/ RAR1OperandFlag,
506  /*RARPopInstruction*/ RAR1OperandFlag,
507  /*RARCallInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
508  /*RARRetInstruction*/ RAR0OperandsFlag | RARIsUnconditionalJumpFlag,
509  /*RARNotInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
513  /*RARNegInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
514  /*RARPushaInstruction*/ RAR0OperandsFlag,
515  /*RARPopaInstruction*/ RAR0OperandsFlag,
516  /*RARPushfInstruction*/ RAR0OperandsFlag | RARReadsStatusFlag,
517  /*RARPopfInstruction*/ RAR0OperandsFlag | RARWritesStatusFlag,
518  /*RARMovzxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag,
519  /*RARMovsxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag,
525  /*RARPrintInstruction*/ RAR0OperandsFlag
526 };
527 
528 int NumberOfRARInstructionOperands(uint8_t instruction)
529 {
530  if (instruction >= RARNumberOfInstructions)
531  return 0;
532  return InstructionFlags[instruction] & RAROperandsFlag;
533 }
534 
535 bool RARInstructionHasByteMode(uint8_t instruction)
536 {
537  if (instruction >= RARNumberOfInstructions)
538  return false;
539  return (InstructionFlags[instruction] & RARHasByteModeFlag)!=0;
540 }
541 
542 bool RARInstructionIsUnconditionalJump(uint8_t instruction)
543 {
544  if (instruction >= RARNumberOfInstructions)
545  return false;
546  return (InstructionFlags[instruction] & RARIsUnconditionalJumpFlag) != 0;
547 }
548 
549 bool RARInstructionIsRelativeJump(uint8_t instruction)
550 {
551  if (instruction >= RARNumberOfInstructions)
552  return false;
553  return (InstructionFlags[instruction] & RARIsRelativeJumpFlag) != 0;
554 }
555 
556 bool RARInstructionWritesFirstOperand(uint8_t instruction)
557 {
558  if (instruction >= RARNumberOfInstructions)
559  return false;
560  return (InstructionFlags[instruction] & RARWritesFirstOperandFlag) != 0;
561 }
562 
563 bool RARInstructionWritesSecondOperand(uint8_t instruction)
564 {
565  if (instruction >= RARNumberOfInstructions)
566  return false;
567  return (InstructionFlags[instruction] & RARWritesSecondOperandFlag) != 0;
568 }
569 
570 /* Program debugging */
571 
572 #ifndef NDEBUG
573 #include <stdio.h>
574 
575 static void RARPrintOperand(uint8_t addressingmode, uint32_t value)
576 {
577  if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7))
578  printf("r%d", addressingmode % 8);
579  else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7))
580  printf("@(r%d)", addressingmode % 8);
581  else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7))
582  printf("@(r%d+$%02x)", addressingmode % 8, value);
583  else if (addressingmode == RARAbsoluteAddressingMode)
584  printf("@($%02x)", value);
585  else if (addressingmode == RARImmediateAddressingMode)
586  printf("$%02x", value);
587 }
588 
590 {
591  static const char *instructionNames[RARNumberOfInstructions] = {
592  "Mov", "Cmp", "Add", "Sub", "Jz", "Jnz", "Inc", "Dec", "Jmp", "Xor",
593  "And", "Or", "Test", "Js", "Jns", "Jb", "Jbe", "Ja", "Jae", "Push",
594  "Pop", "Call", "Ret", "Not", "Shl", "Shr", "Sar", "Neg", "Pusha", "Popa",
595  "Pushf", "Popf", "Movzx", "Movsx", "Xchg", "Mul", "Div", "Adc", "Sbb", "Print",
596  };
597 
598  uint32_t i;
599  for (i = 0; i < prog->length; i++) {
600  RAROpcode *opcode = &prog->opcodes[i];
601  int numoperands = NumberOfRARInstructionOperands(opcode->instruction);
602  printf(" %02x: %s", i, instructionNames[opcode->instruction]);
603  if (opcode->bytemode)
604  printf("B");
605  if (numoperands >= 1) {
606  printf(" ");
607  RARPrintOperand(opcode->addressingmode1, opcode->value1);
608  }
609  if (numoperands == 2) {
610  printf(", ");
611  RARPrintOperand(opcode->addressingmode2, opcode->value2);
612  }
613  printf("\n");
614  }
615 }
616 #endif