rrcc/src/instructions/virtual/Stack.cpp

323 lines
14 KiB
C++

/*****************************************************************************
* Copyright (c) 2020, rrcc FM10K-Documentation Contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <stdexcept>
#include <algorithm>
#include "Stack.h"
#include "../Write.h"
#include "../Load.h"
#include "../Copy.h"
#include "../CalcImm.h"
namespace Instruction {
namespace Stack {
PutImm::PutImm(uint32_t param, const std::vector<uint32_t> &value) {
if (value.size() > 16) {
instructions.push_back(
std::make_unique<Load>(AddressWithOffset{param, frameOffsetRegister}, 1, value));
} else {
instructions.push_back(
std::make_unique<Write>(AddressWithOffset{param, frameOffsetRegister}, value));
}
}
std::vector<uint8_t> PutImm::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
Put::Put(uint32_t param, const AddressWithOffset &address, uint8_t count) {
if (count > 4) {
throw std::runtime_error("Put address count cannot be larger than 4 words at once");
}
instructions.push_back(
std::make_unique<Copy>(AddressWithOffset{param, frameOffsetRegister}, address, count));
}
std::vector<uint8_t> Put::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
std::unique_ptr<Instruction> Put::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
const std::vector<Token> &tokens) {
if (tokens.at(0).getType() == Token::Type::RegisterLocation) {
return std::make_unique<Stack::Put>(tokens.at(0).getNumericValue(), AddressWithOffset{tokens.at(1).getNumericValue(), op.offset1}, tokens.size() >= 3 ? tokens.at(2).getNumericValue() : 1);
} else {
std::vector<uint32_t> data;
for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) {
data.emplace_back(it->getNumericValue());
}
return std::make_unique<Stack::PutImm>(tokens.at(0).getNumericValue(), data);
}
}
Get::Get(const AddressWithOffset &address, uint32_t param, uint8_t count) {
if (count > 4) {
throw std::runtime_error("Get count cannot be larger than 4 words at once");
}
instructions.push_back(
std::make_unique<Copy>(address, AddressWithOffset{param, frameOffsetRegister}, count));
}
std::vector<uint8_t> Get::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
std::unique_ptr<Instruction> Get::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
const std::vector<Token> &tokens) {
return std::make_unique<Stack::Get>(
AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
tokens.size() >= 2 ? tokens.at(1).getNumericValue() : 0,
tokens.size() >= 3 ? tokens.at(2).getNumericValue() : 1);
}
PushImm::PushImm(const std::vector<uint32_t> &value) {
instructions.push_back(std::make_unique<CalcImm>(Calc::Operation::SUB, 0, stackOffsetRegisterAddress,
stackOffsetRegisterAddress, value.size()));
if (value.size() > 16) {
instructions.push_back(
std::make_unique<Load>(AddressWithOffset{1, stackOffsetRegister}, 1, value));
} else {
instructions.push_back(
std::make_unique<Write>(AddressWithOffset{1, stackOffsetRegister}, value));
}
}
std::vector<uint8_t> PushImm::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
Push::Push(const AddressWithOffset &address, uint8_t count) {
if (count > 4) {
throw std::runtime_error("Push address count cannot be larger than 4 words at once");
}
instructions.push_back(std::make_unique<CalcImm>(Calc::Operation::SUB, 0, stackOffsetRegisterAddress,
stackOffsetRegisterAddress, count));
instructions.push_back(
std::make_unique<Copy>(AddressWithOffset{1, stackOffsetRegister}, address, count));
}
std::vector<uint8_t> Push::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
std::unique_ptr<Instruction> Push::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
const std::vector<Token> &tokens) {
if (tokens.at(0).getType() == Token::Type::RegisterLocation) {
return std::make_unique<Stack::Push>(
AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
tokens.size() >= 2 ? tokens.at(1).getNumericValue() : 1);
} else {
std::vector<uint32_t> data;
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
data.emplace_back(it->getNumericValue());
}
return std::make_unique<Stack::PushImm>(data);
}
}
PushGroup::PushGroup(const std::vector<std::pair<Kind, std::pair<uint32_t, AddressWithOffset>>>& group) {
std::vector<std::pair<Kind, std::vector<uint32_t>>> totalData;
uint32_t totalElements = 0;
for(auto& i : group){
auto& kind = i.first;
if(kind == Kind::Immediate){
if(totalData.empty() || totalData.back().first != Kind::Immediate){
totalData.push_back({kind, {i.second.first}});
}else {
totalData.back().second.emplace_back(i.second.first);
}
++totalElements;
} else if (kind == Kind::Address){
totalData.push_back({kind, {i.second.second.address, i.second.second.offset, i.second.first}});
totalElements += i.second.first;
}
}
instructions.push_back(std::make_unique<CalcImm>(Calc::Operation::SUB, 0, stackOffsetRegisterAddress,
stackOffsetRegisterAddress, totalElements));
uint32_t currentIndex = 0;
for(auto& i : totalData){
if(i.first == Kind::Immediate){
auto reversedData = i.second;
std::reverse(reversedData.begin(), reversedData.end());
if (i.second.size() > 16) {
instructions.push_back(
std::make_unique<Load>(AddressWithOffset{1 + totalElements - currentIndex - (uint32_t) reversedData.size(), stackOffsetRegister}, 1, reversedData));
} else {
instructions.push_back(
std::make_unique<Write>(AddressWithOffset{1 + totalElements - currentIndex - (uint32_t) reversedData.size(), stackOffsetRegister}, reversedData));
}
currentIndex += i.second.size();
} else if (i.first == Kind::Address && i.second.size() == 3){
if (i.second.at(2) > 4) {
throw std::runtime_error("Push address count cannot be larger than 4 words at once");
}
instructions.push_back(std::make_unique<Copy>(AddressWithOffset{1 + totalElements - currentIndex - i.second.at(2), stackOffsetRegister}, AddressWithOffset{i.second.at(0), (uint8_t)i.second.at(1)}, i.second.at(2)));
currentIndex += i.second.at(2);
}
}
}
std::vector<uint8_t> PushGroup::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
PopPeek::PopPeek(const AddressWithOffset &address, uint32_t offset, uint8_t count) {
if (count > 4) {
throw std::runtime_error("PopPeek count cannot be larger than 4 words at once");
}
instructions.push_back(
std::make_unique<Copy>(address, AddressWithOffset{count + offset, stackOffsetRegister}, count));
}
std::vector<uint8_t> PopPeek::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
std::unique_ptr<Instruction> PopPeek::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
const std::vector<Token> &tokens) {
return std::make_unique<Stack::PopPeek>(
AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
tokens.size() >= 2 ? tokens.at(1).getNumericValue() : 0,
tokens.size() >= 3 ? tokens.at(2).getNumericValue() : 1);
}
PopImm::PopImm(uint8_t count) {
instructions.push_back(std::make_unique<CalcImm>(Calc::Operation::ADD, 0, stackOffsetRegisterAddress,
stackOffsetRegisterAddress, count));
}
std::vector<uint8_t> PopImm::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
std::unique_ptr<Instruction> PopImm::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
const std::vector<Token> &tokens) {
return std::make_unique<Stack::PopImm>(tokens.size() >= 1 ? tokens.at(0).getNumericValue() : 1);
}
Pop::Pop(const AddressWithOffset &address, uint8_t count) {
if (count > 4) {
throw std::runtime_error("Pop count cannot be larger than 4 words at once");
}
instructions.push_back(
std::make_unique<Copy>(address, AddressWithOffset{1, stackOffsetRegister}, count));
instructions.push_back(std::make_unique<CalcImm>(Calc::Operation::ADD, 0, stackOffsetRegisterAddress,
stackOffsetRegisterAddress, count));
}
std::vector<uint8_t> Pop::toBytes() const {
std::vector<uint8_t> v;
for (auto &i : instructions) {
auto b = i->toBytes();
v.insert(v.end(), b.begin(), b.end());
}
return v;
}
std::unique_ptr<Instruction> Pop::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
const std::vector<Token> &tokens) {
return std::make_unique<Stack::Pop>(
AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
tokens.size() >= 2 ? tokens.at(1).getNumericValue() : 1);
}
}
}