.
This commit is contained in:
@@ -85,7 +85,8 @@ target_compile_options(lib${PROJECT_NAME} PRIVATE ${warnings})
|
|||||||
# tests
|
# tests
|
||||||
#
|
#
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}-bytecode-test src/bytecode/tests.cc)
|
add_executable(${PROJECT_NAME}-bytecode-test src/bytecode/tests.cc
|
||||||
|
src/vm/location.hh)
|
||||||
target_link_libraries(${PROJECT_NAME}-bytecode-test lib${PROJECT_NAME} gtest_main)
|
target_link_libraries(${PROJECT_NAME}-bytecode-test lib${PROJECT_NAME} gtest_main)
|
||||||
add_test(NAME tyche_bytecode_test COMMAND ${PROJECT_NAME}-bytecode-test)
|
add_test(NAME tyche_bytecode_test COMMAND ${PROJECT_NAME}-bytecode-test)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,41 @@ FunctionId Code::import_bytecode(ByteArray incoming)
|
|||||||
return 0; // TODO
|
return 0; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operation Code::operation(Location const& location) const
|
||||||
|
{
|
||||||
|
Instruction inst = (Instruction) bytecode_.get_code_byte(location.function_id, location.pc);
|
||||||
|
OperandType opet = instruction_operand_type(inst);
|
||||||
|
|
||||||
|
switch (opet) {
|
||||||
|
case OperandType::NoOperand:
|
||||||
|
return {
|
||||||
|
.instruction = inst,
|
||||||
|
.operator_ = 0,
|
||||||
|
.next_location = { .function_id = location.function_id, .pc = location.pc + 1 },
|
||||||
|
};
|
||||||
|
case OperandType::Int8:
|
||||||
|
return {
|
||||||
|
.instruction = inst,
|
||||||
|
.operator_ = bytecode_.get_code_int8(location.function_id, location.pc + 1),
|
||||||
|
.next_location = { .function_id = location.function_id, .pc = location.pc + 2 },
|
||||||
|
};
|
||||||
|
case OperandType::Int16:
|
||||||
|
return {
|
||||||
|
.instruction = inst,
|
||||||
|
.operator_ = bytecode_.get_code_int16(location.function_id, location.pc + 1),
|
||||||
|
.next_location = { .function_id = location.function_id, .pc = location.pc + 3 },
|
||||||
|
};
|
||||||
|
case OperandType::Int32:
|
||||||
|
return {
|
||||||
|
.instruction = inst,
|
||||||
|
.operator_ = bytecode_.get_code_int32(location.function_id, location.pc + 1),
|
||||||
|
.next_location = { .function_id = location.function_id, .pc = location.pc + 5 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::logic_error("Should not get here");
|
||||||
|
}
|
||||||
|
|
||||||
std::string Code::disassemble() const
|
std::string Code::disassemble() const
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
|
|||||||
@@ -1,17 +1,28 @@
|
|||||||
#ifndef TYCHE_CODE_HH
|
#ifndef TYCHE_CODE_HH
|
||||||
#define TYCHE_CODE_HH
|
#define TYCHE_CODE_HH
|
||||||
|
|
||||||
|
#include "instruction.hh"
|
||||||
|
#include "location.hh"
|
||||||
#include "value.hh"
|
#include "value.hh"
|
||||||
#include "../bytecode/bytecode.hh"
|
#include "../bytecode/bytecode.hh"
|
||||||
|
|
||||||
namespace tyche {
|
namespace tyche {
|
||||||
|
|
||||||
|
struct Operation
|
||||||
|
{
|
||||||
|
Instruction instruction;
|
||||||
|
int32_t operator_;
|
||||||
|
Location next_location;
|
||||||
|
};
|
||||||
|
|
||||||
class Code {
|
class Code {
|
||||||
public:
|
public:
|
||||||
FunctionId import_bytecode(ByteArray incoming);
|
FunctionId import_bytecode(ByteArray incoming);
|
||||||
|
|
||||||
[[nodiscard]] std::string disassemble() const;
|
[[nodiscard]] std::string disassemble() const;
|
||||||
|
|
||||||
|
[[nodiscard]] Operation operation(Location const& location) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Bytecode bytecode_;
|
Bytecode bytecode_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -98,30 +98,48 @@ std::pair<std::string, size_t> debug_instruction(Instruction inst, int oper)
|
|||||||
out = "???";
|
out = "???";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint8_t) inst < 0xa0)
|
OperandType operands = instruction_operand_type(inst);
|
||||||
|
|
||||||
|
if (operands == OperandType::NoOperand)
|
||||||
return { out, 1 };
|
return { out, 1 };
|
||||||
|
|
||||||
out += " " + std::to_string(oper);
|
out += " " + std::to_string(oper);
|
||||||
if ((uint8_t) inst >= 0xe0)
|
if (operands == OperandType::Int32)
|
||||||
return { out, 5 };
|
return { out, 5 };
|
||||||
else if ((uint8_t) inst >= 0xc0)
|
if (operands == OperandType::Int16)
|
||||||
return { out, 3 };
|
return { out, 3 };
|
||||||
else
|
|
||||||
return { out, 2 };
|
return { out, 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, size_t> debug_instruction(Bytecode const& bt, uint32_t function_id, uint32_t addr)
|
std::pair<std::string, size_t> debug_instruction(Bytecode const& bt, uint32_t function_id, uint32_t addr)
|
||||||
{
|
{
|
||||||
auto inst = (Instruction) bt.get_code_byte(function_id, addr);
|
auto inst = (Instruction) bt.get_code_byte(function_id, addr);
|
||||||
|
|
||||||
|
switch (instruction_operand_type(inst)) {
|
||||||
|
case OperandType::NoOperand:
|
||||||
|
return debug_instruction(inst);
|
||||||
|
case OperandType::Int8:
|
||||||
|
return debug_instruction(inst, bt.get_code_int8(function_id, addr + 1));
|
||||||
|
case OperandType::Int16:
|
||||||
|
return debug_instruction(inst, bt.get_code_int16(function_id, addr + 1));
|
||||||
|
case OperandType::Int32:
|
||||||
|
return debug_instruction(inst, bt.get_code_int32(function_id, addr + 1));
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return { "???", 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
OperandType instruction_operand_type(Instruction inst)
|
||||||
|
{
|
||||||
if ((uint8_t) inst >= 0xe0)
|
if ((uint8_t) inst >= 0xe0)
|
||||||
return debug_instruction(inst, bt.get_code_int32(function_id, addr + 1));
|
return OperandType::Int32;
|
||||||
else if ((uint8_t) inst >= 0xc0)
|
if ((uint8_t) inst >= 0xc0)
|
||||||
return debug_instruction(inst, bt.get_code_int16(function_id, addr + 1));
|
return OperandType::Int16;
|
||||||
else if ((uint8_t) inst >= 0xa0)
|
if ((uint8_t) inst >= 0xa0)
|
||||||
return debug_instruction(inst, bt.get_code_int8(function_id, addr + 1));
|
return OperandType::Int8;
|
||||||
|
return OperandType::NoOperand;
|
||||||
return debug_instruction(inst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -98,6 +98,9 @@ enum class Instruction : uint8_t {
|
|||||||
std::pair<std::string, size_t> debug_instruction(Instruction inst, int oper=0);
|
std::pair<std::string, size_t> debug_instruction(Instruction inst, int oper=0);
|
||||||
std::pair<std::string, size_t> debug_instruction(Bytecode const& bt, uint32_t function_id, uint32_t addr);
|
std::pair<std::string, size_t> debug_instruction(Bytecode const& bt, uint32_t function_id, uint32_t addr);
|
||||||
|
|
||||||
|
enum class OperandType { NoOperand, Int8, Int16, Int32 };
|
||||||
|
OperandType instruction_operand_type(Instruction instruction);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //TYCHE_INSTRUCTION_HH
|
#endif //TYCHE_INSTRUCTION_HH
|
||||||
|
|||||||
16
src/vm/location.hh
Normal file
16
src/vm/location.hh
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef TYCHE_LOCATION_HH
|
||||||
|
#define TYCHE_LOCATION_HH
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace tyche {
|
||||||
|
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
uint32_t function_id;
|
||||||
|
uint32_t pc;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //TYCHE_LOCATION_HH
|
||||||
@@ -21,6 +21,8 @@ public:
|
|||||||
void push_fp();
|
void push_fp();
|
||||||
void pop_fp();
|
void pop_fp();
|
||||||
|
|
||||||
|
[[nodiscard]] size_t fp_level() const { return fps_.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Value> stack_;
|
std::vector<Value> stack_;
|
||||||
std::stack<size_t> fps_;
|
std::stack<size_t> fps_;
|
||||||
|
|||||||
12
src/vm/vm.cc
12
src/vm/vm.cc
@@ -27,7 +27,19 @@ void VM::call(size_t n_params)
|
|||||||
|
|
||||||
void VM::run_until_return()
|
void VM::run_until_return()
|
||||||
{
|
{
|
||||||
|
size_t level = stack_.fp_level();
|
||||||
|
|
||||||
|
while (stack_.fp_level() >= level)
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::step()
|
||||||
|
{
|
||||||
|
Operation op = code_.operation(loc_.top());
|
||||||
|
switch (op.instruction) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
loc_.top() = op.next_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // tyche
|
} // tyche
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define TYCHE_VM_HH
|
#define TYCHE_VM_HH
|
||||||
|
|
||||||
#include "code.hh"
|
#include "code.hh"
|
||||||
|
#include "location.hh"
|
||||||
#include "stack.hh"
|
#include "stack.hh"
|
||||||
|
|
||||||
namespace tyche {
|
namespace tyche {
|
||||||
@@ -13,9 +14,8 @@ public:
|
|||||||
void call(size_t n_params);
|
void call(size_t n_params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Location { uint32_t function_id; uint32_t pc; };
|
|
||||||
|
|
||||||
void run_until_return();
|
void run_until_return();
|
||||||
|
void step();
|
||||||
|
|
||||||
Stack stack_;
|
Stack stack_;
|
||||||
Code code_;
|
Code code_;
|
||||||
|
|||||||
Reference in New Issue
Block a user