Skip to content

Instantly share code, notes, and snippets.

@lostdj
Created October 16, 2012 05:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lostdj/3897335 to your computer and use it in GitHub Desktop.
Save lostdj/3897335 to your computer and use it in GitHub Desktop.
#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