text: #include "zvm/VM.h"
  #include "zvm/Util.h"
  #include "zvm/Op.h"
  
  namespace zvm
  {
  	inline static Op
  	pop_op(VM& self, const mn::Buf<uint8_t>& code)
  	{
  		return Op(pop8(code, self.r[Reg_IP].u64));
  	}
  
  	inline static Reg
  	pop_reg(VM& self, const mn::Buf<uint8_t>& code)
  	{
  		return Reg(pop8(code, self.r[Reg_IP].u64));
  	}
  
  	inline static Reg_Val&
  	load_reg(VM& self, const mn::Buf<uint8_t>& code)
  	{
  		Reg i = pop_reg(self, code);
  		assert(i < Reg_COUNT);
  		return self.r[i];
  	}
  
  	// API
  	VM
  	vm_new()
  	{
  		VM self{};
  		return self;
  	}
  
  	CPU_State
  	vm_cpu(VM& self, const mn::Buf<uint8_t>& code)
  	{
  		auto op = pop_op(self, code);
  		switch(op)
  		{
  		case Op_ADD32:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u32 += src.u32;
  			return CPU_STATE_OK;
  		}
  		case Op_ADD64:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u64 += src.u64;
  			return CPU_STATE_OK;
  		}
  
  		case Op_SUB32:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u32 -= src.u32;
  			return CPU_STATE_OK;
  		}
  		case Op_SUB64:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u64 -= src.u64;
  			return CPU_STATE_OK;
  		}
  
  		case Op_MUL32:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u32 *= src.u32;
  			return CPU_STATE_OK;
  		}
  		case Op_MUL64:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u64 *= src.u64;
  			return CPU_STATE_OK;
  		}
  
  		case Op_IMUL32:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.i32 *= src.i32;
  			return CPU_STATE_OK;
  		}
  		case Op_IMUL64:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.i64 *= src.i64;
  			return CPU_STATE_OK;
  		}
  
  		case Op_DIV32:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u32 /= src.u32;
  			return CPU_STATE_OK;
  		}
  		case Op_DIV64:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.u64 /= src.u64;
  			return CPU_STATE_OK;
  		}
  
  		case Op_IDIV32:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.i32 /= src.i32;
  			return CPU_STATE_OK;
  		}
  		case Op_IDIV64:
  		{
  			auto dst = load_reg(self, code);
  			auto src = load_reg(self, code);
  			dst.i64 /= src.i64;
  			return CPU_STATE_OK;
  		}
  
  		case Op_HALT:
  			return CPU_STATE_HALT;
  
  		case Op_IGL:
  		default:
  			return CPU_STATE_OP_ERR;
  		}
  	}
  }