Created
October 16, 2012 05:17
-
-
Save lostdj/3897335 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
enum op_codes | |
{ | |
OP_NOP=1, OP_JMP, OP_JMP_GE, | |
OP_MOV, OP_ADD, OP_MUL, | |
OP_PRINT, OP_RET | |
}; | |
typedef uint64_t inst; | |
void vm(inst *prog) | |
{ | |
int r[8]; // Registers. | |
inst *ip = prog; // Instruction pointer. | |
//static const void const *oparray[]= | |
//{ | |
// [OP_NOP]=&&op_nop, [OP_JMP]=&&op_jmp, [OP_JMP_GE]=&&op_jmp_ge, | |
// [OP_MOV]=&&op_mov, [OP_ADD]=&&op_add, [OP_MUL]=&&op_mul, | |
// [OP_PRINT]=&&op_print, [OP_RET]=&&op_ret | |
//}; | |
static const int const oparray[]= | |
{ | |
[OP_NOP]=&&op_nop - &&op_nop, [OP_JMP]=&&op_jmp - &&op_nop, [OP_JMP_GE]=&&op_jmp_ge - &&op_nop, | |
[OP_MOV]=&&op_mov - &&op_nop, [OP_ADD]=&&op_add - &&op_nop, [OP_MUL]=&&op_mul - &&op_nop, | |
[OP_PRINT]=&&op_print - &&op_nop, [OP_RET]=&&op_ret - &&op_nop | |
}; | |
//#define NEXT() ++ip; break; | |
//#define GOTO() goto *oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)]; | |
#define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] ); | |
#define NEXT() GOTO(); | |
#define R_1() r[(0x0000FFFF00000000 & *ip) >> 32] | |
#define R_2() r[(0x00000000FFFF0000 & *ip) >> 16] | |
#define R_3() r[(0x000000000000FFFF & *ip) >> 0] | |
#define IMMV_1() ((0x0000FFFF00000000 & *ip) >> 32) | |
#define IMMV_2() ((0x00000000FFFF0000 & *ip) >> 16) | |
#define IMMV_3() ((0x000000000000FFFF & *ip) >> 0) | |
// Register or immediate value. First, second and third operand. | |
// 123 opts opcode ... | |
// 11100000 11111111 ... | |
#define R_OR_IMMV_1() (((0x8000000000000000 & *ip) >> 63) ? R_1() : ((int16_t)IMMV_1())) | |
#define R_OR_IMMV_2() (((0x4000000000000000 & *ip) >> 62) ? R_2() : ((int16_t)IMMV_2())) | |
#define R_OR_IMMV_3() (((0x2000000000000000 & *ip) >> 61) ? R_3() : ((int16_t)IMMV_3())) | |
uint16_t op; | |
while(1) | |
{ | |
op = (uint16_t)((0x00FF000000000000 & *ip) >> 48); | |
// opts opcode operands | |
// 00000000 11111111 00000000 00000000 00000000 00000000 00000000 00000000 | |
switch(op) | |
{ | |
case OP_NOP: op_nop: NEXT() | |
case OP_JMP: op_jmp: ip = prog + IMMV_1(); goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *ip ) >> 48)] ); //ip = prog + IMMV_1(); break; | |
case OP_JMP_GE: op_jmp_ge: if((R_OR_IMMV_1() - R_OR_IMMV_2()) >= 0) {ip = prog + IMMV_3(); goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *ip ) >> 48)] );} else {NEXT()} //if((R_OR_IMMV_1() - R_OR_IMMV_2()) >= 0) {ip = prog + IMMV_3(); break;} else {NEXT()} | |
case OP_MOV: op_mov: R_1() = R_OR_IMMV_2(); NEXT() | |
case OP_ADD: op_add: R_3() = R_OR_IMMV_1() + R_OR_IMMV_2(); NEXT() | |
case OP_MUL: op_mul: R_3() = R_OR_IMMV_1() * R_OR_IMMV_2(); NEXT() | |
case OP_PRINT: op_print: printf("%d\n", R_OR_IMMV_1()); fflush(stdout); NEXT() | |
case OP_RET: op_ret: return; | |
} | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
// | |
inst *ip; | |
inst *program = ip = memset(malloc(sizeof(inst) * 1024), 0, sizeof(inst) * 1024); | |
// | |
char op[32]; | |
char arg1_s[32], arg2_s[32], arg3_s[32]; | |
inst arg1_i, arg2_i, arg3_i; | |
// Using it in SET_OP() macro. I'm too lazy to type it 100 times. | |
inst temp_op; | |
// | |
while(scanf("%s", op) != EOF) | |
{ | |
// | |
memset(arg1_s, 0, 32), memset(arg2_s, 0, 32), memset(arg3_s, 0, 32); | |
arg1_i = 0, arg2_i = 0, arg3_i = 0; | |
// Macro for parsing and composing opcodes. Don't read this block. | |
{ | |
// :) | |
#define elif else if | |
// | |
#define OP_SWITCH(_CODE) \ | |
if(0){ \ | |
_CODE \ | |
} | |
// | |
#define SET_OP() \ | |
{ \ | |
*ip = temp_op << 48; \ | |
} | |
//#define SET_OP() \ | |
// { \ | |
// *ip = temp_op << 48; \ | |
// printf("op: %d; ", temp_op); \ | |
// } | |
// | |
#define CASE(_OP) \ | |
} \ | |
elif(!strcmp(op, #_OP) && (temp_op = _OP)) \ | |
{ \ | |
SET_OP(); | |
// | |
#define SET_ARG(_VAL, _R_OR_IMMV, _OFFSET, _R_OR_IMMV_OPT) \ | |
{ \ | |
*ip |= (inst)((inst)_VAL << _OFFSET); \ | |
if(_R_OR_IMMV) \ | |
*ip |= _R_OR_IMMV_OPT; \ | |
} | |
//#define SET_ARG(_VAL, _R_OR_IMMV, _OFFSET, _R_OR_IMMV_OPT) \ | |
// { \ | |
// *ip |= (inst)((inst)_VAL << _OFFSET); \ | |
// if(_R_OR_IMMV) \ | |
// *ip |= _R_OR_IMMV_OPT; \ | |
// printf("arg %d: %d; ", _OFFSET, _VAL); \ | |
// } | |
#define SET_ARG_1(_VAL, _R_OR_IMMV) SET_ARG(_VAL, _R_OR_IMMV, 32, 0x8000000000000000) | |
#define SET_ARG_2(_VAL, _R_OR_IMMV) SET_ARG(_VAL, _R_OR_IMMV, 16, 0x4000000000000000) | |
#define SET_ARG_3(_VAL, _R_OR_IMMV) SET_ARG(_VAL, _R_OR_IMMV, 0, 0x2000000000000000) | |
// | |
#define CALL(_MACRO, _ARGS) _MACRO _ARGS | |
#define READ_AND_SET_R_OR_IMMV(_ARG_NUM) \ | |
{ \ | |
scanf("%s", &arg##_ARG_NUM##_s); \ | |
if(arg##_ARG_NUM##_s[0] == '$' && arg##_ARG_NUM##_s[1] == 'r') \ | |
{ \ | |
sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \ | |
CALL(SET_ARG_##_ARG_NUM, (arg##_ARG_NUM##_i, 1)) \ | |
} \ | |
else \ | |
{ \ | |
sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \ | |
CALL(SET_ARG_##_ARG_NUM, (arg##_ARG_NUM##_i, 0)) \ | |
} \ | |
} | |
#define READ_AND_SET_R(_ARG_NUM) \ | |
{ \ | |
scanf("%s", &arg##_ARG_NUM##_s); \ | |
sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \ | |
CALL(SET_ARG_##_ARG_NUM, (arg##_ARG_NUM##_i, 1)) \ | |
} | |
#define READ_AND_SET_IMMV(_ARG_NUM) \ | |
{ \ | |
scanf("%d", &arg##_ARG_NUM##_i); \ | |
CALL(SET_ARG_##_ARG_NUM, (arg##_ARG_NUM##_i, 0)) \ | |
} | |
} | |
// | |
OP_SWITCH | |
( | |
CASE(OP_NOP) | |
CASE(OP_JMP) | |
READ_AND_SET_IMMV(1); | |
CASE(OP_JMP_GE) | |
READ_AND_SET_R_OR_IMMV(1); | |
READ_AND_SET_R_OR_IMMV(2); | |
READ_AND_SET_IMMV(3); | |
CASE(OP_MOV) | |
READ_AND_SET_R(1); | |
READ_AND_SET_R_OR_IMMV(2); | |
CASE(OP_ADD) | |
READ_AND_SET_R_OR_IMMV(1); | |
READ_AND_SET_R_OR_IMMV(2); | |
READ_AND_SET_R(3); | |
CASE(OP_MUL) | |
READ_AND_SET_R_OR_IMMV(1); | |
READ_AND_SET_R_OR_IMMV(2); | |
READ_AND_SET_R(3); | |
CASE(OP_PRINT) | |
READ_AND_SET_R_OR_IMMV(1); | |
CASE(OP_RET) | |
) | |
//printf("\n%d %s %s %s %s\n\n", (int16_t)(((*ip) & 0x00FF000000000000) >> 48), op, arg1_s, arg2_s, arg3_s); fflush(stdout); | |
++ip; | |
} | |
vm(program); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment