File indexing completed on 2025-02-02 04:26:02

0001 /* Copyright 2015 the unarr project authors (see AUTHORS file).
0002    License: LGPLv3 */
0003 
0004 /* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.c */
0005 
0006 #include "rarvm.h"
0007 #include "../common/allocator.h"
0008 
0009 #include <stdlib.h>
0010 #include <string.h>
0011 
0012 typedef struct RAROpcode_s RAROpcode;
0013 
0014 struct RAROpcode_s {
0015     uint8_t instruction;
0016     uint8_t bytemode;
0017     uint8_t addressingmode1;
0018     uint8_t addressingmode2;
0019     uint32_t value1;
0020     uint32_t value2;
0021 };
0022 
0023 struct RARProgram_s {
0024     RAROpcode *opcodes;
0025     uint32_t length;
0026     uint32_t capacity;
0027 };
0028 
0029 /* Program building */
0030 
0031 RARProgram *RARCreateProgram()
0032 {
0033     return calloc(1, sizeof(RARProgram));
0034 }
0035 
0036 void RARDeleteProgram(RARProgram *prog)
0037 {
0038     if (prog)
0039         free(prog->opcodes);
0040     free(prog);
0041 }
0042 
0043 bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode)
0044 {
0045     if (instruction >= RARNumberOfInstructions)
0046         return false;
0047     if (bytemode && !RARInstructionHasByteMode(instruction))
0048         return false;
0049     if (prog->length + 1 >= prog->capacity) {
0050         /* in my small file sample, 16 is the value needed most often */
0051         uint32_t newCapacity = prog->capacity ? prog->capacity * 4 : 32;
0052         RAROpcode *newCodes = calloc(newCapacity, sizeof(*prog->opcodes));
0053         if (!newCodes)
0054             return false;
0055         memcpy(newCodes, prog->opcodes, prog->capacity * sizeof(*prog->opcodes));
0056         free(prog->opcodes);
0057         prog->opcodes = newCodes;
0058         prog->capacity = newCapacity;
0059     }
0060     memset(&prog->opcodes[prog->length], 0, sizeof(prog->opcodes[prog->length]));
0061     prog->opcodes[prog->length].instruction = instruction;
0062     if (instruction == RARMovzxInstruction || instruction == RARMovsxInstruction)
0063         prog->opcodes[prog->length].bytemode = 2; /* second argument only */
0064     else if (bytemode)
0065         prog->opcodes[prog->length].bytemode = (1 | 2);
0066     else
0067         prog->opcodes[prog->length].bytemode = 0;
0068     prog->length++;
0069     return true;
0070 }
0071 
0072 bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2)
0073 {
0074     RAROpcode *opcode = &prog->opcodes[prog->length - 1];
0075     int numoperands;
0076 
0077     if (addressingmode1 >= RARNumberOfAddressingModes || addressingmode2 >= RARNumberOfAddressingModes)
0078         return false;
0079     if (!prog->length || opcode->addressingmode1 || opcode->value1 || opcode->addressingmode2 || opcode->value2)
0080         return false;
0081 
0082     numoperands = NumberOfRARInstructionOperands(opcode->instruction);
0083     if (numoperands == 0)
0084         return true;
0085 
0086     if (addressingmode1 == RARImmediateAddressingMode && RARInstructionWritesFirstOperand(opcode->instruction))
0087         return false;
0088     opcode->addressingmode1 = addressingmode1;
0089     opcode->value1 = value1;
0090 
0091     if (numoperands == 2) {
0092         if (addressingmode2 == RARImmediateAddressingMode && RARInstructionWritesSecondOperand(opcode->instruction))
0093             return false;
0094         opcode->addressingmode2 = addressingmode2;
0095         opcode->value2 = value2;
0096     }
0097 
0098     return true;
0099 }
0100 
0101 bool RARIsProgramTerminated(RARProgram *prog)
0102 {
0103     return prog->length > 0 && RARInstructionIsUnconditionalJump(prog->opcodes[prog->length - 1].instruction);
0104 }
0105 
0106 /* Execution */
0107 
0108 #define EXTMACRO_BEGIN do {
0109 #ifdef _MSC_VER
0110 #define EXTMACRO_END } __pragma(warning(push)) __pragma(warning(disable:4127)) while (0) __pragma(warning(pop))
0111 #else
0112 #define EXTMACRO_END } while (0)
0113 #endif
0114 
0115 #define CarryFlag 1
0116 #define ZeroFlag 2
0117 #define SignFlag 0x80000000
0118 
0119 #define SignExtend(a) ((uint32_t)((int8_t)(a)))
0120 
0121 static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode);
0122 static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data);
0123 
0124 #define GetOperand1() _RARGetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1)
0125 #define GetOperand2() _RARGetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2)
0126 #define SetOperand1(data) _RARSetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1, data)
0127 #define SetOperand2(data) _RARSetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2, data)
0128 
0129 #define SetFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t result = (res); flags = (result == 0 ? ZeroFlag : (result & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END
0130 #define SetByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t result = (res); flags = (result == 0 ? ZeroFlag : (SignExtend(result) & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END
0131 #define SetFlags(res) SetFlagsWithCarry(res, 0)
0132 
0133 #define SetOperand1AndFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t r = (res); SetFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END
0134 #define SetOperand1AndByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t r = (res); SetByteFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END
0135 #define SetOperand1AndFlags(res) EXTMACRO_BEGIN uint32_t r = (res); SetFlags(r); SetOperand1(r); EXTMACRO_END
0136 
0137 #define NextInstruction() { opcode++; continue; }
0138 #define Jump(offs) { uint32_t o = (offs); if (o >= prog->length) return false; opcode = &prog->opcodes[o]; continue; }
0139 
0140 bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog)
0141 {
0142     RAROpcode *opcode = prog->opcodes;
0143     uint32_t flags = 0;
0144     uint32_t op1, op2, carry, i;
0145     uint32_t counter = 0;
0146 
0147     if (!RARIsProgramTerminated(prog))
0148         return false;
0149 
0150     while ((uint32_t)(opcode - prog->opcodes) < prog->length && counter++ < RARRuntimeMaxInstructions) {
0151         switch (opcode->instruction) {
0152         case RARMovInstruction:
0153             SetOperand1(GetOperand2());
0154             NextInstruction();
0155 
0156         case RARCmpInstruction:
0157             op1 = GetOperand1();
0158             SetFlagsWithCarry(op1 - GetOperand2(), result > op1);
0159             NextInstruction();
0160 
0161         case RARAddInstruction:
0162             op1 = GetOperand1();
0163             if (opcode->bytemode)
0164                 SetOperand1AndByteFlagsWithCarry((op1 + GetOperand2()) & 0xFF, result < op1);
0165             else
0166                 SetOperand1AndFlagsWithCarry(op1 + GetOperand2(), result < op1);
0167             NextInstruction();
0168 
0169         case RARSubInstruction:
0170             op1 = GetOperand1();
0171 #if 0 /* apparently not correctly implemented in the RAR VM */
0172             if (opcode->bytemode)
0173                 SetOperand1AndByteFlagsWithCarry((op1 - GetOperand2()) & 0xFF, result > op1);
0174             else
0175 #endif
0176             SetOperand1AndFlagsWithCarry(op1 - GetOperand2(), result > op1);
0177             NextInstruction();
0178 
0179         case RARJzInstruction:
0180             if ((flags & ZeroFlag))
0181                 Jump(GetOperand1());
0182             NextInstruction();
0183 
0184         case RARJnzInstruction:
0185             if (!(flags & ZeroFlag))
0186                 Jump(GetOperand1());
0187             NextInstruction();
0188 
0189         case RARIncInstruction:
0190             if (opcode->bytemode)
0191                 SetOperand1AndFlags((GetOperand1() + 1) & 0xFF);
0192             else
0193                 SetOperand1AndFlags(GetOperand1() + 1);
0194             NextInstruction();
0195 
0196         case RARDecInstruction:
0197             if (opcode->bytemode)
0198                 SetOperand1AndFlags((GetOperand1() - 1) & 0xFF);
0199             else
0200                 SetOperand1AndFlags(GetOperand1() - 1);
0201             NextInstruction();
0202 
0203         case RARJmpInstruction:
0204             Jump(GetOperand1());
0205 
0206         case RARXorInstruction:
0207             SetOperand1AndFlags(GetOperand1() ^ GetOperand2());
0208             NextInstruction();
0209 
0210         case RARAndInstruction:
0211             SetOperand1AndFlags(GetOperand1() & GetOperand2());
0212             NextInstruction();
0213 
0214         case RAROrInstruction:
0215             SetOperand1AndFlags(GetOperand1() | GetOperand2());
0216             NextInstruction();
0217 
0218         case RARTestInstruction:
0219             SetFlags(GetOperand1() & GetOperand2());
0220             NextInstruction();
0221 
0222         case RARJsInstruction:
0223             if ((flags & SignFlag))
0224                 Jump(GetOperand1());
0225             NextInstruction();
0226 
0227         case RARJnsInstruction:
0228             if (!(flags & SignFlag))
0229                 Jump(GetOperand1());
0230             NextInstruction();
0231 
0232         case RARJbInstruction:
0233             if ((flags & CarryFlag))
0234                 Jump(GetOperand1());
0235             NextInstruction();
0236 
0237         case RARJbeInstruction:
0238             if ((flags & (CarryFlag | ZeroFlag)))
0239                 Jump(GetOperand1());
0240             NextInstruction();
0241 
0242         case RARJaInstruction:
0243             if (!(flags & (CarryFlag | ZeroFlag)))
0244                 Jump(GetOperand1());
0245             NextInstruction();
0246 
0247         case RARJaeInstruction:
0248             if (!(flags & CarryFlag))
0249                 Jump(GetOperand1());
0250             NextInstruction();
0251 
0252         case RARPushInstruction:
0253             vm->registers[7] -= 4;
0254             RARVirtualMachineWrite32(vm, vm->registers[7], GetOperand1());
0255             NextInstruction();
0256 
0257         case RARPopInstruction:
0258             SetOperand1(RARVirtualMachineRead32(vm, vm->registers[7]));
0259             vm->registers[7] += 4;
0260             NextInstruction();
0261 
0262         case RARCallInstruction:
0263             vm->registers[7] -= 4;
0264             RARVirtualMachineWrite32(vm, vm->registers[7], (uint32_t)(opcode - prog->opcodes + 1));
0265             Jump(GetOperand1());
0266 
0267         case RARRetInstruction:
0268             if (vm->registers[7] >= RARProgramMemorySize)
0269                 return true;
0270             i = RARVirtualMachineRead32(vm, vm->registers[7]);
0271             vm->registers[7] += 4;
0272             Jump(i);
0273 
0274         case RARNotInstruction:
0275             SetOperand1(~GetOperand1());
0276             NextInstruction();
0277 
0278         case RARShlInstruction:
0279             op1 = GetOperand1();
0280             op2 = GetOperand2();
0281             SetOperand1AndFlagsWithCarry(op1 << op2, ((op1 << (op2 - 1)) & 0x80000000) != 0);
0282             NextInstruction();
0283 
0284         case RARShrInstruction:
0285             op1 = GetOperand1();
0286             op2 = GetOperand2();
0287             SetOperand1AndFlagsWithCarry(op1 >> op2, ((op1 >> (op2 - 1)) & 1) != 0);
0288             NextInstruction();
0289 
0290         case RARSarInstruction:
0291             op1 = GetOperand1();
0292             op2 = GetOperand2();
0293             SetOperand1AndFlagsWithCarry(((int32_t)op1) >> op2, ((op1 >> (op2 - 1)) & 1) != 0);
0294             NextInstruction();
0295 
0296         case RARNegInstruction:
0297             SetOperand1AndFlagsWithCarry(-(int32_t)GetOperand1(), result != 0);
0298             NextInstruction();
0299 
0300         case RARPushaInstruction:
0301             vm->registers[7] -= 32;
0302             for (i = 0; i < 8; i++)
0303                 RARVirtualMachineWrite32(vm, vm->registers[7] + (7 - i) * 4, vm->registers[i]);
0304             NextInstruction();
0305 
0306         case RARPopaInstruction:
0307             for (i = 0; i < 8; i++)
0308                 vm->registers[i] = RARVirtualMachineRead32(vm, vm->registers[7] + (7 - i) * 4);
0309             vm->registers[7] += 32;
0310             NextInstruction();
0311 
0312         case RARPushfInstruction:
0313             vm->registers[7] -= 4;
0314             RARVirtualMachineWrite32(vm, vm->registers[7], flags);
0315             NextInstruction();
0316 
0317         case RARPopfInstruction:
0318             flags = RARVirtualMachineRead32(vm, vm->registers[7]);
0319             vm->registers[7] += 4;
0320             NextInstruction();
0321 
0322         case RARMovzxInstruction:
0323             SetOperand1(GetOperand2());
0324             NextInstruction();
0325 
0326         case RARMovsxInstruction:
0327             SetOperand1(SignExtend(GetOperand2()));
0328             NextInstruction();
0329 
0330         case RARXchgInstruction:
0331             op1 = GetOperand1();
0332             op2 = GetOperand2();
0333             SetOperand1(op2);
0334             SetOperand2(op1);
0335             NextInstruction();
0336 
0337         case RARMulInstruction:
0338             SetOperand1(GetOperand1() * GetOperand2());
0339             NextInstruction();
0340 
0341         case RARDivInstruction:
0342             op2 = GetOperand2();
0343             if (op2 != 0)
0344                 SetOperand1(GetOperand1() / op2);
0345             NextInstruction();
0346 
0347         case RARAdcInstruction:
0348             op1 = GetOperand1();
0349             carry = (flags & CarryFlag);
0350             if (opcode->bytemode)
0351                 SetOperand1AndFlagsWithCarry((op1 + GetOperand2() + carry) & 0xFF, result < op1 || (result == op1 && carry)); /* does not correctly set sign bit */
0352             else
0353                 SetOperand1AndFlagsWithCarry(op1 + GetOperand2() + carry, result < op1 || (result == op1 && carry));
0354             NextInstruction();
0355 
0356         case RARSbbInstruction:
0357             op1 = GetOperand1();
0358             carry = (flags & CarryFlag);
0359             if (opcode->bytemode)
0360                 SetOperand1AndFlagsWithCarry((op1 - GetOperand2() - carry) & 0xFF, result > op1 || (result == op1 && carry)); /* does not correctly set sign bit */
0361             else
0362                 SetOperand1AndFlagsWithCarry(op1 - GetOperand2() - carry, result > op1 || (result == op1 && carry));
0363             NextInstruction();
0364 
0365         case RARPrintInstruction:
0366             /* TODO: ??? */
0367             NextInstruction();
0368         }
0369     }
0370 
0371     return false;
0372 }
0373 
0374 /* Memory and register access */
0375 
0376 static uint32_t _RARRead32(const uint8_t *b)
0377 {
0378     return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0];
0379 }
0380 
0381 static void _RARWrite32(uint8_t *b, uint32_t n)
0382 {
0383     b[3] = (n >> 24) & 0xFF;
0384     b[2] = (n >> 16) & 0xFF;
0385     b[1] = (n >> 8) & 0xFF;
0386     b[0] = n & 0xFF;
0387 }
0388 
0389 void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8])
0390 {
0391     if (registers)
0392         memcpy(vm->registers, registers, sizeof(vm->registers));
0393     else
0394         memset(vm->registers, 0, sizeof(vm->registers));
0395 }
0396 
0397 uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address)
0398 {
0399     return _RARRead32(&vm->memory[address & RARProgramMemoryMask]);
0400 }
0401 
0402 void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val)
0403 {
0404     _RARWrite32(&vm->memory[address & RARProgramMemoryMask], val);
0405 }
0406 
0407 uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address)
0408 {
0409     return vm->memory[address & RARProgramMemoryMask];
0410 }
0411 
0412 void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val)
0413 {
0414     vm->memory[address & RARProgramMemoryMask] = val;
0415 }
0416 
0417 static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode)
0418 {
0419     if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) {
0420         uint32_t result = vm->registers[addressingmode % 8];
0421         if (bytemode)
0422             result = result & 0xFF;
0423         return result;
0424     }
0425     if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) {
0426         if (bytemode)
0427             return RARVirtualMachineRead8(vm, vm->registers[addressingmode % 8]);
0428         return RARVirtualMachineRead32(vm, vm->registers[addressingmode % 8]);
0429     }
0430     if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) {
0431         if (bytemode)
0432             return RARVirtualMachineRead8(vm, value + vm->registers[addressingmode % 8]);
0433         return RARVirtualMachineRead32(vm, value + vm->registers[addressingmode % 8]);
0434     }
0435     if (addressingmode == RARAbsoluteAddressingMode) {
0436         if (bytemode)
0437             return RARVirtualMachineRead8(vm, value);
0438         return RARVirtualMachineRead32(vm, value);
0439     }
0440     /* if (addressingmode == RARImmediateAddressingMode) */
0441     return value;
0442 }
0443 
0444 static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data)
0445 {
0446     if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) {
0447         if (bytemode)
0448             data = data & 0xFF;
0449         vm->registers[addressingmode % 8] = data;
0450     }
0451     else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) {
0452         if (bytemode)
0453             RARVirtualMachineWrite8(vm, vm->registers[addressingmode % 8], (uint8_t)data);
0454         else
0455             RARVirtualMachineWrite32(vm, vm->registers[addressingmode % 8], data);
0456     }
0457     else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) {
0458         if (bytemode)
0459             RARVirtualMachineWrite8(vm, value + vm->registers[addressingmode % 8], (uint8_t)data);
0460         else
0461             RARVirtualMachineWrite32(vm, value + vm->registers[addressingmode % 8], data);
0462     }
0463     else if (addressingmode == RARAbsoluteAddressingMode) {
0464         if (bytemode)
0465             RARVirtualMachineWrite8(vm, value, (uint8_t)data);
0466         else
0467             RARVirtualMachineWrite32(vm, value, data);
0468     }
0469 }
0470 
0471 /* Instruction properties */
0472 
0473 #define RAR0OperandsFlag 0
0474 #define RAR1OperandFlag 1
0475 #define RAR2OperandsFlag 2
0476 #define RAROperandsFlag 3
0477 #define RARHasByteModeFlag 4
0478 #define RARIsUnconditionalJumpFlag 8
0479 #define RARIsRelativeJumpFlag 16
0480 #define RARWritesFirstOperandFlag 32
0481 #define RARWritesSecondOperandFlag 64
0482 #define RARReadsStatusFlag 128
0483 #define RARWritesStatusFlag 256
0484 
0485 static const int InstructionFlags[RARNumberOfInstructions] = {
0486     /*RARMovInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
0487     /*RARCmpInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
0488     /*RARAddInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0489     /*RARSubInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0490     /*RARJzInstruction*/ RAR1OperandFlag | RARIsUnconditionalJumpFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0491     /*RARJnzInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0492     /*RARIncInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0493     /*RARDecInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0494     /*RARJmpInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
0495     /*RARXorInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0496     /*RARAndInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0497     /*RAROrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0498     /*RARTestInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
0499     /*RARJsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0500     /*RARJnsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0501     /*RARJbInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0502     /*RARJbeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0503     /*RARJaInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0504     /*RARJaeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
0505     /*RARPushInstruction*/ RAR1OperandFlag,
0506     /*RARPopInstruction*/ RAR1OperandFlag,
0507     /*RARCallInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
0508     /*RARRetInstruction*/ RAR0OperandsFlag | RARIsUnconditionalJumpFlag,
0509     /*RARNotInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
0510     /*RARShlInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0511     /*RARShrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0512     /*RARSarInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0513     /*RARNegInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
0514     /*RARPushaInstruction*/ RAR0OperandsFlag,
0515     /*RARPopaInstruction*/ RAR0OperandsFlag,
0516     /*RARPushfInstruction*/ RAR0OperandsFlag | RARReadsStatusFlag,
0517     /*RARPopfInstruction*/ RAR0OperandsFlag | RARWritesStatusFlag,
0518     /*RARMovzxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag,
0519     /*RARMovsxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag,
0520     /*RARXchgInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag | RARWritesSecondOperandFlag | RARHasByteModeFlag,
0521     /*RARMulInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
0522     /*RARDivInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
0523     /*RARAdcInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag,
0524     /*RARSbbInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag,
0525     /*RARPrintInstruction*/ RAR0OperandsFlag
0526 };
0527 
0528 int NumberOfRARInstructionOperands(uint8_t instruction)
0529 {
0530     if (instruction >= RARNumberOfInstructions)
0531         return 0;
0532     return InstructionFlags[instruction] & RAROperandsFlag;
0533 }
0534 
0535 bool RARInstructionHasByteMode(uint8_t instruction)
0536 {
0537     if (instruction >= RARNumberOfInstructions)
0538         return false;
0539     return (InstructionFlags[instruction] & RARHasByteModeFlag)!=0;
0540 }
0541 
0542 bool RARInstructionIsUnconditionalJump(uint8_t instruction)
0543 {
0544     if (instruction >= RARNumberOfInstructions)
0545         return false;
0546     return (InstructionFlags[instruction] & RARIsUnconditionalJumpFlag) != 0;
0547 }
0548 
0549 bool RARInstructionIsRelativeJump(uint8_t instruction)
0550 {
0551     if (instruction >= RARNumberOfInstructions)
0552         return false;
0553     return (InstructionFlags[instruction] & RARIsRelativeJumpFlag) != 0;
0554 }
0555 
0556 bool RARInstructionWritesFirstOperand(uint8_t instruction)
0557 {
0558     if (instruction >= RARNumberOfInstructions)
0559         return false;
0560     return (InstructionFlags[instruction] & RARWritesFirstOperandFlag) != 0;
0561 }
0562 
0563 bool RARInstructionWritesSecondOperand(uint8_t instruction)
0564 {
0565     if (instruction >= RARNumberOfInstructions)
0566         return false;
0567     return (InstructionFlags[instruction] & RARWritesSecondOperandFlag) != 0;
0568 }
0569 
0570 /* Program debugging */
0571 
0572 #ifndef NDEBUG
0573 #include <stdio.h>
0574 
0575 static void RARPrintOperand(uint8_t addressingmode, uint32_t value)
0576 {
0577     if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7))
0578         printf("r%d", addressingmode % 8);
0579     else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7))
0580         printf("@(r%d)", addressingmode % 8);
0581     else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7))
0582         printf("@(r%d+$%02x)", addressingmode % 8, value);
0583     else if (addressingmode == RARAbsoluteAddressingMode)
0584         printf("@($%02x)", value);
0585     else if (addressingmode == RARImmediateAddressingMode)
0586         printf("$%02x", value);
0587 }
0588 
0589 void RARPrintProgram(RARProgram *prog)
0590 {
0591     static const char *instructionNames[RARNumberOfInstructions] = {
0592         "Mov", "Cmp", "Add", "Sub", "Jz", "Jnz", "Inc", "Dec", "Jmp", "Xor",
0593         "And", "Or", "Test", "Js", "Jns", "Jb", "Jbe", "Ja", "Jae", "Push",
0594         "Pop", "Call", "Ret", "Not", "Shl", "Shr", "Sar", "Neg", "Pusha", "Popa",
0595         "Pushf", "Popf", "Movzx", "Movsx", "Xchg", "Mul", "Div", "Adc", "Sbb", "Print",
0596     };
0597 
0598     uint32_t i;
0599     for (i = 0; i < prog->length; i++) {
0600         RAROpcode *opcode = &prog->opcodes[i];
0601         int numoperands = NumberOfRARInstructionOperands(opcode->instruction);
0602         printf("  %02x: %s", i, instructionNames[opcode->instruction]);
0603         if (opcode->bytemode)
0604             printf("B");
0605         if (numoperands >= 1) {
0606             printf(" ");
0607             RARPrintOperand(opcode->addressingmode1, opcode->value1);
0608         }
0609         if (numoperands == 2) {
0610             printf(", ");
0611             RARPrintOperand(opcode->addressingmode2, opcode->value2);
0612         }
0613         printf("\n");
0614     }
0615 }
0616 #endif