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 {
24 RAROpcode *opcodes;
25 uint32_t length;
26 uint32_t capacity;
27 };
28
29 /* Program building */
30
RARCreateProgram()31 RARProgram *RARCreateProgram()
32 {
33 return calloc(1, sizeof(RARProgram));
34 }
35
RARDeleteProgram(RARProgram * prog)36 void RARDeleteProgram(RARProgram *prog)
37 {
38 if (prog)
39 free(prog->opcodes);
40 free(prog);
41 }
42
RARProgramAddInstr(RARProgram * prog,uint8_t instruction,bool bytemode)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
RARSetLastInstrOperands(RARProgram * prog,uint8_t addressingmode1,uint32_t value1,uint8_t addressingmode2,uint32_t value2)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
86 if (addressingmode1 == RARImmediateAddressingMode && RARInstructionWritesFirstOperand(opcode->instruction))
87 return false;
88 opcode->addressingmode1 = addressingmode1;
89 opcode->value1 = value1;
90
91 if (numoperands == 2) {
92 if (addressingmode2 == RARImmediateAddressingMode && RARInstructionWritesSecondOperand(opcode->instruction))
93 return false;
94 opcode->addressingmode2 = addressingmode2;
95 opcode->value2 = value2;
96 }
97
98 return true;
99 }
100
RARIsProgramTerminated(RARProgram * prog)101 bool RARIsProgramTerminated(RARProgram *prog)
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
RARExecuteProgram(RARVirtualMachine * vm,RARProgram * prog)140 bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog)
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:
153 SetOperand1(GetOperand2());
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
193 SetOperand1AndFlags(GetOperand1() + 1);
194 NextInstruction();
195
196 case RARDecInstruction:
197 if (opcode->bytemode)
198 SetOperand1AndFlags((GetOperand1() - 1) & 0xFF);
199 else
200 SetOperand1AndFlags(GetOperand1() - 1);
201 NextInstruction();
202
203 case RARJmpInstruction:
204 Jump(GetOperand1());
205
206 case RARXorInstruction:
207 SetOperand1AndFlags(GetOperand1() ^ GetOperand2());
208 NextInstruction();
209
210 case RARAndInstruction:
211 SetOperand1AndFlags(GetOperand1() & GetOperand2());
212 NextInstruction();
213
214 case RAROrInstruction:
215 SetOperand1AndFlags(GetOperand1() | GetOperand2());
216 NextInstruction();
217
218 case RARTestInstruction:
219 SetFlags(GetOperand1() & GetOperand2());
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;
254 RARVirtualMachineWrite32(vm, vm->registers[7], GetOperand1());
255 NextInstruction();
256
257 case RARPopInstruction:
258 SetOperand1(RARVirtualMachineRead32(vm, vm->registers[7]));
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:
275 SetOperand1(~GetOperand1());
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:
323 SetOperand1(GetOperand2());
324 NextInstruction();
325
326 case RARMovsxInstruction:
327 SetOperand1(SignExtend(GetOperand2()));
328 NextInstruction();
329
330 case RARXchgInstruction:
331 op1 = GetOperand1();
332 op2 = GetOperand2();
333 SetOperand1(op2);
334 SetOperand2(op1);
335 NextInstruction();
336
337 case RARMulInstruction:
338 SetOperand1(GetOperand1() * GetOperand2());
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
_RARRead32(const uint8_t * b)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
_RARWrite32(uint8_t * b,uint32_t n)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
RARSetVirtualMachineRegisters(RARVirtualMachine * vm,uint32_t registers[8])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
RARVirtualMachineRead32(RARVirtualMachine * vm,uint32_t address)397 uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address)
398 {
399 return _RARRead32(&vm->memory[address & RARProgramMemoryMask]);
400 }
401
RARVirtualMachineWrite32(RARVirtualMachine * vm,uint32_t address,uint32_t val)402 void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val)
403 {
404 _RARWrite32(&vm->memory[address & RARProgramMemoryMask], val);
405 }
406
RARVirtualMachineRead8(RARVirtualMachine * vm,uint32_t address)407 uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address)
408 {
409 return vm->memory[address & RARProgramMemoryMask];
410 }
411
RARVirtualMachineWrite8(RARVirtualMachine * vm,uint32_t address,uint8_t val)412 void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val)
413 {
414 vm->memory[address & RARProgramMemoryMask] = val;
415 }
416
_RARGetOperand(RARVirtualMachine * vm,uint8_t addressingmode,uint32_t value,bool bytemode)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
_RARSetOperand(RARVirtualMachine * vm,uint8_t addressingmode,uint32_t value,bool bytemode,uint32_t data)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
485 static const int InstructionFlags[RARNumberOfInstructions] = {
486 /*RARMovInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
487 /*RARCmpInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
488 /*RARAddInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
489 /*RARSubInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
490 /*RARJzInstruction*/ RAR1OperandFlag | RARIsUnconditionalJumpFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
491 /*RARJnzInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
492 /*RARIncInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
493 /*RARDecInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
494 /*RARJmpInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
495 /*RARXorInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
496 /*RARAndInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
497 /*RAROrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
498 /*RARTestInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
499 /*RARJsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
500 /*RARJnsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
501 /*RARJbInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
502 /*RARJbeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
503 /*RARJaInstruction*/ 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,
510 /*RARShlInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
511 /*RARShrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
512 /*RARSarInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
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,
520 /*RARXchgInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag | RARWritesSecondOperandFlag | RARHasByteModeFlag,
521 /*RARMulInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
522 /*RARDivInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
523 /*RARAdcInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag,
524 /*RARSbbInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag,
525 /*RARPrintInstruction*/ RAR0OperandsFlag
526 };
527
NumberOfRARInstructionOperands(uint8_t instruction)528 int NumberOfRARInstructionOperands(uint8_t instruction)
529 {
530 if (instruction >= RARNumberOfInstructions)
531 return 0;
532 return InstructionFlags[instruction] & RAROperandsFlag;
533 }
534
RARInstructionHasByteMode(uint8_t instruction)535 bool RARInstructionHasByteMode(uint8_t instruction)
536 {
537 if (instruction >= RARNumberOfInstructions)
538 return false;
539 return (InstructionFlags[instruction] & RARHasByteModeFlag)!=0;
540 }
541
RARInstructionIsUnconditionalJump(uint8_t instruction)542 bool RARInstructionIsUnconditionalJump(uint8_t instruction)
543 {
544 if (instruction >= RARNumberOfInstructions)
545 return false;
546 return (InstructionFlags[instruction] & RARIsUnconditionalJumpFlag) != 0;
547 }
548
RARInstructionIsRelativeJump(uint8_t instruction)549 bool RARInstructionIsRelativeJump(uint8_t instruction)
550 {
551 if (instruction >= RARNumberOfInstructions)
552 return false;
553 return (InstructionFlags[instruction] & RARIsRelativeJumpFlag) != 0;
554 }
555
RARInstructionWritesFirstOperand(uint8_t instruction)556 bool RARInstructionWritesFirstOperand(uint8_t instruction)
557 {
558 if (instruction >= RARNumberOfInstructions)
559 return false;
560 return (InstructionFlags[instruction] & RARWritesFirstOperandFlag) != 0;
561 }
562
RARInstructionWritesSecondOperand(uint8_t instruction)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
RARPrintOperand(uint8_t addressingmode,uint32_t value)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
RARPrintProgram(RARProgram * prog)589 void RARPrintProgram(RARProgram *prog)
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
617