Last active
May 5, 2018 20:36
-
-
Save maxattack/c73d49eee35540006284c5534cb72475 to your computer and use it in GitHub Desktop.
Unstructured Embeddable Scripting VM for a toy game engine, 15 minutes in...
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 <cstdio> | |
#include <cstdint> | |
#include <cstdlib> | |
#include "glm/glm.hpp" | |
#include "glm/gtx/type_aligned.hpp" | |
namespace Trinket { | |
enum class OP : uint8_t { | |
NOOP, | |
PUSH32_FROM_ADDR, | |
POP32_TO_ADDR, | |
ADD_F32, | |
EXIT, | |
}; | |
typedef int32_t Address; | |
union Slot32 { | |
int32_t ival; | |
float fval; | |
Address aval; | |
}; | |
typedef glm::aligned_vec4 Slot128; | |
class VirtualMachine { | |
private: | |
Slot32 ram[1024 * 1024]; | |
Slot32 stack[128]; | |
Slot128 vstack[128]; | |
public: | |
inline Slot32* GetPtr32(Address addr) { | |
// todo: bounds check | |
return &ram[addr]; | |
} | |
void Execute(uint8_t* instructions, int nbytes) { | |
auto ps = stack; | |
auto pv = vstack; | |
auto pc = instructions; | |
auto pend = instructions + nbytes; | |
while (pc < pend) { | |
auto op = (OP) *pc; | |
++pc; | |
switch(op) { | |
default: | |
case OP::NOOP: | |
break; | |
case OP::PUSH32_FROM_ADDR: | |
// todo: stack bounds check | |
// todo: instruction bounds check | |
// todo: ram bounds check | |
*ps = ram[*(Address*)pc]; | |
++ps; | |
pc += sizeof(Address); | |
break; | |
case OP::POP32_TO_ADDR: | |
// todo: stack bounds check | |
// todo: instruction bounds check | |
// todo: ram bounds check | |
ram[*(Address*)pc] = *(ps-1); | |
--ps; | |
pc += sizeof(Address); | |
break; | |
case OP::ADD_F32: | |
// todo: stack bounds check | |
(ps-2)->fval += (ps-1)->fval; | |
--ps; | |
break; | |
case OP::EXIT: | |
pc = pend; | |
break; | |
} | |
} | |
} | |
}; | |
} | |
int main(int argc, char * argv[]) { | |
puts("Hello, World"); | |
using namespace Trinket; | |
static VirtualMachine vm; | |
vm.GetPtr32(1)->fval = 20.0f; | |
vm.GetPtr32(2)->fval = 22.0f; | |
static uint8_t instructions[] = { | |
(uint8_t) OP::PUSH32_FROM_ADDR, 1, 0, 0, 0, | |
(uint8_t) OP::PUSH32_FROM_ADDR, 2, 0, 0, 0, | |
(uint8_t) OP::ADD_F32, | |
(uint8_t) OP::POP32_TO_ADDR, 3, 0, 0, 0, | |
(uint8_t) OP::EXIT, | |
}; | |
vm.Execute(instructions, sizeof(instructions)); | |
printf("Result = %f\n", vm.GetPtr32(3)->fval); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment