179 lines
4.0 KiB
C++
179 lines
4.0 KiB
C++
#include "furvm/instruction.hpp"
|
|
|
|
#include "furlang/view.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
namespace furvm {
|
|
|
|
const std::size_t instruction_argument::s_sizes[instruction_argument::Count] = {
|
|
// None:
|
|
0,
|
|
// S8:
|
|
1,
|
|
// U8:
|
|
1,
|
|
// S16:
|
|
2,
|
|
// U16:
|
|
2,
|
|
// S32
|
|
1,
|
|
// U32
|
|
1,
|
|
// Constant:
|
|
4,
|
|
// Type:
|
|
4,
|
|
// Variable:
|
|
2,
|
|
// Function:
|
|
4,
|
|
// Offset:
|
|
1,
|
|
};
|
|
|
|
const bool instruction_argument::s_signedness[instruction_argument::Count] = {
|
|
// None:
|
|
false,
|
|
// S8:
|
|
true,
|
|
// U8:
|
|
false,
|
|
// S16:
|
|
true,
|
|
// U16:
|
|
false,
|
|
// S32
|
|
true,
|
|
// U32:
|
|
false,
|
|
// Constant:
|
|
false,
|
|
// Type:
|
|
false,
|
|
// Variable:
|
|
false,
|
|
// Function:
|
|
false,
|
|
// Offset:
|
|
true,
|
|
};
|
|
|
|
const instruction_argument_t instruction::s_arguments[instruction::Count] = {
|
|
// NoOperation:
|
|
instruction_argument::None,
|
|
// PushS8:
|
|
instruction_argument::S8,
|
|
// PushU8:
|
|
instruction_argument::U8,
|
|
// PushS16:
|
|
instruction_argument::S16,
|
|
// PushU16:
|
|
instruction_argument::U16,
|
|
// PushS32:
|
|
instruction_argument::S32,
|
|
// PushU32:
|
|
instruction_argument::U32,
|
|
// PushConstant:
|
|
instruction_argument::Constant,
|
|
// Array:
|
|
instruction_argument::Type,
|
|
// Get:
|
|
instruction_argument::None,
|
|
// Set:
|
|
instruction_argument::None,
|
|
// Drop:
|
|
instruction_argument::None,
|
|
// Duplicate:
|
|
instruction_argument::None,
|
|
// Swap:
|
|
instruction_argument::None,
|
|
// Clone:
|
|
instruction_argument::None,
|
|
// Reference:
|
|
instruction_argument::None,
|
|
// Add:
|
|
instruction_argument::None,
|
|
// Sub:
|
|
instruction_argument::None,
|
|
// Mul:
|
|
instruction_argument::None,
|
|
// Div:
|
|
instruction_argument::None,
|
|
// Mod:
|
|
instruction_argument::None,
|
|
// Equals:
|
|
instruction_argument::None,
|
|
// NotEquals:
|
|
instruction_argument::None,
|
|
// LessThan:
|
|
instruction_argument::None,
|
|
// GreaterThan:
|
|
instruction_argument::None,
|
|
// LessEqual:
|
|
instruction_argument::None,
|
|
// GreaterEqual:
|
|
instruction_argument::None,
|
|
// Pointerof:
|
|
instruction_argument::None,
|
|
// Sizeof:
|
|
instruction_argument::None,
|
|
// Lengthof:
|
|
instruction_argument::None,
|
|
// Load:
|
|
instruction_argument::Variable,
|
|
// Store:
|
|
instruction_argument::Variable,
|
|
// Call:
|
|
instruction_argument::Function,
|
|
// Jump:
|
|
instruction_argument::Offset,
|
|
// JumpNotZero:
|
|
instruction_argument::Offset,
|
|
// Return:
|
|
instruction_argument::None,
|
|
};
|
|
|
|
std::size_t instruction::read(furlang::view<std::uint8_t> in) {
|
|
type = static_cast<type_e>(in[0]);
|
|
if (type >= Count) throw std::runtime_error("invalid instruction");
|
|
arg.type = s_arguments[type];
|
|
|
|
furlang::view argView = in.subview(1, arg.size());
|
|
if (argView.size() != arg.size()) throw std::runtime_error("invalid bytecode");
|
|
switch (argView.size()) {
|
|
case 0: break;
|
|
case 1: arg.u8 = argView[0]; break;
|
|
case 2: arg.u16 = argView[0] | (argView[1] << 8); break;
|
|
case 4: arg.u32 = argView[0] | (argView[1] << 8) | (argView[2] << 16) | (argView[3] << 24); break;
|
|
default: throw std::runtime_error("unreachable");
|
|
}
|
|
|
|
return 1 + argView.size();
|
|
}
|
|
|
|
std::size_t instruction::write(std::vector<std::uint8_t>& out) const {
|
|
if (type >= Count) throw std::runtime_error("invalid instruction");
|
|
if (s_arguments[type] != arg.type) throw std::runtime_error("malformed instruction");
|
|
out.push_back(static_cast<char>(type));
|
|
switch (arg.size()) {
|
|
case 0: break;
|
|
case 1: out.push_back(arg.u8); break;
|
|
case 2:
|
|
out.push_back(arg.u16 & 0xFF);
|
|
out.push_back((arg.u16 >> 8) & 0xFF);
|
|
break;
|
|
case 4:
|
|
out.push_back(arg.u32 & 0xFF);
|
|
out.push_back((arg.u32 >> 8) & 0xFF);
|
|
out.push_back((arg.u32 >> 16) & 0xFF);
|
|
out.push_back((arg.u32 >> 24) & 0xFF);
|
|
break;
|
|
default: throw std::runtime_error("unreachable");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
} // namespace furvm
|