rrcc/src/instructions/Instruction.cpp
DataHoarder 93a5ae1c13
All checks were successful
continuous-integration/drone/push Build is passing
Implemented INIT op
2021-08-05 16:29:29 +02:00

301 lines
15 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 <sstream>
#include <algorithm>
#include "Instruction.h"
#include "Write.h"
#include "Copy.h"
#include "Load.h"
#include "Init.h"
#include "Calc.h"
#include "CalcImm.h"
#include "Branch.h"
#include "Poll.h"
#include "Loop.h"
#include "Jump.h"
#include "Return.h"
#include "Set.h"
#include "Wait.h"
#include "End.h"
#include "virtual/Stack.h"
#include "virtual/Call.h"
#include "virtual/FastCall.h"
#include "virtual/Container.h"
#include "../Declaration.h"
namespace Instruction {
std::vector<struct Instruction::knownOperator> Instruction::knownOperators{};
void Instruction::addDefaultOperators() {
addOperator("POP", 1, Stack::Pop::fromTokens);
addOperator("POPI", 0, Stack::PopImm::fromTokens);
addOperator("POPP", 1, Stack::PopPeek::fromTokens);
addOperator("PUSH", 1, Stack::Push::fromTokens);
addOperator("GET", 1, Stack::Get::fromTokens);
addOperator("PUT", 1, Stack::Put::fromTokens);
addOperator("CALL", 1, Call::fromTokens);
addOperator("RET", 0, Ret::fromTokens);
addOperator("FASTCALL", 1, FastCall::fromTokens);
addOperator("MOV", 2, [](const parseOperatorResult &op, const std::vector<Token> &tokens) -> std::unique_ptr<Instruction> {
if (tokens.at(1).getType() == Token::Type::RegisterLocation) {
return std::make_unique<Copy>(AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
AddressWithOffset{tokens.at(1).getNumericValue(), op.offset2}, 1);
} else {
return std::make_unique<Write>(AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
std::vector<uint32_t>{tokens.at(1).getNumericValue()});
}
});
addOperator("JUMP", 1, Jump::fromTokens);
addOperator("RETURN", 1, Return::fromTokens);
addOperator("WRITE", 2, Write::fromTokens);
addOperator("COPY", 2, Copy::fromTokens);
// INIT <R> <count> [data] [data_add]
addOperator("INIT", 2, Init::fromTokens);
addOperator("INIT_DIRECT", 2, Init::fromDirectTokens);
addOperator("LOAD", 2, Load::fromTokens);
addOperator("LOAD_DIRECT", 2, Load::fromDirectTokens);
// NOT dest, source
//Using NOT x = 255 - x.
addOperator("NOT", 2, [](const parseOperatorResult &op, const std::vector<Token> &tokens) -> std::unique_ptr<Instruction> {
if(op.offset1 != 0){
auto c = std::make_unique<Container>("NOT op with offset");
c->addInstruction(std::make_unique<Copy>(AddressWithOffset{(uint32_t) MgmtRegisters::std_SCRATCH_0, 0}, AddressWithOffset{tokens.at(1).getNumericValue(), op.offset1}, 1));
c->addInstruction(std::make_unique<Calc>(Calc::Operation::SUB, 0,
(uint32_t) MgmtRegisters::std_SCRATCH_0,
(uint32_t)MgmtRegisters::INTERNAL_REGISTER_ALWAYS_FFFFFFFF,
(uint32_t) MgmtRegisters::std_SCRATCH_0));
c->addInstruction(std::make_unique<Copy>(AddressWithOffset{tokens.at(1).getNumericValue(), op.offset2}, AddressWithOffset{(uint32_t) MgmtRegisters::std_SCRATCH_0, 0}, 1));
return std::move(c);
}
auto i = std::make_unique<Calc>(Calc::Operation::SUB, 0,
tokens.at(0).getNumericValue(),
(uint32_t)MgmtRegisters::INTERNAL_REGISTER_ALWAYS_FFFFFFFF,
tokens.at(1).getNumericValue());
i->comment = "NOT op";
return std::move(i);
});
//XOR P1, P2 = A, P3 = B
addOperator("XOR", 3, [](const parseOperatorResult &op, const std::vector<Token> &tokens) -> std::unique_ptr<Instruction> {
if(op.offset1 != 0){
throw std::runtime_error("XOR cannot use addressing offsets");
}
auto c = std::make_unique<Container>("XOR op = a + b - (a & b) - (a & b)");
/*
* Non-offset version
* AND S1, A, B
* ADD S0, A, B
* SUB S0, S0, S1
* SUB P1, S0, S1
*/
if(tokens.at(2).getType() == Token::Type::Immediate){
c->addInstruction(std::make_unique<CalcImm>(Calc::Operation::AND, 0, (uint32_t) MgmtRegisters::std_SCRATCH_1, tokens.at(1).getNumericValue(), tokens.at(2).getNumericValue()), "XOR, s1 = a & b");
c->addInstruction(std::make_unique<CalcImm>(Calc::Operation::ADD, 0, (uint32_t) MgmtRegisters::std_SCRATCH_0, tokens.at(1).getNumericValue(), tokens.at(2).getNumericValue()), "XOR, s0 = a + b");
}else{
c->addInstruction(std::make_unique<Calc>(Calc::Operation::AND, 0, (uint32_t) MgmtRegisters::std_SCRATCH_1, tokens.at(1).getNumericValue(), tokens.at(2).getNumericValue()), "XOR, s1 = a & b");
c->addInstruction(std::make_unique<Calc>(Calc::Operation::ADD, 0, (uint32_t) MgmtRegisters::std_SCRATCH_0, tokens.at(1).getNumericValue(), tokens.at(2).getNumericValue()), "XOR, s0 = a + b");
}
c->addInstruction(std::make_unique<Calc>(Calc::Operation::SUB, 0, (uint32_t) MgmtRegisters::std_SCRATCH_0, (uint32_t) MgmtRegisters::std_SCRATCH_0, (uint32_t) MgmtRegisters::std_SCRATCH_1), "XOR, s0 = s0 - s1");
c->addInstruction(std::make_unique<Calc>(Calc::Operation::SUB, 0, tokens.at(0).getNumericValue(), (uint32_t) MgmtRegisters::std_SCRATCH_0, (uint32_t) MgmtRegisters::std_SCRATCH_1), "XOR, result = s0 - s1");
return std::move(c);
});
addOperator("AND", 3, CalcImm::fromAndTokens);
addOperator("OR", 3, CalcImm::fromOrTokens);
addOperator("ADD", 3, CalcImm::fromAddTokens);
addOperator("SUB", 3, CalcImm::fromSubTokens);
addOperator("LSHIFT", 3, CalcImm::fromLShiftTokens);
addOperator("SHL", 3, CalcImm::fromLShiftTokens);
addOperator("RSHIFT", 3, CalcImm::fromRShiftTokens);
addOperator("SHR", 3, CalcImm::fromRShiftTokens);
addOperator("ARSHIFT", 3, CalcImm::fromARShiftTokens);
addOperator("SAR", 3, CalcImm::fromARShiftTokens);
addOperator("BRANCH_EQUALS", 4, Branch::fromEqualTokens);
addOperator("BEQ", 4, Branch::fromEqualTokens); //TODO: redo
addOperator("BRANCH_NOTEQUALS", 4, Branch::fromNonEqualTokens);
addOperator("BNE", 4, Branch::fromNonEqualTokens); //TODO: redo
addOperator("POLL_EQUALS", 6, Poll::fromEqualTokens);
addOperator("PEQ", 6, Poll::fromEqualTokens); //TODO: redo
addOperator("POLL_NOTEQUALS", 6, Poll::fromNonEqualTokens);
addOperator("PNE", 6, Poll::fromNonEqualTokens); //TODO: redo
//This allows both static and dynamic calls, with multiple offsets
addOperator("SET", 3, [](const parseOperatorResult &op, const std::vector<Token> &tokens) -> std::unique_ptr<Instruction> {
if (tokens.at(1).getType() == Token::Type::Immediate && tokens.at(2).getType() == Token::Type::Immediate) {
return Set::fromTokens(op, tokens);
} else {
auto c = std::make_unique<Container>("SET op, extended with registers");
//Get register if needed due to offset
if (op.offset1) {
c->addInstruction(std::make_unique<Copy>(AddressWithOffset{(uint32_t) MgmtRegisters::std_SCRATCH_0, 0},
AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1}));
}
//S0 = (Register & ~maskValue)
if (tokens.at(2).getType() == Token::Type::Immediate) {
c->addInstruction(std::make_unique<CalcImm>(Calc::Operation::AND, 0, (uint32_t) MgmtRegisters::std_SCRATCH_0,
op.offset1 ? (uint32_t) MgmtRegisters::std_SCRATCH_0 : tokens.at(
0).getNumericValue(), ~tokens.at(2).getNumericValue()));
} else {
if (op.offset2) {
c->addInstruction(std::make_unique<Copy>(AddressWithOffset{(uint32_t) MgmtRegisters::std_SCRATCH_1, 0},
AddressWithOffset{tokens.at(2).getNumericValue(), op.offset2}));
}
//NOT without offset
c->addInstruction(std::make_unique<Calc>(Calc::Operation::SUB, 0,
(uint32_t) MgmtRegisters::std_SCRATCH_1,
(uint32_t) MgmtRegisters::INTERNAL_REGISTER_ALWAYS_FFFFFFFF,
op.offset2 ? (uint32_t) MgmtRegisters::std_SCRATCH_1 : tokens.at(
2).getNumericValue()));
c->addInstruction(std::make_unique<Calc>(Calc::Operation::AND, 0, (uint32_t) MgmtRegisters::std_SCRATCH_0,
op.offset1 ? (uint32_t) MgmtRegisters::std_SCRATCH_0 : tokens.at(
0).getNumericValue(), (uint32_t) MgmtRegisters::std_SCRATCH_1));
}
//Register = S0 | value
if (tokens.at(1).getType() == Token::Type::Immediate) {
c->addInstruction(std::make_unique<CalcImm>(Calc::Operation::OR, 0,
op.offset1 ? (uint32_t) MgmtRegisters::std_SCRATCH_0 : tokens.at(
0).getNumericValue(), (uint32_t) MgmtRegisters::std_SCRATCH_0,
tokens.at(1).getNumericValue()));
} else {
if (op.offset3) {
c->addInstruction(std::make_unique<Copy>(AddressWithOffset{(uint32_t) MgmtRegisters::std_SCRATCH_1, 0},
AddressWithOffset{tokens.at(1).getNumericValue(), op.offset2}));
}
c->addInstruction(std::make_unique<Calc>(Calc::Operation::OR, 0,
op.offset1 ? (uint32_t) MgmtRegisters::std_SCRATCH_0 : tokens.at(
0).getNumericValue(), (uint32_t) MgmtRegisters::std_SCRATCH_0,
op.offset3 ? (uint32_t) MgmtRegisters::std_SCRATCH_1 : tokens.at(
1).getNumericValue()));
}
//set register if needed due to offset
if (op.offset1) {
c->addInstruction(std::make_unique<Copy>(AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
AddressWithOffset{(uint32_t) MgmtRegisters::std_SCRATCH_0, 0}));
}
return std::move(c);
}
});
addOperator("LOOP", 1, Loop::fromTokens);
addOperator("WAIT", 1, Wait::fromTokens);
addOperator("END", 0, End::fromTokens);
}
std::unique_ptr<Instruction> Instruction::getCommandForDeclaration(const Declaration &declaration) {
size_t offset = 0;
for (auto &t : declaration.tokens) {
if (t.getType() == Token::Type::Operator) {
break;
}
++offset;
}
if (offset == declaration.tokens.size()) {
return nullptr;
}
offset++;
std::string operatorValue = declaration.tokens.at(offset - 1).getTextValue();
auto operatorData = parseOperator(operatorValue);
std::vector<Token> tokens(declaration.tokens.begin() + offset, declaration.tokens.end());
std::string opName = operatorData.name;
for (auto & c: opName){
c = std::toupper(c);
}
for (auto &e : knownOperators) {
if (e.name == opName && tokens.size() >= e.minParams) {
return e.callable(operatorData, tokens);
}
}
return nullptr;
}
Instruction::parseOperatorResult Instruction::parseOperator(const std::string &op) {
std::stringstream s(op);
std::vector<std::string> segments;
std::string segment;
while (std::getline(s, segment, '~')) {
segments.push_back(segment);
}
uint8_t offset1 = segments.size() > 1 ? std::stoul(segments.at(1).substr(0, 1), nullptr, 10) : 0;
uint8_t offset2 = (segments.size() > 1 && segments.at(1).size() > 1) ? std::stoul(
segments.at(1).substr(1, 1), nullptr, 10) : 0;
return Instruction::parseOperatorResult{
segments.at(0),
offset1,
offset2
};
}
}