gigatron/rom/Contrib/at67/operators.cpp
2025-01-28 19:17:01 +03:00

1503 lines
54 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <cmath>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#include "memory.h"
#include "cpu.h"
#include "assembler.h"
#include "compiler.h"
#include "operators.h"
#include "linker.h"
namespace Operators
{
bool _nextTempVar = true;
std::vector<std::string> _operators;
std::vector<std::string>& getOperators(void) {return _operators;}
bool initialise(void)
{
_nextTempVar = true;
// Operators
_operators.push_back(" AND ");
_operators.push_back(" XOR ");
_operators.push_back(" OR " );
_operators.push_back("NOT " );
_operators.push_back(" MOD ");
_operators.push_back(" LSL ");
_operators.push_back(" LSR ");
_operators.push_back(" ASR ");
return true;
}
void changeToTmpVar(Expression::Numeric& numeric)
{
numeric._value = uint8_t(Compiler::getTempVarStart());
numeric._varType = Expression::TmpVar;
numeric._name = Compiler::getTempVarStartStr();
}
void createSingleOp(const std::string& opcodeStr, Expression::Numeric& numeric)
{
switch(numeric._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm(opcodeStr, Expression::byteToHexString(uint8_t(std::lround(numeric._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
Compiler::emitVcpuAsmUserVar(opcodeStr, numeric, false);
}
break;
default: break;
}
}
void handleSingleOp(const std::string& opcodeStr, Expression::Numeric& numeric)
{
createSingleOp(opcodeStr, numeric);
changeToTmpVar(numeric);
}
void selectSingleOp(const std::string& opcodeStr, Expression::Numeric& numeric)
{
if(numeric._varType == Expression::Number)
{
int16_t val = int16_t(std::lround(numeric._value));
(val >= 0 && val <= 255) ? Compiler::emitVcpuAsm("LDI", std::to_string(val), false) : Compiler::emitVcpuAsm("LDWI", std::to_string(val), false);
}
else
{
Operators::createSingleOp(opcodeStr, numeric);
}
}
bool handleDualOp(const std::string& opcodeStr, Expression::Numeric& lhs, Expression::Numeric& rhs, bool outputHex)
{
std::string opcode = std::string(opcodeStr);
// Swap left and right to take advantage of LDWI for 16bit numbers
if(rhs._varType == Expression::Number && (rhs._value < 0 || rhs._value > 255))
{
std::swap(lhs, rhs);
if(opcode == "SUB")
{
opcode = "ADD";
if(lhs._value > 0) lhs._value = -lhs._value;
}
}
// LHS
if(lhs._varType == Expression::Number)
{
// 8bit positive constants
if(lhs._value >=0 && lhs._value <= 255)
{
(outputHex) ? Compiler::emitVcpuAsm("LDI", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false) : Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(lhs._value))), false);
}
// 16bit constants
else
{
(outputHex) ? Compiler::emitVcpuAsm("LDWI", Expression::wordToHexString(int16_t(std::lround(lhs._value))), false) : Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(lhs._value))), false);
}
_nextTempVar = true;
}
else
{
switch(lhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
_nextTempVar = false;
}
break;
default: break;
}
}
// RHS
if(rhs._varType == Expression::Number)
{
// Skip XOR if operand is 0, (n XOR 0 = n)
if(rhs._value || opcode != "XOR")
{
(outputHex) ? Compiler::emitVcpuAsm(opcode + "I", Expression::wordToHexString(int8_t(std::lround(rhs._value))), false) : Compiler::emitVcpuAsm(opcode + "I", std::to_string(int8_t(std::lround(rhs._value))), false);
}
}
else
{
switch(rhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm(opcode + "W", Expression::byteToHexString(uint8_t(std::lround(rhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar(opcode + "W", rhs, _nextTempVar)) return false;
_nextTempVar = false;
}
break;
default: break;
}
}
changeToTmpVar(lhs);
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return true;
}
bool handleLogicalOp(const std::string& opcode, Expression::Numeric& lhs)
{
// SYS shift function needs this preamble, LSLW doesn't
switch(lhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
}
break;
default: break;
}
if(opcode != "LSLW") Compiler::emitVcpuAsm("STW", "mathShift", false);
changeToTmpVar(lhs);
return true;
}
void emitCcType(Expression::CCType ccType, std::string& cc)
{
switch(ccType)
{
case Expression::BooleanCC:
{
// Init functions are not needed for ROMv5a and higher as CALLI is able to directly CALL them
if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
{
Compiler::emitVcpuAsm("CALLI", "convert" + cc + "Op", false);
}
else
// Enable system internal sub intialiser and mark system internal sub to be loaded
{
Compiler::emitVcpuAsm("CALL", "convert" + cc + "OpAddr", false);
Compiler::enableSysInitFunc("Init" + cc + "Op");
Linker::setInternalSubToLoad("convert" + cc + "Op");
}
}
break;
case Expression::NormalCC: Compiler::emitVcpuAsm("%Jump" + Expression::strToUpper(cc), "", false); break;
case Expression::FastCC: Compiler::emitVcpuAsm("B" + Expression::strToUpper(cc), "", false); break;
default: break;
}
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
}
bool handleConditionOp(Expression::Numeric& lhs, Expression::Numeric& rhs, Expression::CCType ccType, bool& invertedLogic, const std::string& opcode="SUB")
{
// Swap left and right to take advantage of LDWI for 16bit numbers
invertedLogic = false;
if(rhs._varType == Expression::Number && (rhs._value < 0 || rhs._value > 255))
{
std::swap(lhs, rhs);
invertedLogic = true;
}
// JumpCC and BCC are inverses of each other
lhs._ccType = ccType;
if(ccType == Expression::FastCC) invertedLogic = !invertedLogic;
// LHS
if(lhs._varType == Expression::Number)
{
// 8bit positive constants
if(lhs._value >=0 && lhs._value <= 255)
{
Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(lhs._value))), false);
}
// 16bit constants
else
{
Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(lhs._value))), false);
}
_nextTempVar = true;
}
else
{
switch(lhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
_nextTempVar = false;
}
break;
default: break;
}
}
// RHS
if(rhs._varType == Expression::Number)
{
// Skip XOR if operand is 0, (n XOR 0 = n)
if(rhs._value || opcode != "XOR") Compiler::emitVcpuAsm(opcode + "I", std::to_string(int16_t(std::lround(rhs._value))), false);
}
else
{
switch(rhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm(opcode + "W", Expression::byteToHexString(uint8_t(std::lround(rhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar(opcode + "W", rhs, _nextTempVar)) return false;
_nextTempVar = false;
}
break;
default: break;
}
}
changeToTmpVar(lhs);
return true;
}
bool handleStringCcOP(Expression::Numeric& lhs, Expression::Numeric& rhs, Expression::OPType opType)
{
if(lhs._varType != Expression::String && lhs._varType != Expression::Constant && lhs._varType != Expression::StrVar && lhs._varType != Expression::Str2Var &&
lhs._varType != Expression::TmpStrVar) return false;
if(rhs._varType != Expression::String && rhs._varType != Expression::Constant && rhs._varType != Expression::StrVar && rhs._varType != Expression::Str2Var &&
rhs._varType != Expression::TmpStrVar) return false;
if(lhs._varType == Expression::String && rhs._varType == Expression::String)
{
switch(opType)
{
case Expression::EqOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) == 0); return true;
case Expression::NeOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) != 0); return true;
case Expression::LeOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) <= 0); return true;
case Expression::GeOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) >= 0); return true;
case Expression::LtOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) < 0); return true;
case Expression::GtOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) > 0); return true;
default: break;
}
}
// Get addresses of strings to be compared
int lhsIndex = int(lhs._index);
int rhsIndex = int(rhs._index);
std::string lhsName, rhsName;
uint16_t lhsAddr, rhsAddr;
// String inputs can be literal, const, var and temp
if(lhs._varType == Expression::TmpStrVar)
{
lhsAddr = Compiler::getStrWorkArea();
}
else
{
Compiler::getOrCreateString(lhs, lhsName, lhsAddr, lhsIndex);
}
if(rhs._varType == Expression::TmpStrVar)
{
rhsAddr = Compiler::getStrWorkArea();
}
else
{
Compiler::getOrCreateString(rhs, rhsName, rhsAddr, rhsIndex);
}
// By definition this must be a match
if(lhsAddr == rhsAddr)
{
Compiler::emitVcpuAsm("LDI", "1", false);
}
// Compare strings
else
{
Compiler::emitStringAddress(lhs, lhsAddr);
Compiler::emitVcpuAsm("STW", "strSrcAddr", false);
Compiler::emitStringAddress(rhs, rhsAddr);
Compiler::emitVcpuAsm("%StringCmp", "", false);
// 0, 1, 2, (lesser, equal, greater)
switch(opType)
{
case Expression::EqOP:
{
// 0, 1, 2 to 0, 1, 0
Compiler::emitVcpuAsm("ANDI", "1", false);
}
break;
case Expression::NeOP:
{
// 0, 1, 2 to 1, 0, 1
Compiler::emitVcpuAsm("ANDI", "1", false);
Compiler::emitVcpuAsm("XORI", "1", false);
}
break;
case Expression::LeOP:
{
// 0, 1 to 1 : 2 to 0
Compiler::emitVcpuAsm("XORI", "2", false);
if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
{
Compiler::emitVcpuAsm("CALLI", "convertNeOpAddr", false);
}
else
{
Compiler::emitVcpuAsm("CALL", "convertNeOpAddr", false);
Compiler::enableSysInitFunc("InitNeOp");
Linker::setInternalSubToLoad("convertNeOp");
}
}
break;
case Expression::GeOP:
{
// 1, 2 to 1 : 0 to 0
if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
{
Compiler::emitVcpuAsm("CALLI", "convertNeOpAddr", false);
}
else
{
Compiler::emitVcpuAsm("CALL", "convertNeOpAddr", false);
Compiler::enableSysInitFunc("InitNeOp");
Linker::setInternalSubToLoad("convertNeOp");
}
}
break;
case Expression::LtOP:
{
// 0 to 1 : 1, 2 to 0
if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
{
Compiler::emitVcpuAsm("CALLI", "convertEqOpAddr", false);
}
else
{
Compiler::emitVcpuAsm("CALL", "convertEqOpAddr", false);
Compiler::enableSysInitFunc("InitEqOp");
Linker::setInternalSubToLoad("convertEqOp");
}
}
break;
case Expression::GtOP:
{
// 0, 1 to 0 : 2 to 1
Compiler::emitVcpuAsm("ANDI", "2", false);
if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
{
Compiler::emitVcpuAsm("CALLI", "convertNeOpAddr", false);
}
else
{
Compiler::emitVcpuAsm("CALL", "convertNeOpAddr", false);
Compiler::enableSysInitFunc("InitNeOp");
Linker::setInternalSubToLoad("convertNeOp");
}
}
break;
default: break;
}
}
changeToTmpVar(lhs);
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return true;
}
bool handleStringAdd(Expression::Numeric& lhs, Expression::Numeric& rhs)
{
if(lhs._varType != Expression::String && lhs._varType != Expression::Constant && lhs._varType != Expression::StrVar && lhs._varType != Expression::Str2Var &&
lhs._varType != Expression::TmpStrVar) return false;
if(rhs._varType != Expression::String && rhs._varType != Expression::Constant && rhs._varType != Expression::StrVar && rhs._varType != Expression::Str2Var &&
rhs._varType != Expression::TmpStrVar) return false;
// Get addresses of strings to be compared
int lhsIndex = int(lhs._index);
int rhsIndex = int(rhs._index);
std::string lhsName, rhsName;
uint16_t lhsAddr, rhsAddr;
// String inputs can be literal, const, var and temp
if(lhs._varType == Expression::TmpStrVar)
{
lhsAddr = Compiler::getStrWorkArea();
}
else
{
Compiler::getOrCreateString(lhs, lhsName, lhsAddr, lhsIndex);
}
if(rhs._varType == Expression::TmpStrVar)
{
// If both lhs and rhs are temporaries then get next string work area and swap lhs and rhs, (stringConcat requires dst = src0)
if(lhs._varType == Expression::TmpStrVar) Compiler::nextStrWorkArea();
rhsAddr = Compiler::getStrWorkArea();
std::swap(lhs, rhs);
std::swap(lhsAddr, rhsAddr);
}
else
{
Compiler::getOrCreateString(rhs, rhsName, rhsAddr, rhsIndex);
}
Compiler::emitStringAddress(lhs, lhsAddr);
Compiler::emitVcpuAsm("STW", "strSrcAddr", false);
Compiler::emitStringAddress(rhs, rhsAddr);
Compiler::emitVcpuAsm("STW", "strSrcAddr2", false);
Compiler::emitVcpuAsm("LDWI", Expression::wordToHexString(Compiler::getStrWorkArea()), false);
Compiler::emitVcpuAsm("%StringConcat", "", false);
lhs = Expression::Numeric(0, -1, true, false, false, Expression::TmpStrVar, Expression::BooleanCC, Expression::Int16Both, "", std::string(""));
return true;
}
bool handleMathOp(const std::string& opcode, const std::string& operand, Expression::Numeric& lhs, Expression::Numeric& rhs, bool isMod=false)
{
// LHS
if(lhs._varType == Expression::Number)
{
// 8bit positive constants
if(lhs._value >=0 && lhs._value <= 255)
{
Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(lhs._value))), false);
}
// 16bit constants
else
{
Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(lhs._value))), false);
}
_nextTempVar = true;
}
else
{
switch(lhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
_nextTempVar = false;
}
break;
default: break;
}
}
Compiler::emitVcpuAsm("STW", "mathX", false);
// RHS
if(rhs._varType == Expression::Number)
{
if(rhs._value >=0 && rhs._value <= 255)
{
Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(rhs._value))), false);
}
else
{
Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(rhs._value))), false);
}
}
else
{
switch(rhs._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(rhs._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
if(!Compiler::emitVcpuAsmUserVar("LDW", rhs, _nextTempVar)) return false;
_nextTempVar = false;
}
break;
default: break;
}
}
Compiler::emitVcpuAsm("STW", "mathY", false);
if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
{
Compiler::emitVcpuAsm(opcode, operand, false);
}
else
{
Compiler::emitVcpuAsm("LDWI", operand, false);
Compiler::emitVcpuAsm(opcode, "giga_vAC", false);
}
changeToTmpVar(lhs);
if(isMod) Compiler::emitVcpuAsm("LDW", "mathRem", false);
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return true;
}
uint32_t handleRevOp(uint32_t input, uint32_t n)
{
uint32_t output = 0;
uint32_t bits = input & uint32_t(pow(2, n) - 1);
for(uint32_t i=0; i<=n-1; i++)
{
output = (output << 1) | (bits & 1);
bits = bits >> 1;
}
return output;
}
// ********************************************************************************************
// Unary Operators
// ********************************************************************************************
Expression::Numeric POS(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = +numeric._value;
return numeric;
}
Compiler::getNextTempVar();
handleSingleOp("LDW", numeric);
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return numeric;
}
Expression::Numeric NEG(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = -numeric._value;
return numeric;
}
Compiler::getNextTempVar();
Compiler::emitVcpuAsm("LDI", std::to_string(0), false);
handleSingleOp("SUBW", numeric);
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return numeric;
}
Expression::Numeric NOT(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = ~int16_t(std::lround(numeric._value));
return numeric;
}
Compiler::getNextTempVar();
Compiler::emitVcpuAsm("LDWI", std::to_string(-1), false);
handleSingleOp("XORW", numeric);
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return numeric;
}
// ********************************************************************************************
// Unary Math Operators
// ********************************************************************************************
Expression::Numeric CEIL(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = ceil(numeric._value);
}
return numeric;
}
Expression::Numeric FLOOR(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = floor(numeric._value);
}
return numeric;
}
Expression::Numeric POWF(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number && numeric._params.size() > 0 && numeric._params[0]._varType == Expression::Number)
{
numeric._value = pow(numeric._value, numeric._params[0]._value);
}
numeric._params.clear();
return numeric;
}
Expression::Numeric SQRT(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number && numeric._value > 0.0)
{
numeric._value = sqrt(numeric._value);
}
return numeric;
}
Expression::Numeric EXP(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = exp(numeric._value);
}
return numeric;
}
Expression::Numeric EXP2(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = exp2(numeric._value);
}
return numeric;
}
Expression::Numeric LOG(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number && numeric._value > 0.0)
{
numeric._value = log(numeric._value);
}
return numeric;
}
Expression::Numeric LOG2(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number && numeric._value > 0.0)
{
numeric._value = log2(numeric._value);
}
return numeric;
}
Expression::Numeric LOG10(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number && numeric._value > 0.0)
{
numeric._value = log10(numeric._value);
}
return numeric;
}
Expression::Numeric SIN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = sin(numeric._value*MATH_PI/180.0);
}
return numeric;
}
Expression::Numeric COS(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = cos(numeric._value*MATH_PI/180.0);
}
return numeric;
}
Expression::Numeric TAN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = tan(numeric._value*MATH_PI/180.0);
}
return numeric;
}
Expression::Numeric ASIN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = asin(numeric._value)/MATH_PI*180.0;
}
return numeric;
}
Expression::Numeric ACOS(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = acos(numeric._value)/MATH_PI*180.0;
}
return numeric;
}
Expression::Numeric ATAN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = atan(numeric._value)/MATH_PI*180.0;
}
return numeric;
}
Expression::Numeric ATAN2(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number && numeric._params.size() > 0 && numeric._params[0]._varType == Expression::Number)
{
if(numeric._value != 0.0 || numeric._params[0]._value != 0.0)
{
numeric._value = atan2(numeric._value, numeric._params[0]._value)/MATH_PI*180.0;
}
}
numeric._params.clear();
return numeric;
}
Expression::Numeric RAND(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
long value = std::lround(numeric._value);
numeric._value = (value <= 0) ? 0 : double(rand() % value);
}
return numeric;
}
Expression::Numeric REV16(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = double(handleRevOp(uint32_t(std::lround(numeric._value)), 16));
}
return numeric;
}
Expression::Numeric REV8(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = double(handleRevOp(uint32_t(std::lround(numeric._value)), 8));
}
return numeric;
}
Expression::Numeric REV4(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(numeric._varType == Expression::Number)
{
numeric._value = double(handleRevOp(uint32_t(std::lround(numeric._value)), 4));
}
return numeric;
}
// ********************************************************************************************
// Binary Operators
// ********************************************************************************************
Expression::Numeric ADD(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringAdd(left, right)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value += right._value;
return left;
}
left._isValid = handleDualOp("ADD", left, right, false);
return left;
}
Expression::Numeric SUB(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value -= right._value;
return left;
}
left._isValid = handleDualOp("SUB", left, right, false);
return left;
}
Expression::Numeric AND(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = int16_t(std::lround(left._value)) & int16_t(std::lround(right._value));
return left;
}
left._isValid = handleDualOp("AND", left, right, true);
return left;
}
Expression::Numeric XOR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = int16_t(std::lround(left._value)) ^ int16_t(std::lround(right._value));
return left;
}
left._isValid = handleDualOp("XOR", left, right, true);
return left;
}
Expression::Numeric OR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = int16_t(std::lround(left._value)) | int16_t(std::lround(right._value));
return left;
}
left._isValid = handleDualOp("OR", left, right, true);
return left;
}
// ********************************************************************************************
// Logical Operators
// ********************************************************************************************
Expression::Numeric LSL(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = (int16_t(std::lround(left._value)) << int16_t(std::lround(right._value))) & 0x0000FFFF;
return left;
}
Compiler::getNextTempVar();
if((left._varType == Expression::TmpVar || left._varType == Expression::IntVar16) && right._varType == Expression::Number)
{
if(right._value == 8)
{
switch(left._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LD", Expression::byteToHexString(uint8_t(std::lround(left._value))), false);
}
break;
// User variable name
case Expression::IntVar16:
{
int varIndex = Compiler::findVar(left._name);
if(varIndex == -1) fprintf(stderr, "Operator::LSL() : '%s:%d' : couldn't find variable name '%s' : %s\n", moduleName.c_str(), codeLineStart, left._name.c_str(), codeLineText.c_str());
Compiler::emitVcpuAsm("LD", "_" + left._name, false);
}
default: break;
}
changeToTmpVar(left);
Compiler::emitVcpuAsm("ST", "giga_vAC + 1", false);
Compiler::emitVcpuAsm("ORI", "0xFF", false);
Compiler::emitVcpuAsm("XORI", "0xFF", false);
}
else
{
handleLogicalOp("LSLW", left);
for(uint8_t s=0; s<uint8_t(std::lround(right._value)); s++)
{
Compiler::emitVcpuAsm("LSLW", "", false);
}
}
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
}
return left;
}
Expression::Numeric LSR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = int16_t(std::lround(left._value)) >> int16_t(std::lround(right._value));
return left;
}
Compiler::getNextTempVar();
if((left._varType == Expression::TmpVar || left._varType == Expression::IntVar16) && right._varType == Expression::Number)
{
// Optimised high byte read
if(right._value == 8)
{
switch(left._varType)
{
// Temporary variable address
case Expression::TmpVar:
{
Compiler::emitVcpuAsm("LD", Expression::byteToHexString(uint8_t(std::lround(left._value))) + " + 1", false);
}
break;
// User variable name
case Expression::IntVar16:
{
int varIndex = Compiler::findVar(left._name);
if(varIndex == -1) fprintf(stderr, "Operator::LSR() : '%s:%d' : couldn't find variable name '%s' : %s\n", moduleName.c_str(), codeLineStart, left._name.c_str(), codeLineText.c_str());
Compiler::emitVcpuAsm("LD", "_" + left._name + " + 1", false);
}
break;
default: break;
}
changeToTmpVar(left);
}
else
{
std::string opcode;
switch(int16_t(std::lround(right._value)))
{
case 1: opcode = "%ShiftRight1bit"; break;
case 2: opcode = "%ShiftRight2bit"; break;
case 3: opcode = "%ShiftRight3bit"; break;
case 4: opcode = "%ShiftRight4bit"; break;
case 5: opcode = "%ShiftRight5bit"; break;
case 6: opcode = "%ShiftRight6bit"; break;
case 7: opcode = "%ShiftRight7bit"; break;
default: break;
}
handleLogicalOp(opcode, left);
Compiler::emitVcpuAsm(opcode, "", false);
}
}
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return left;
}
Expression::Numeric ASR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value /= (1 << int16_t(std::lround(right._value))) & 0x0000FFFF;
return left;
}
Compiler::getNextTempVar();
if((left._varType == Expression::TmpVar || left._varType == Expression::IntVar16) && right._varType == Expression::Number)
{
std::string opcode;
switch(int16_t(std::lround(right._value)))
{
case 1: opcode = "%ShiftRightSgn1bit"; break;
case 2: opcode = "%ShiftRightSgn2bit"; break;
case 3: opcode = "%ShiftRightSgn3bit"; break;
case 4: opcode = "%ShiftRightSgn4bit"; break;
case 5: opcode = "%ShiftRightSgn5bit"; break;
case 6: opcode = "%ShiftRightSgn6bit"; break;
case 7: opcode = "%ShiftRightSgn7bit"; break;
case 8: opcode = "%ShiftRightSgn8bit"; break;
default: break;
}
handleLogicalOp(opcode, left);
Compiler::emitVcpuAsm(opcode, "", false);
}
Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
return left;
}
// ********************************************************************************************
// Conditional Operators
// ********************************************************************************************
Expression::Numeric EQ(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringCcOP(left, right, Expression::EqOP)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = (left._value == right._value);
return left;
}
bool invertedLogic = false;
left._isValid = handleConditionOp(left, right, ccType, invertedLogic, "XOR");
// Convert EQ into one of the condition types of branch instruction
std::string cc = (ccType == Expression::FastCC) ? "Ne" : "Eq"; //(!invertedLogic) ? "Eq" : "Ne";
emitCcType(ccType, cc);
return left;
}
Expression::Numeric NE(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringCcOP(left, right, Expression::NeOP)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = left._value != right._value;
return left;
}
bool invertedLogic = false;
left._isValid = handleConditionOp(left, right, ccType, invertedLogic, "XOR");
// Convert NE into one of the condition types of branch instruction
std::string cc = (ccType == Expression::FastCC) ? "Eq" : "Ne"; //(!invertedLogic) ? "Ne" : "Eq";
emitCcType(ccType, cc);
return left;
}
Expression::Numeric LE(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringCcOP(left, right, Expression::LeOP)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = left._value <= right._value;
return left;
}
bool invertedLogic = false;
left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
// Convert LE into one of the condition types of branch instruction
std::string cc = (!invertedLogic) ? "Le" : "Gt";
emitCcType(ccType, cc);
return left;
}
Expression::Numeric GE(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringCcOP(left, right, Expression::GeOP)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = left._value >= right._value;
return left;
}
bool invertedLogic = false;
left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
// Convert GE into one of the condition types of branch instruction
std::string cc = (!invertedLogic) ? "Ge" : "Lt";
emitCcType(ccType, cc);
return left;
}
Expression::Numeric LT(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringCcOP(left, right, Expression::LtOP)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = (left._value < right._value);
return left;
}
bool invertedLogic = false;
left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
// Convert LT into one of the condition types of branch instruction
std::string cc = (!invertedLogic) ? "Lt" : "Ge";
emitCcType(ccType, cc);
return left;
}
Expression::Numeric GT(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(handleStringCcOP(left, right, Expression::GtOP)) return left;
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = (left._value > right._value);
return left;
}
bool invertedLogic = false;
left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
// Convert GT into one of the condition types of branch instruction
std::string cc = (!invertedLogic) ? "Gt" : "Le";
emitCcType(ccType, cc);
return left;
}
// ********************************************************************************************
// Math Operators
// ********************************************************************************************
Expression::Numeric POW(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = pow(double(left._value), double(right._value));
return left;
}
// Optimise base = 0
if(left._varType == Expression::Number && left._value == 0)
{
return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
}
// Optimise base = 1
else if(left._varType == Expression::Number && left._value == 1)
{
return Expression::Numeric(1, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
}
// Optimise exponent = 0
else if(right._varType == Expression::Number && right._value == 0)
{
return Expression::Numeric(1, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
}
left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "power16bit", left, right) : handleMathOp("CALL", "power16bit", left, right);
return left;
}
Expression::Numeric MUL(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value *= right._value;
return left;
}
// Optimise multiply with 0
if((left._varType == Expression::Number && left._value == 0) || (right._varType == Expression::Number && right._value == 0))
{
return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
}
left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "multiply16bit", left, right) : handleMathOp("CALL", "multiply16bit", left, right);
return left;
}
Expression::Numeric DIV(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = (right._value == 0) ? 0 : left._value / right._value;
return left;
}
// Optimise divide with 0, term() never lets denominator = 0
if((left._varType == Expression::Number && left._value == 0) || (right._varType == Expression::Number && right._value == 0))
{
return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
}
left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "divide16bit", left, right) : handleMathOp("CALL", "divide16bit", left, right);
return left;
}
Expression::Numeric MOD(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
{
UNREFERENCED_PARAM(moduleName);
UNREFERENCED_PARAM(codeLineText);
UNREFERENCED_PARAM(codeLineStart);
if(left._varType == Expression::Number && right._varType == Expression::Number)
{
left._value = (int16_t(std::lround(right._value)) == 0) ? 0 : int16_t(std::lround(left._value)) % int16_t(std::lround(right._value));
return left;
}
// Optimise divide with 0, term() never lets denominator = 0
if((left._varType == Expression::Number && left._value == 0) || (right._varType == Expression::Number && right._value == 0))
{
return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
}
left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "divide16bit", left, right, true) : handleMathOp("CALL", "divide16bit", left, right, true);
return left;
}
}