From fc647ed2ecf67355a13f09ff7e2c68b943691cf4 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Sun, 11 Nov 2018 21:49:25 +0200 Subject: Removed data stack class --- spasm/src/spasm.cpp | 100 +++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 49 deletions(-) (limited to 'spasm/src/spasm.cpp') diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index e67c975..857143f 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -1,10 +1,13 @@ #include #include +#include #include "spasm.hpp" namespace SpasmImpl { + + PC_t Spasm::op_size = 21; // Be sure the same number is on the previous and next lines Operation Spasm::operations[] = {NULL, @@ -104,16 +107,6 @@ void Spasm::deleteobj() delete[] bytecode; } -/*! -** Returns the dstack, so that it can be examined after execution -** -** \return const reference to the data stack -*/ -const Dstack& Spasm::get_dstack() const -{ - return data_stack; -} - /*! ** Starts the machine. The machine stops if it reaches an invalid opcode ** or opcode 0 or the pc reaches beyond the end of the bytecode. @@ -139,7 +132,7 @@ void Spasm::run() void Spasm::push() { ++pc; - data_stack.push(*reinterpret_cast(bytecode + pc)); + push_data(*reinterpret_cast(bytecode + pc)); pc += sizeof(data_t) - 1; } @@ -148,7 +141,7 @@ void Spasm::push() */ void Spasm::pop() { - data_stack.pop(); + data_stack.pop_back(); } /*! @@ -156,7 +149,7 @@ void Spasm::pop() */ void Spasm::dup() { - data_stack.push(data_stack.top()); + push_data(data_stack.back()); } /*! @@ -167,7 +160,7 @@ void Spasm::read() { data_t x; *istr >> x; - data_stack.push(x); + push_data(x); } /*! @@ -176,7 +169,8 @@ void Spasm::read() */ void Spasm::print() { - *ostr << data_stack.pop(); + *ostr << data_stack.back(); + pop(); } /*! @@ -185,9 +179,9 @@ void Spasm::print() */ void Spasm::plus() { - data_t x, y = data_stack.pop(); - x = data_stack.pop(); - data_stack.push(x + y); + data_t x, y = pop_data(); + x = pop_data(); + push_data(x + y); } /*! @@ -196,9 +190,9 @@ void Spasm::plus() */ void Spasm::minus() { - data_t x, y = data_stack.pop(); - x = data_stack.pop(); - data_stack.push(x - y); + data_t x, y = pop_data(); + x = pop_data(); + push_data(x - y); } /*! @@ -207,9 +201,9 @@ void Spasm::minus() */ void Spasm::multiply() { - data_t x, y = data_stack.pop(); - x = data_stack.pop(); - data_stack.push(x * y); + data_t y = pop_data(), + x = pop_data(); + push_data(x * y); } /*! @@ -218,9 +212,9 @@ void Spasm::multiply() */ void Spasm::divide() { - data_t x, y = data_stack.pop(); - x = data_stack.pop(); - data_stack.push(x / y); + data_t y = pop_data(), + x = pop_data(); + push_data(x / y); } /*! @@ -229,9 +223,9 @@ void Spasm::divide() */ void Spasm::modulus() { - data_t x, y = data_stack.pop(); - x = data_stack.pop(); - data_stack.push(x % y); + data_t y = pop_data(), + x = pop_data(); + push_data(x % y); } /*! @@ -242,7 +236,7 @@ void Spasm::modulus() void Spasm::gotrue() { ++pc; - if (data_stack.pop()) + if (pop_data()) pc = *(reinterpret_cast(bytecode + pc)) - 1; else pc += sizeof(size_t) - 1; @@ -256,7 +250,7 @@ void Spasm::gotrue() void Spasm::gofalse() { ++pc; - if (!data_stack.pop()) + if (!pop_data()) pc = *(reinterpret_cast(bytecode + pc)) - 1; else pc += sizeof(size_t) - 1; @@ -278,12 +272,15 @@ void Spasm::go() */ void Spasm::call() { + assert(false && "not-implemented"); +#if 0 size_t fs; // new frame size return_stack.push(pc); // using the ++pc in run() - data_stack.pop(&fs, sizeof(fs)); - data_stack.pop(&pc, sizeof(pc)); + pop_data(&fs, sizeof(fs)); + pop_data(&pc, sizeof(pc)); frame.new_frame(fs); --pc; // the ++pc in run() +#endif } /*! @@ -303,10 +300,7 @@ void Spasm::ret() */ void Spasm::load() { - size_t offset; - - data_stack.pop(&offset, sizeof(offset)); - data_stack.push(frame[offset]); + assert(false && "not-implemented"); } /*! @@ -314,11 +308,7 @@ void Spasm::load() */ void Spasm::store() { - data_t value = data_stack.pop(); - size_t offset; - - data_stack.pop(&offset, sizeof(offset)); - frame[offset] = value; + assert(false && "not-implemented"); } /*! @@ -327,10 +317,10 @@ void Spasm::store() */ void Spasm::less() { - data_t y = data_stack.pop(); - data_t x = data_stack.pop(); + data_t y = pop_data(); + data_t x = pop_data(); - data_stack.push(x < y); + push_data(x < y); } /*! @@ -339,10 +329,22 @@ void Spasm::less() */ void Spasm::lesseq() { - data_t y = data_stack.pop(); - data_t x = data_stack.pop(); + data_t y = pop_data(); + data_t x = pop_data(); + + push_data(x <= y); +} + +data_t Spasm::pop_data() +{ + auto result = data_stack.back(); + data_stack.pop_back(); + return result; +} - data_stack.push(x <= y); +void Spasm::push_data(data_t data) +{ + data_stack.push_back(data); } } // namespace SpasmImpl -- cgit v1.3.1-23-gd82d From f81f1c56cc01ec3d91a73ec7314519ac59abd5b4 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Mon, 12 Nov 2018 23:41:13 +0200 Subject: Converted spasm to a register machine --- spasm/src/spasm.cpp | 342 ++++++++++++++++++++++++++--------------------- spasm/src/spasm_impl.hpp | 91 ++++++++----- spasm/src/types.hpp | 2 + 3 files changed, 251 insertions(+), 184 deletions(-) (limited to 'spasm/src/spasm.cpp') diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index 857143f..60f7531 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -1,40 +1,12 @@ #include -#include #include +#include #include "spasm.hpp" namespace SpasmImpl { - - -PC_t Spasm::op_size = 21; -// Be sure the same number is on the previous and next lines -Operation Spasm::operations[] = {NULL, - &Spasm::push, - &Spasm::pop, - &Spasm::dup, - &Spasm::print, - &Spasm::read, - &Spasm::plus, - &Spasm::minus, - &Spasm::multiply, - &Spasm::divide, - &Spasm::modulus, - &Spasm::gotrue, - &Spasm::gofalse, - &Spasm::go, - &Spasm::call, - &Spasm::ret, - &Spasm::load, - &Spasm::store, - &Spasm::less, - &Spasm::lesseq}; - -Spasm::Spasm() - : pc(0), bc_size(0), bytecode(NULL), istr(&std::cin), ostr(&std::cout) -{ -} +Spasm::Spasm() {} /*! ** Constructs new Spasm object @@ -48,92 +20,155 @@ Spasm::Spasm(PC_t _bc_size, const byte* _bytecode, std::istream& _istr, std::ostream& _ostr) - : pc(0), bc_size(_bc_size), istr(&_istr), ostr(&_ostr) -{ - bytecode = new byte[bc_size]; - std::copy(_bytecode, _bytecode + bc_size, bytecode); -} - -Spasm::Spasm(const Spasm& m) - : pc(m.pc), - bc_size(m.bc_size), - data_stack(m.data_stack), - return_stack(m.return_stack), - frame(m.frame), - istr(m.istr), - ostr(m.ostr) + : m_PC(0), + m_ByteCode(_bytecode, _bytecode + _bc_size), + istr(&_istr), + ostr(&_ostr) { - copybc(m); + data_stack.resize(1024); + m_SP = &data_stack[0]; + m_FP = &data_stack[0]; } -Spasm::~Spasm() -{ - deleteobj(); -} - -Spasm& Spasm::operator=(const Spasm& m) -{ - if (this != &m) - { - deleteobj(); - data_stack = m.data_stack; - return_stack = m.return_stack; - frame = m.frame; - istr = m.istr; - ostr = m.ostr; - copybc(m); - } - return *this; -} +Spasm::~Spasm() {} /*! -** Copies the bytecode of another machine m -** -** \param m - the machine from the bytecode is copied -*/ - -void Spasm::copybc(const Spasm& m) -{ - bytecode = new byte[bc_size]; - std::copy(m.bytecode, m.bytecode + bc_size, bytecode); -} - -/*! -** Deletes the machine -*/ -void Spasm::deleteobj() -{ - if (bytecode) - delete[] bytecode; -} - -/*! -** Starts the machine. The machine stops if it reaches an invalid opcode +** Runs the machine. The machine stops if it reaches an invalid opcode ** or opcode 0 or the pc reaches beyond the end of the bytecode. +** @return error code for success or failure */ -void Spasm::run() +Spasm::RunResult Spasm::run() { - while (pc < bc_size) + const auto size = m_ByteCode.size(); + while (m_PC < size) { - if (bytecode[pc] > 0 && bytecode[pc] < op_size) - (this->*operations[bytecode[pc]])(); - else + const auto instruction = m_ByteCode[m_PC++]; + const auto opcode = OpCodes(instruction & 0x3f); + const auto size = instruction >> 6; + assert(size == 0 && "no long args yet"); + (void)size; + switch (opcode) { - std::cerr << "opcode got to " << int(bytecode[pc]) << std::endl; - break; + case OpCodes::Halt: + return RunResult::Success; + case OpCodes::Dup: + dup(); + break; + case OpCodes::Pop: + pop(); + break; + case OpCodes::PopTo: + break; + case OpCodes::Push: + { + const auto arg0 = read_reg(size); + push(arg0); + break; + } + case OpCodes::Print: + { + const auto arg0 = read_reg(size); + print(arg0); + break; + } + case OpCodes::Read: + { + const auto arg0 = read_reg(size); + read(arg0); + break; + } + case OpCodes::Jump: + { + const auto arg0 = read_reg(size); + go(arg0); + break; + } + case OpCodes::JumpT: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + gotrue(arg0, arg1); + break; + } + case OpCodes::JumpF: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + gofalse(arg0, arg1); + break; + } + case OpCodes::Add: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + plus(arg0, arg1, arg2); + break; + } + case OpCodes::Sub: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + minus(arg0, arg1, arg2); + break; + } + case OpCodes::Mul: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + multiply(arg0, arg1, arg2); + break; + } + case OpCodes::Div: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + divide(arg0, arg1, arg2); + break; + } + case OpCodes::Mod: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + modulus(arg0, arg1, arg2); + break; + } + case OpCodes::Less: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + less(arg0, arg1, arg2); + break; + } + case OpCodes::LessEq: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + lesseq(arg0, arg1, arg2); + break; + } + default: + { + std::cerr << opcode << ": not implemented" << std::endl; + return RunResult::NotImplemented; + } } - ++pc; } + return RunResult::Success; } /*! ** Pushes the next data_t object on the data stack */ -void Spasm::push() +void Spasm::push(reg_t reg) { - ++pc; - push_data(*reinterpret_cast(bytecode + pc)); - pc += sizeof(data_t) - 1; + push_data(get_local(reg)); } /*! @@ -141,7 +176,7 @@ void Spasm::push() */ void Spasm::pop() { - data_stack.pop_back(); + --m_SP; } /*! @@ -149,83 +184,72 @@ void Spasm::pop() */ void Spasm::dup() { - push_data(data_stack.back()); + push_data(*(m_SP - 1)); } /*! ** Reads a data_t object from the input stream and pushes it on the data ** stack. */ -void Spasm::read() +void Spasm::read(reg_t reg) { data_t x; *istr >> x; - push_data(x); + set_local(reg, x); } /*! ** Pops a data_t object from the data stack and prints it on the output ** stream. */ -void Spasm::print() +void Spasm::print(reg_t reg) { - *ostr << data_stack.back(); - pop(); + *ostr << get_local(reg); } /*! ** Pops two data objects from the data stack and pushes their sum on the ** data stack. */ -void Spasm::plus() +void Spasm::plus(reg_t a0, reg_t a1, reg_t a2) { - data_t x, y = pop_data(); - x = pop_data(); - push_data(x + y); + set_local(a0, get_local(a1) + get_local(a2)); } /*! ** Pops two data objects from the data stack and pushes their difference ** on the data stack. */ -void Spasm::minus() +void Spasm::minus(reg_t a0, reg_t a1, reg_t a2) { - data_t x, y = pop_data(); - x = pop_data(); - push_data(x - y); + set_local(a0, get_local(a1) - get_local(a2)); } /*! ** Pops two data objects from the data stack and pushes their product ** on the data stack. */ -void Spasm::multiply() +void Spasm::multiply(reg_t a0, reg_t a1, reg_t a2) { - data_t y = pop_data(), - x = pop_data(); - push_data(x * y); + set_local(a0, get_local(a1) * get_local(a2)); } /*! ** Pops two data objects from the data stack and pushes their division ** on the data stack. */ -void Spasm::divide() +void Spasm::divide(reg_t a0, reg_t a1, reg_t a2) { - data_t y = pop_data(), - x = pop_data(); - push_data(x / y); + set_local(a0, get_local(a1) / get_local(a2)); } /*! ** Pops two data objects from the data stack and pushes their modulus ** on the data stack. */ -void Spasm::modulus() +void Spasm::modulus(reg_t a0, reg_t a1, reg_t a2) { - data_t y = pop_data(), - x = pop_data(); - push_data(x % y); + set_local(a0, get_local(a1) % get_local(a2)); } /*! @@ -233,13 +257,12 @@ void Spasm::modulus() ** If the data_t object on top of the data stack evaluates to true ** execution continues from the place pointed by number in the next bytes */ -void Spasm::gotrue() +void Spasm::gotrue(reg_t a0, reg_t a1) { - ++pc; - if (pop_data()) - pc = *(reinterpret_cast(bytecode + pc)) - 1; - else - pc += sizeof(size_t) - 1; + if (get_local(a0)) + { + m_PC = a1; + } } /*! @@ -247,23 +270,21 @@ void Spasm::gotrue() ** If the data_t object on top of the data stack evaluates to false ** execution continues from the place pointed by number in the next bytes */ -void Spasm::gofalse() +void Spasm::gofalse(reg_t a0, reg_t a1) { - ++pc; - if (!pop_data()) - pc = *(reinterpret_cast(bytecode + pc)) - 1; - else - pc += sizeof(size_t) - 1; + if (!get_local(a0)) + { + m_PC = a1; + } } /*! ** Unconditional execution. ** Execution continues from the opcode pointed by the next bytes */ -void Spasm::go() +void Spasm::go(reg_t a0) { - ++pc; - pc = *(reinterpret_cast(bytecode + pc)) - 1; + m_PC = a0; } /*! @@ -287,11 +308,15 @@ void Spasm::call() ** Function return. The frame of the current function is destroyed and the ** saved return address is loaded in the pc */ -void Spasm::ret() +void Spasm::ret(reg_t reg) { + // TODO: Implement + (void)reg; +#if 0 pc = return_stack.top(); return_stack.pop(); frame.pop_frame(); +#endif } /*! @@ -315,24 +340,32 @@ void Spasm::store() ** Compares the values on top of the stack. Pushes 1 if the value before ** the top of the stack is less than that on top of the stack. */ -void Spasm::less() +void Spasm::less(reg_t a0, reg_t a1, reg_t a2) { - data_t y = pop_data(); - data_t x = pop_data(); - - push_data(x < y); + set_local(a0, get_local(a1) < get_local(a2)); } /*! ** Compares the values on top of the stack. Pushes 1 if the value before ** the top of the stack is less than or equal to that on top of the stack. */ -void Spasm::lesseq() +void Spasm::lesseq(reg_t a0, reg_t a1, reg_t a2) { - data_t y = pop_data(); - data_t x = pop_data(); + set_local(a0, get_local(a1) <= get_local(a2)); +} - push_data(x <= y); +data_t Spasm::get_local(reg_t reg) +{ + assert(&data_stack[0] <= (m_FP + reg)); + assert((m_FP + reg) < &data_stack[data_stack.size() - 1]); + return m_FP[reg]; +} + +void Spasm::set_local(reg_t reg, data_t data) +{ + assert(&data_stack[0] <= (m_FP + reg)); + assert((m_FP + reg) < &data_stack[data_stack.size() - 1]); + m_FP[reg] = data; } data_t Spasm::pop_data() @@ -344,7 +377,14 @@ data_t Spasm::pop_data() void Spasm::push_data(data_t data) { - data_stack.push_back(data); + assert(m_SP < &data_stack[data_stack.size() - 1]); + *(m_SP++) = data; +} + +reg_t Spasm::read_reg(int size) +{ + assert(size == 0); + return m_ByteCode[m_PC++]; } } // namespace SpasmImpl diff --git a/spasm/src/spasm_impl.hpp b/spasm/src/spasm_impl.hpp index 7c4d8f7..487f130 100644 --- a/spasm/src/spasm_impl.hpp +++ b/spasm/src/spasm_impl.hpp @@ -8,6 +8,28 @@ namespace SpasmImpl { +enum OpCodes : char +{ + Halt, + Dup, + Pop, + PopTo, + Push, + Print, + Read, + Call, + Ret, + Jump, + JumpT, + JumpF, + Add, + Sub, + Mul, + Div, + Mod, + Less, + LessEq, +}; //! The Abstract Stack Machine /*! ** The machine contains a data stack for operations and control flow and @@ -22,32 +44,35 @@ class Spasm const byte*, std::istream& = std::cin, std::ostream& = std::cout); - Spasm(const Spasm&); ~Spasm(); - Spasm& operator=(const Spasm&); + Spasm(const Spasm&) = delete; + Spasm& operator=(const Spasm&) = delete; - void run(); + enum RunResult { + Success, + Exception, + NotImplemented, + }; + RunResult run(); private: - //! Operations (opcodes) of the machine - static Operation operations[]; - - //! number of operations - static PC_t op_size; - //! Program counter - points the current opcode - PC_t pc; - - //! size of the program bytecode - PC_t bc_size; + PC_t m_PC = 0; + typedef SPVector ByteCode; //! bytecode of the program - byte* bytecode; + ByteCode m_ByteCode; typedef SPVector DataStack; - //! Data stack for arithmetic operations and control flow + //! stack for storing arguments and local variables DataStack data_stack; + //! Stack pointer - always the top of the stack + data_t* m_SP = nullptr; + + //! Frame pointer - the start of the stack for the current function + data_t* m_FP = nullptr; + //! Return stack for the addresses of the returns Rstack_t return_stack; @@ -60,38 +85,38 @@ class Spasm //! Output stream for print () opertion std::ostream* ostr; - void push(); + void push(reg_t reg); + void pop(reg_t reg); void pop(); void dup(); - void print(); - void read(); + void print(reg_t reg); + void read(reg_t reg); - void plus(); - void minus(); - void multiply(); - void divide(); - void modulus(); + void plus(reg_t a0, reg_t a1, reg_t a2); + void minus(reg_t a0, reg_t a1, reg_t a2); + void multiply(reg_t a0, reg_t a1, reg_t a2); + void divide(reg_t a0, reg_t a1, reg_t a2); + void modulus(reg_t a0, reg_t a1, reg_t a2); - void gotrue(); - void gofalse(); - void go(); + void gotrue(reg_t a0, reg_t a1); + void gofalse(reg_t a0, reg_t a1); + void go(reg_t a0); void call(); - void ret(); + void ret(reg_t a0); void load(); void store(); - void less(); - void lesseq(); - - // private method for copying and deleting an object - void copybc(const Spasm&); - void deleteobj(); + void less(reg_t a0, reg_t a1, reg_t a2); + void lesseq(reg_t a0, reg_t a1, reg_t a2); + data_t get_local(reg_t reg); + void set_local(reg_t reg, data_t data); data_t pop_data(); void push_data(data_t); + reg_t read_reg(int size); }; } // namespace SpasmImpl diff --git a/spasm/src/types.hpp b/spasm/src/types.hpp index 4a8606b..ec5a0cb 100644 --- a/spasm/src/types.hpp +++ b/spasm/src/types.hpp @@ -17,5 +17,7 @@ typedef void (Spasm::*Operation)(); template using SPVector = std::vector; + +typedef long long int reg_t; } // namespace SpasmImpl #endif // ----- #ifndef TYPES_HPP -- cgit v1.3.1-23-gd82d From 7f2b2038c600f5a482ee84b04b922637f757c649 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Tue, 13 Nov 2018 20:20:50 +0200 Subject: Fixed windows build and added const instruction --- spasm/src/main.cpp | 3 ++- spasm/src/spasm.cpp | 32 +++++++++++++++++++++++--------- spasm/src/spasm.hpp | 1 + spasm/src/spasm_impl.hpp | 6 ++++-- 4 files changed, 30 insertions(+), 12 deletions(-) (limited to 'spasm/src/spasm.cpp') diff --git a/spasm/src/main.cpp b/spasm/src/main.cpp index 17bb322..cc2c831 100644 --- a/spasm/src/main.cpp +++ b/spasm/src/main.cpp @@ -23,7 +23,8 @@ int main(int argc, const char* argv[]) std::cout << std::hex << (int)bytecode[i] << ' '; std::cout << std::endl; - Spasm::Spasm vm(len, bytecode.get()); + Spasm::Spasm vm; + vm.Initialize(len, bytecode.get()); vm.run(); diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index 60f7531..79c72a7 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -16,15 +16,16 @@ Spasm::Spasm() {} ** \param _istr - input stream for the machine ** \param _ostr - output stream for the machine */ -Spasm::Spasm(PC_t _bc_size, +void Spasm::Initialize(PC_t _bc_size, const byte* _bytecode, std::istream& _istr, std::ostream& _ostr) - : m_PC(0), - m_ByteCode(_bytecode, _bytecode + _bc_size), - istr(&_istr), - ostr(&_ostr) + { + m_PC = 0; + m_ByteCode.assign(_bytecode, _bytecode + _bc_size); + istr = &_istr; + ostr = &_ostr; data_stack.resize(1024); m_SP = &data_stack[0]; m_FP = &data_stack[0]; @@ -39,14 +40,13 @@ Spasm::~Spasm() {} */ Spasm::RunResult Spasm::run() { - const auto size = m_ByteCode.size(); - while (m_PC < size) + const auto codeSize = m_ByteCode.size(); + while (m_PC < codeSize) { const auto instruction = m_ByteCode[m_PC++]; const auto opcode = OpCodes(instruction & 0x3f); const auto size = instruction >> 6; assert(size == 0 && "no long args yet"); - (void)size; switch (opcode) { case OpCodes::Halt: @@ -97,6 +97,13 @@ Spasm::RunResult Spasm::run() gofalse(arg0, arg1); break; } + case OpCodes::Const: + { + const auto reg = read_reg(size); + const auto value = read_number(size); + set_local(reg, value); + break; + } case OpCodes::Add: { const auto arg0 = read_reg(size); @@ -381,10 +388,17 @@ void Spasm::push_data(data_t data) *(m_SP++) = data; } -reg_t Spasm::read_reg(int size) +reg_t Spasm::read_reg(size_t size) { assert(size == 0); return m_ByteCode[m_PC++]; } +data_t Spasm::read_number(size_t size) +{ + assert(size == 0); + return m_ByteCode[m_PC++]; +} + + } // namespace SpasmImpl diff --git a/spasm/src/spasm.hpp b/spasm/src/spasm.hpp index 7468bd8..85b2e8d 100644 --- a/spasm/src/spasm.hpp +++ b/spasm/src/spasm.hpp @@ -8,6 +8,7 @@ namespace Spasm using SpasmImpl::byte; using SpasmImpl::PC_t; using SpasmImpl::Spasm; +using SpasmImpl::OpCodes; } // namespace Spasm #endif // #ifndef SPASM_HPP diff --git a/spasm/src/spasm_impl.hpp b/spasm/src/spasm_impl.hpp index 487f130..1e1d3ef 100644 --- a/spasm/src/spasm_impl.hpp +++ b/spasm/src/spasm_impl.hpp @@ -22,6 +22,7 @@ enum OpCodes : char Jump, JumpT, JumpF, + Const, Add, Sub, Mul, @@ -40,7 +41,7 @@ class Spasm { public: Spasm(); - Spasm(PC_t, + void Initialize(PC_t, const byte*, std::istream& = std::cin, std::ostream& = std::cout); @@ -116,7 +117,8 @@ class Spasm void set_local(reg_t reg, data_t data); data_t pop_data(); void push_data(data_t); - reg_t read_reg(int size); + reg_t read_reg(size_t size); + data_t read_number(size_t size); }; } // namespace SpasmImpl -- cgit v1.3.1-23-gd82d From e7c2a14f3e424f1ef1109d7634ece820a058e862 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Tue, 13 Nov 2018 23:52:40 +0200 Subject: Implemented call and ret opcodes --- JSImpl/solution/JSImpl.sln | 1 + JSImpl/solution/Makefile | 2 +- JSImpl/test/sprtTests.cpp | 188 ++++++++++++++++++++++++++++++++++-- spasm/solution/sprt.make | 6 -- spasm/solution/sprt.vcxproj | 2 - spasm/solution/sprt.vcxproj.filters | 3 - spasm/src/frames.cpp | 130 ------------------------- spasm/src/frames.hpp | 51 ---------- spasm/src/main.cpp | 2 +- spasm/src/spasm.cpp | 83 +++++++++------- spasm/src/spasm_impl.hpp | 19 ++-- spasm/src/types.hpp | 3 +- 12 files changed, 246 insertions(+), 244 deletions(-) delete mode 100644 spasm/src/frames.cpp delete mode 100644 spasm/src/frames.hpp (limited to 'spasm/src/spasm.cpp') diff --git a/JSImpl/solution/JSImpl.sln b/JSImpl/solution/JSImpl.sln index d4acff7..9915cf9 100644 --- a/JSImpl/solution/JSImpl.sln +++ b/JSImpl/solution/JSImpl.sln @@ -3,6 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "..\test\Test.vcxproj", "{45DC8C7C-3113-8E0D-DAFF-7310C6150A0F}" ProjectSection(ProjectDependencies) = postProject + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F} = {AE0A9E7C-9A41-9F0D-432E-85102F441B0F} {19EA680D-85FE-90BE-4E80-341EBA538DEF} = {19EA680D-85FE-90BE-4E80-341EBA538DEF} {EC34880F-5849-B0C0-21CB-53208D9EACF1} = {EC34880F-5849-B0C0-21CB-53208D9EACF1} {B686840F-229B-ACC0-EB1C-502057F0A8F1} = {B686840F-229B-ACC0-EB1C-502057F0A8F1} diff --git a/JSImpl/solution/Makefile b/JSImpl/solution/Makefile index 37c7a63..b920fc7 100644 --- a/JSImpl/solution/Makefile +++ b/JSImpl/solution/Makefile @@ -20,7 +20,7 @@ JSImpl: JSLib @echo "==== Building JSImpl ($(config)) ====" @${MAKE} --no-print-directory -C . -f JSImpl.make -Test: JSLib gtest gmock gtest_main +Test: sprt JSLib gtest gmock gtest_main @echo "==== Building Test ($(config)) ====" @${MAKE} --no-print-directory -C ../test -f Test.make diff --git a/JSImpl/test/sprtTests.cpp b/JSImpl/test/sprtTests.cpp index 92bd5a6..7621ca3 100644 --- a/JSImpl/test/sprtTests.cpp +++ b/JSImpl/test/sprtTests.cpp @@ -7,20 +7,82 @@ using Spasm::OpCodes; struct SPRTTest : public ::testing::Test { - void Run(Spasm::byte bytecode[], size_t size) - { - VM.Initialize(size, bytecode, Input, Output); - ASSERT_EQ(Spasm::Spasm::RunResult::Success, VM.run()); - } - Spasm::Spasm VM; - std::istringstream Input; - std::ostringstream Output; + typedef std::vector ByteCode; + + void Run(ByteCode& code) + { + Run(code.data(), code.size()); + } + + void Run(Spasm::byte* bytecode, size_t size) + { + VM.Initialize(size, bytecode, Input, Output); + ASSERT_EQ(Spasm::Spasm::RunResult::Success, VM.run()); + } + Spasm::byte Label(Spasm::byte label) const { + return 0x80 + label; + } + Spasm::Spasm VM; + std::istringstream Input; + std::ostringstream Output; }; TEST_F(SPRTTest, Empty) { } +TEST_F(SPRTTest, Add) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Add, 3, 1, 2, + OpCodes::Print, 3, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "13"); +} + +TEST_F(SPRTTest, Sub) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Sub, 3, 1, 2, + OpCodes::Print, 3, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "-1"); +} + +TEST_F(SPRTTest, Div) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Div, 3, 1, 2, + OpCodes::Print, 3, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "0"); +} + +TEST_F(SPRTTest, Mod) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Mod, 3, 1, 2, + OpCodes::Print, 3, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "6"); +} + TEST_F(SPRTTest, Mutliply) { Spasm::byte bytecode[] = { @@ -40,9 +102,119 @@ TEST_F(SPRTTest, Less) OpCodes::Const, 1, 6, OpCodes::Const, 2, 7, OpCodes::Less, 3, 1, 2, + OpCodes::Less, 4, 2, 1, + OpCodes::Less, 5, 2, 2, + OpCodes::Print, 3, + OpCodes::Print, 4, + OpCodes::Print, 5, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "100"); +} + + +TEST_F(SPRTTest, LessEq) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::LessEq, 3, 1, 2, + OpCodes::LessEq, 4, 2, 1, + OpCodes::LessEq, 5, 2, 2, + OpCodes::Print, 3, + OpCodes::Print, 4, + OpCodes::Print, 5, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "101"); +} + +TEST_F(SPRTTest, Jump) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::LessEq, 3, 1, 2, + OpCodes::LessEq, 4, 2, 1, + OpCodes::Jump, 18, + OpCodes::Print, 5, OpCodes::Print, 3, }; Run(bytecode, sizeof(bytecode)); ASSERT_EQ(Output.str(), "1"); } + +TEST_F(SPRTTest, JumpTrue) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, // 3 + OpCodes::Const, 2, 7, // 6 + OpCodes::Less, 3, 1, 2, // 10 + OpCodes::JumpT, 3, 17, // 13 + OpCodes::Print, 2, // 15 + OpCodes::Jump, 19, // 17 + OpCodes::Print, 1, // 19 + OpCodes::Halt, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "6"); +} + +TEST_F(SPRTTest, JumpFalse) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, // 3 + OpCodes::Const, 2, 7, // 6 + OpCodes::Less, 3, 1, 2, // 10 + OpCodes::JumpF, 3, 17, // 13 + OpCodes::Print, 2, // 15 + OpCodes::Jump, 19, // 17 + OpCodes::Print, 1, // 19 + OpCodes::Halt, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "7"); +} + +TEST_F(SPRTTest, Call) +{ + Spasm::byte bytecode[] = { + OpCodes::Alloc, 5, // 2 + OpCodes::Const, 1, 0, // 5 + OpCodes::Const, 2, 6, // 8 + OpCodes::Const, 3, 7, // 11 + OpCodes::Const, 4, 2, // 14 + OpCodes::Push, 3, // 16 + OpCodes::Push, 2, // 18 + OpCodes::Push, 4, // 20 + OpCodes::Call, 25, // 22 + OpCodes::Print, 4, // 24 + OpCodes::Halt, // 25 + OpCodes::Print, 0, // 27 + OpCodes::Print, -1, // 29 + OpCodes::Print, -2, // 31 + OpCodes::Mul, 1, -2, -1,// 33 + OpCodes::Ret, 1, // 35 + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "26742"); +} + +TEST_F(SPRTTest, Read) +{ + Spasm::byte bytecode[] = { + OpCodes::Read, 1, + OpCodes::Print, 1, + }; + + Input.str("42"); + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "42"); +} + diff --git a/spasm/solution/sprt.make b/spasm/solution/sprt.make index d4ffbe8..10f5b52 100644 --- a/spasm/solution/sprt.make +++ b/spasm/solution/sprt.make @@ -61,7 +61,6 @@ ifeq ($(config),debug64) LINKOBJS = $(OBJECTS) LINKCMD = $(AR) -rcs $(TARGET) OBJECTS := \ - $(OBJDIR)/src/frames.o \ $(OBJDIR)/src/spasm.o \ define PREBUILDCMDS @@ -91,7 +90,6 @@ ifeq ($(config),release64) LINKOBJS = $(OBJECTS) LINKCMD = $(AR) -rcs $(TARGET) OBJECTS := \ - $(OBJDIR)/src/frames.o \ $(OBJDIR)/src/spasm.o \ define PREBUILDCMDS @@ -157,10 +155,6 @@ $(GCH_OBJC): $(PCH) $(MAKEFILE) | $(OBJDIR) $(SILENT) $(CXX) $(ALL_OBJCPPFLAGS) -x objective-c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" endif -$(OBJDIR)/src/frames.o: ../src/frames.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" - $(OBJDIR)/src/spasm.o: ../src/spasm.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src @echo $(notdir $<) $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" diff --git a/spasm/solution/sprt.vcxproj b/spasm/solution/sprt.vcxproj index 9ffa6d1..2698c10 100644 --- a/spasm/solution/sprt.vcxproj +++ b/spasm/solution/sprt.vcxproj @@ -112,8 +112,6 @@ - - diff --git a/spasm/solution/sprt.vcxproj.filters b/spasm/solution/sprt.vcxproj.filters index 02c2afd..d9f8e3a 100644 --- a/spasm/solution/sprt.vcxproj.filters +++ b/spasm/solution/sprt.vcxproj.filters @@ -9,8 +9,5 @@ src - - src - diff --git a/spasm/src/frames.cpp b/spasm/src/frames.cpp deleted file mode 100644 index 8b7c891..0000000 --- a/spasm/src/frames.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include - -#include "types.hpp" - -#include "frames.hpp" - -namespace SpasmImpl -{ -FrameStack::FrameStack() : base_ptr(NULL), frame_ptr(NULL), g_size(0), c_size(0) -{ -} - -FrameStack::FrameStack(const FrameStack& fs) - : g_size(fs.g_size), c_size(fs.c_size), fstack(fs.fstack) -{ - copy_fstack(fs); -} - -FrameStack::~FrameStack() -{ - delete_fstack(); -} - -FrameStack& FrameStack::operator=(const FrameStack& fs) -{ - if (this != &fs) - { - delete_fstack(); - copy_fstack(fs); - g_size = fs.g_size; - c_size = fs.c_size; - fstack = fs.fstack; - } - return *this; -} - -/*! -** Deletes the frame stack -*/ -void FrameStack::delete_fstack() -{ - if (base_ptr) - delete[] base_ptr; -} - -/*! -** Copies the frame stack fs -** -** \param fs - the frame stack to be copied -*/ -void FrameStack::copy_fstack(const FrameStack& fs) -{ - base_ptr = new data_t[fs.g_size]; - std::copy(fs.base_ptr, fs.frame_ptr + fs.c_size, base_ptr); - frame_ptr = base_ptr + (fs.frame_ptr - fs.base_ptr); -} - -/*! -** Returns a data_t object from the current frame -** -** \param index - index of the data_t object -** \return const reference to the object -*/ -const data_t& FrameStack::operator[](size_t index) const -{ - return frame_ptr[index]; -} - -/*! -** Returns a data_t object from the current frame -** -** \param index - index of the data_t object -** \return reference to the object -*/ -data_t& FrameStack::operator[](size_t index) -{ - return frame_ptr[index]; -} - -/*! -** Removes the current frame from the stack. -** It is called when a function does return. -*/ -void FrameStack::pop_frame() -{ - if (fstack.empty()) - { - frame_ptr = base_ptr; - c_size = 0; - } - else - { - data_t* new_frame_ptr = base_ptr + fstack.top(); - fstack.pop(); - c_size = frame_ptr - new_frame_ptr; - frame_ptr = new_frame_ptr; - } -} - -/*! -** Creates (pushes on the stack) new frame of fsize data_t objects -** -** \param fsize - size in data_t objects of the new frame -*/ -void FrameStack::new_frame(size_t fsize) -{ - if (frame_ptr + c_size + fsize > base_ptr + g_size) - { - size_t new_size = g_size + std::max(g_size, c_size + fsize); - data_t* new_base = new data_t[new_size]; - if (base_ptr) - { - std::copy(base_ptr, frame_ptr + c_size, new_base); - delete[] base_ptr; - } - frame_ptr = new_base + (frame_ptr - base_ptr); - base_ptr = new_base; - } - fstack.push(frame_ptr - base_ptr); - c_size = fsize; -} - -/*! -** \return true if the stack is empty -*/ -bool FrameStack::empty() const -{ - return frame_ptr == base_ptr && c_size == 0; -} -} // namespace SpasmImpl diff --git a/spasm/src/frames.hpp b/spasm/src/frames.hpp deleted file mode 100644 index 14d1d14..0000000 --- a/spasm/src/frames.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef FRAMES_HPP -#define FRAMES_HPP - -#include - -#include "types.hpp" - -namespace SpasmImpl -{ -//! Class representing the stack frame for a function -/*! -** The class is implemented as a simple stack of frames while each frame -** is built up by a number of data_t objects -*/ -class FrameStack -{ - public: - FrameStack(); - FrameStack(const FrameStack&); - ~FrameStack(); - FrameStack& operator=(const FrameStack&); - - const data_t& operator[](size_t) const; - data_t& operator[](size_t); - void pop_frame(); - void new_frame(size_t); - bool empty() const; - - private: - //! pointer to the base of the stack - data_t* base_ptr; - - //! pointer to the beginning of the current frame - data_t* frame_ptr; - - //! size of the whole stack in data_t objects - size_t g_size; - - //! size of the current frame in data_t objects - size_t c_size; - - //! stack of the offsets between frames in the stack. - std::stack fstack; - - void copy_fstack(const FrameStack&); - void delete_fstack(); -}; - -} // namespace SpasmImpl - -#endif // #ifndef FRAMES_HPP diff --git a/spasm/src/main.cpp b/spasm/src/main.cpp index cc2c831..a6465a6 100644 --- a/spasm/src/main.cpp +++ b/spasm/src/main.cpp @@ -24,7 +24,7 @@ int main(int argc, const char* argv[]) std::cout << std::endl; Spasm::Spasm vm; - vm.Initialize(len, bytecode.get()); + vm.Initialize(len, bytecode.get()); vm.run(); diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index 79c72a7..d06552d 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -17,15 +17,15 @@ Spasm::Spasm() {} ** \param _ostr - output stream for the machine */ void Spasm::Initialize(PC_t _bc_size, - const byte* _bytecode, - std::istream& _istr, - std::ostream& _ostr) + const byte* _bytecode, + std::istream& _istr, + std::ostream& _ostr) { - m_PC = 0; - m_ByteCode.assign(_bytecode, _bytecode + _bc_size); - istr = &_istr; - ostr = &_ostr; + m_PC = 0; + m_ByteCode.assign(_bytecode, _bytecode + _bc_size); + istr = &_istr; + ostr = &_ostr; data_stack.resize(1024); m_SP = &data_stack[0]; m_FP = &data_stack[0]; @@ -65,6 +65,15 @@ Spasm::RunResult Spasm::run() push(arg0); break; } + case OpCodes::Alloc: + { + const auto count = PC_t(read_reg(size)); + for (PC_t i = 0; i < count; ++i) + { + push_data(0); + } + break; + } case OpCodes::Print: { const auto arg0 = read_reg(size); @@ -77,6 +86,18 @@ Spasm::RunResult Spasm::run() read(arg0); break; } + case OpCodes::Call: + { + const auto arg0 = read_reg(size); + call(arg0); + break; + } + case OpCodes::Ret: + { + const auto arg0 = read_reg(size); + ret(arg0); + break; + } case OpCodes::Jump: { const auto arg0 = read_reg(size); @@ -97,13 +118,13 @@ Spasm::RunResult Spasm::run() gofalse(arg0, arg1); break; } - case OpCodes::Const: - { - const auto reg = read_reg(size); - const auto value = read_number(size); - set_local(reg, value); - break; - } + case OpCodes::Const: + { + const auto reg = read_reg(size); + const auto value = read_number(size); + set_local(reg, value); + break; + } case OpCodes::Add: { const auto arg0 = read_reg(size); @@ -298,17 +319,13 @@ void Spasm::go(reg_t a0) ** Function call. A new frame with the specified size is created, the ** return address is saved in the return stack and the new pc is loaded. */ -void Spasm::call() +void Spasm::call(reg_t a0) { - assert(false && "not-implemented"); -#if 0 - size_t fs; // new frame size - return_stack.push(pc); // using the ++pc in run() - pop_data(&fs, sizeof(fs)); - pop_data(&pc, sizeof(pc)); - frame.new_frame(fs); - --pc; // the ++pc in run() -#endif + Frame call{m_PC, PC_t(m_FP - &data_stack[0]), + m_SP - &data_stack[0] - PC_t(*(m_SP - 1)) - 1}; + m_Frames.push(std::move(call)); + m_FP = m_SP - 1; + go(a0); } /*! @@ -317,13 +334,12 @@ void Spasm::call() */ void Spasm::ret(reg_t reg) { - // TODO: Implement - (void)reg; -#if 0 - pc = return_stack.top(); - return_stack.pop(); - frame.pop_frame(); -#endif + Frame parent = m_Frames.top(); + m_Frames.pop(); + m_SP = &data_stack[parent.StackPointer]; + *(m_SP - 1) = m_FP[reg]; + m_FP = &data_stack[parent.FramePointer]; + m_PC = parent.ReturnAddress; } /*! @@ -396,9 +412,8 @@ reg_t Spasm::read_reg(size_t size) data_t Spasm::read_number(size_t size) { - assert(size == 0); - return m_ByteCode[m_PC++]; + assert(size == 0); + return m_ByteCode[m_PC++]; } - } // namespace SpasmImpl diff --git a/spasm/src/spasm_impl.hpp b/spasm/src/spasm_impl.hpp index 1e1d3ef..75fb4c4 100644 --- a/spasm/src/spasm_impl.hpp +++ b/spasm/src/spasm_impl.hpp @@ -3,7 +3,6 @@ #include -#include "frames.hpp" #include "types.hpp" namespace SpasmImpl @@ -15,6 +14,7 @@ enum OpCodes : char Pop, PopTo, Push, + Alloc, Print, Read, Call, @@ -30,7 +30,10 @@ enum OpCodes : char Mod, Less, LessEq, + LastIndex = LessEq, }; +static_assert(LastIndex < 0x3f, "Too many opcodes"); + //! The Abstract Stack Machine /*! ** The machine contains a data stack for operations and control flow and @@ -74,11 +77,15 @@ class Spasm //! Frame pointer - the start of the stack for the current function data_t* m_FP = nullptr; - //! Return stack for the addresses of the returns - Rstack_t return_stack; + struct Frame { + PC_t ReturnAddress; + PC_t FramePointer; + PC_t StackPointer; + }; - //! Stack for the frame of the functions - FrameStack frame; + typedef std::stack FrameStack; + //! Stack for function frames + FrameStack m_Frames; //! Input stream for read () operation std::istream* istr; @@ -104,7 +111,7 @@ class Spasm void gofalse(reg_t a0, reg_t a1); void go(reg_t a0); - void call(); + void call(reg_t a0); void ret(reg_t a0); void load(); diff --git a/spasm/src/types.hpp b/spasm/src/types.hpp index ec5a0cb..26450db 100644 --- a/spasm/src/types.hpp +++ b/spasm/src/types.hpp @@ -7,10 +7,9 @@ namespace SpasmImpl { -typedef unsigned char byte; +typedef int8_t byte; typedef size_t PC_t; typedef int data_t; -typedef std::stack Rstack_t; class Spasm; typedef void (Spasm::*Operation)(); -- cgit v1.3.1-23-gd82d