323 lines
14 KiB
C++
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);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|