#include #include "memory.h" #include "cpu.h" #include "loader.h" #include "expression.h" #include "assembler.h" #include "compiler.h" #include "pragmas.h" namespace Pragmas { std::map _pragmas; std::map& getPragmas(void) {return _pragmas;} bool initialise(void) { // Pragmas _pragmas["_codeRomType_"] = {"_codeRomType_", CODEROMTYPE }; _pragmas["_runtimePath_"] = {"_runtimePath_", RUNTIMEPATH }; _pragmas["_runtimeStart_"] = {"_runtimeStart_", RUNTIMESTART }; _pragmas["_userCodeStart_"] = {"_userCodeStart_", USERCODESTART }; _pragmas["_arraysStart_"] = {"_arraysStart_", ARRAYSSTART }; _pragmas["_stringsStart_"] = {"_stringsStart_", STRINGSSTART }; _pragmas["_stringWorkArea_"] = {"_stringWorkArea_", STRINGWORKAREA }; _pragmas["_tempVarSize_"] = {"_tempVarSize_", TEMPVARSIZE }; _pragmas["_codeOptimiseType_"] = {"_codeOptimiseType_", CODEOPTIMISETYPE }; _pragmas["_arrayIndiciesOne_"] = {"_arrayIndiciesOne_", ARRAYINDICIESONE }; _pragmas["_maxNumSprites_"] = {"_maxNumSprites_", MAXNUMSPRITES }; _pragmas["_spriteStripeChunks_"] = {"_spriteStripeChunks_", SPRITESTRIPECHUNKS}; _pragmas["_enable6BitAudioEmu_"] = {"_enable6BitAudioEmu_", ENABLE6BITAUDIOEMU}; return true; } bool findPragma(std::string code, const std::string& pragma, size_t& foundPos) { foundPos = code.find(pragma); if(foundPos != std::string::npos) { foundPos += pragma.size(); return true; } return false; } PragmaResult handlePragmas(std::string& input, int codeLineIndex) { std::vector tokens = Expression::tokenise(input, ' ', false); if(tokens.size() >= 1) { std::string token = tokens[0]; Expression::stripNonStringWhitespace(token); if(_pragmas.find(token) == _pragmas.end()) return PragmaNotFound; // Handle pragma in input size_t foundPos; if(findPragma(token, _pragmas[token]._name, foundPos) && _pragmas[token]._func) { bool success = _pragmas[token]._func(input, codeLineIndex, foundPos); if(success) return PragmaFound; return PragmaError; } } return PragmaNotFound; } // ******************************************************************************************** // Pragmas // ******************************************************************************************** bool CODEROMTYPE(const std::string& input, int codeLineIndex, size_t foundPos) { // Get rom type std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); Expression::strToUpper(pragma); if(Cpu::getRomTypeMap().find(pragma) == Cpu::getRomTypeMap().end()) { fprintf(stderr, "Pragmas::CODEROMTYPE() : 'Main:%d' : syntax error, use _codeRomType_ <\"ROM TYPE\"> : %s\n", codeLineIndex + 1, input.c_str()); return false; } Compiler::setCodeRomType(Cpu::getRomTypeMap()[pragma]); return true; } bool RUNTIMEPATH(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); if(pragma.size() < 3 || !Expression::isStringValid(pragma)) { fprintf(stderr, "Pragmas::RUNTIMEPATH() : 'Main:%d' : syntax error, use _runtimePath_ <\"Path to runtime\"> : %s\n", codeLineIndex + 1, input.c_str()); return false; } // Strip quotes std::string runtimePath = pragma; runtimePath.erase(0, 1); runtimePath.erase(runtimePath.size() - 1, 1); // Set build path Compiler::setBuildPath(runtimePath, Loader::getFilePath()); return true; } bool RUNTIMESTART(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::RUNTIMESTART() : 'Main:%d' : syntax error, use _runtimeStart_
: %s\n", codeLineIndex + 1, input.c_str()); return false; } Expression::Numeric addrNumeric; std::string addrOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], addrOperand, addrNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::RUNTIMESTART() : 'Main:%d' : syntax error in address field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t address = uint16_t(std::lround(addrNumeric._value)); if(address < DEFAULT_EXEC_ADDRESS) { fprintf(stderr, "Pragmas::RUNTIMESTART() : 'Main:%d' : address field must be above &h%04x, found %s : %s\n", codeLineIndex + 1, DEFAULT_EXEC_ADDRESS, tokens[0].c_str(), input.c_str()); return false; } Compiler::setRuntimeStart(address); // Re-initialise memory manager for 64K if(address >= RAM_UPPER_START && Memory::getSizeRAM() != RAM_SIZE_HI) { Memory::setSizeRAM(RAM_SIZE_HI); } // String work area needs to be updated, (return old work areas and get new ones) for(int i=0; i tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::USERCODESTART() : 'Main:%d' : syntax error, use _userCodeStart_
: %s\n", codeLineIndex + 1, input.c_str()); return false; } Expression::Numeric addrNumeric; std::string addrOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], addrOperand, addrNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::USERCODESTART() : 'Main:%d' : syntax error in address field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t address = uint16_t(std::lround(addrNumeric._value)); if(address < DEFAULT_EXEC_ADDRESS) { fprintf(stderr, "Pragmas::USERCODESTART() : 'Main:%d' : address field must be above &h%04x, found %s : %s\n", codeLineIndex + 1, DEFAULT_EXEC_ADDRESS, tokens[0].c_str(), input.c_str()); return false; } // Programmer wants to use video memory as code space if(address >= 0x0800 && address < 0x7FA0 && (address & 0x00FF) < 0x00A0) Memory::invertFreeRAM(); Compiler::setUserCodeStart(address); return true; } bool ARRAYSSTART(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::ARRAYSSTART() : 'Main:%d' : syntax error, use _arraysStart_
: %s\n", codeLineIndex + 1, input.c_str()); return false; } Expression::Numeric addrNumeric; std::string addrOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], addrOperand, addrNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::ARRAYSSTART() : 'Main:%d' : syntax error in address field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t address = uint16_t(std::lround(addrNumeric._value)); if(address < DEFAULT_EXEC_ADDRESS) { fprintf(stderr, "Pragmas::ARRAYSSTART() : 'Main:%d' : address field must be above &h%04x, found %s : %s\n", codeLineIndex + 1, DEFAULT_EXEC_ADDRESS, tokens[0].c_str(), input.c_str()); return false; } Compiler::setArraysStart(address); // Re-initialise memory manager for 64K if(address >= RAM_UPPER_START && Memory::getSizeRAM() != RAM_SIZE_HI) { Memory::setSizeRAM(RAM_SIZE_HI); } return true; } bool STRINGSSTART(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::STRINGSSTART() : 'Main:%d' : syntax error, use _stringsStart_
: %s\n", codeLineIndex + 1, input.c_str()); return false; } Expression::Numeric addrNumeric; std::string addrOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], addrOperand, addrNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::STRINGSSTART() : 'Main:%d' : syntax error in address field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t address = uint16_t(std::lround(addrNumeric._value)); if(address < DEFAULT_EXEC_ADDRESS) { fprintf(stderr, "Pragmas::STRINGSSTART() : 'Main:%d' : address field must be above &h%04x, found %s : %s\n", codeLineIndex + 1, DEFAULT_EXEC_ADDRESS, tokens[0].c_str(), input.c_str()); return false; } Compiler::setStringsStart(address); // Re-initialise memory manager for 64K if(address >= RAM_UPPER_START && Memory::getSizeRAM() != RAM_SIZE_HI) { Memory::setSizeRAM(RAM_SIZE_HI); } return true; } bool STRINGWORKAREA(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::STRINGWORKAREA() : 'Main:%d' : syntax error, use _stringWorkArea_
: %s\n", codeLineIndex + 1, input.c_str()); return false; } Expression::Numeric addrNumeric; std::string addrOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], addrOperand, addrNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::STRINGWORKAREA() : 'Main:%d' : syntax error in address field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t strWorkArea = uint16_t(std::lround(addrNumeric._value)); if(strWorkArea < DEFAULT_EXEC_ADDRESS) { fprintf(stderr, "Pragmas::STRINGWORKAREA() : 'Main:%d' : address field must be above &h%04x, found %s : %s\n", codeLineIndex + 1, DEFAULT_EXEC_ADDRESS, tokens[0].c_str(), input.c_str()); return false; } // String work area needs to be updated, (return old work areas and get new ones) Memory::giveFreeRAM(Compiler::getStrWorkArea(0), USER_STR_SIZE + 2); if(!Memory::takeFreeRAM(strWorkArea, USER_STR_SIZE + 2)) { fprintf(stderr, "Pragmas::STRINGWORKAREA() : 'Main:%d' : setting new string work area failed : %s\n", codeLineIndex + 1, input.c_str()); return false; } Compiler::setStrWorkArea(strWorkArea, 0); Memory::giveFreeRAM(Compiler::getStrWorkArea(1), USER_STR_SIZE + 2); if(!Memory::getFreeRAM(Memory::FitDescending, USER_STR_SIZE + 2, USER_CODE_START, strWorkArea, strWorkArea)) { fprintf(stderr, "Pragmas::STRINGWORKAREA() : 'Main:%d' : setting new string work area failed : %s\n", codeLineIndex + 1, input.c_str()); return false; } Compiler::setStrWorkArea(strWorkArea, 1); return true; } bool TEMPVARSIZE(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::TEMPVARSIZE() : 'Main:%d' : syntax error, use '_tempVarSize_ ' : %s\n", codeLineIndex + 1, input.c_str()); return false; } Expression::Numeric sizeNumeric; std::string sizeOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], sizeOperand, sizeNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::TEMPVARSIZE() : 'Main:%d' : syntax error in size field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint8_t size = uint8_t(std::lround(sizeNumeric._value)); if(size < 2 || size > 16) { fprintf(stderr, "Pragmas::TEMPVARSIZE() : 'Main:%d' : size field must be in the range 2 to 16, found %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } Compiler::setTempVarSize(size); return true; } bool CODEOPTIMISETYPE(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::CODEOPTIMISETYPE() : 'Main:%d' : syntax error, use _codeOptimiseType_ : %s\n", codeLineIndex + 1, input.c_str()); return false; } if(tokens[0] == "SIZE") { Compiler::setCodeOptimiseType(Compiler::CodeSize); return true; } else if(tokens[0] == "SPEED") { Compiler::setCodeOptimiseType(Compiler::CodeSpeed); return true; } fprintf(stderr, "Pragmas::CODEOPTIMISETYPE() : 'Main:%d' : syntax error, _use codeOptimiseType_ <'size'/'speed'> : %s\n", codeLineIndex + 1, input.c_str()); return false; } bool ARRAYINDICIESONE(const std::string& input, int codeLineIndex, size_t foundPos) { UNREFERENCED_PARAM(input); UNREFERENCED_PARAM(foundPos); UNREFERENCED_PARAM(codeLineIndex); Compiler::setArrayIndiciesOne(true); return true; } bool MAXNUMSPRITES(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false, true); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::MAXNUMSPRITES() : 'Main:%d' : syntax error, use _maxNumSprites_ : %s\n", codeLineIndex + 1, input.c_str()); return false; } // Max num sprites Expression::Numeric maxNumNumeric; std::string maxNumOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], maxNumOperand, maxNumNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::MAXNUMSPRITES() : 'Main:%d' : syntax error in max num field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t maxNumSprites = uint16_t(std::lround(maxNumNumeric._value)); if(Compiler::getRuntimeStart() < RAM_UPPER_START && maxNumSprites > MAX_NUM_SPRITES_LO) { fprintf(stderr, "Pragmas::MAXNUMSPRITES() : 'Main:%d' : maximum number of sprites for 32K RAM is limited to %d, found %s : %s\n", codeLineIndex + 1, MAX_NUM_SPRITES_LO, tokens[0].c_str(), input.c_str()); return false; } if(Compiler::getRuntimeStart() >= RAM_UPPER_START && maxNumSprites > MAX_NUM_SPRITES_HI) { fprintf(stderr, "Pragmas::MAXNUMSPRITES() : 'Main:%d' : maximum number of sprites for 64K RAM is limited to %d, found %s : %s\n", codeLineIndex + 1, MAX_NUM_SPRITES_HI, tokens[0].c_str(), input.c_str()); return false; } // Allocate RAM for sprite's LUT now, otherwise more than 48 sprites in a 32K RAM system can fail uint16_t lutAddress; int lutSize = int(maxNumSprites) * 2; if(!Memory::getFreeRAM(Memory::FitDescending, lutSize, USER_CODE_START, Compiler::getRuntimeStart(), lutAddress)) { fprintf(stderr, "Pragmas::MAXNUMSPRITES() : 'Main:%d' : not enough RAM for sprites LUT of size %d : %s\n", codeLineIndex + 1, lutSize, input.c_str()); return false; } Compiler::setSpritesAddrLutAddress(lutAddress); return true; } bool SPRITESTRIPECHUNKS(const std::string& input, int codeLineIndex, size_t foundPos) { std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false, true); if(tokens.size() < 1 || tokens.size() > 3) { fprintf(stderr, "Pragmas::SPRITESTRIPECHUNKS() : 'Main:%d' : syntax error, use _spriteStripeChunks_ , , : %s\n", codeLineIndex + 1, input.c_str()); return false; } // Number of chunks Expression::Numeric chunksNumeric; std::string chunksOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[0], chunksOperand, chunksNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::SPRITESTRIPECHUNKS() : 'Main:%d' : syntax error in num chunks field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t spriteStripeChunks = uint16_t(std::lround(chunksNumeric._value)); if(spriteStripeChunks > SPRITE_STRIPE_CHUNKS_HI) { fprintf(stderr, "Pragmas::SPRITESTRIPECHUNKS() : 'Main:%d' : num chunks field can not be larger than %d, found %s : %s\n", codeLineIndex + 1, SPRITE_STRIPE_CHUNKS_HI, tokens[0].c_str(), input.c_str()); return false; } Compiler::setSpriteStripeChunks(spriteStripeChunks); // RAM minimum address if(tokens.size() >= 2) { Expression::Numeric addrNumeric; std::string addrOperand; if(Compiler::parseStaticExpression(codeLineIndex, tokens[1], addrOperand, addrNumeric) == Compiler::OperandInvalid) { fprintf(stderr, "Pragmas::SPRITESTRIPECHUNKS() : 'Main:%d' : syntax error in address field %s : %s\n", codeLineIndex + 1, tokens[0].c_str(), input.c_str()); return false; } uint16_t minAddress = uint16_t(std::lround(addrNumeric._value)); if(minAddress < DEFAULT_EXEC_ADDRESS) { fprintf(stderr, "Pragmas::SPRITESTRIPECHUNKS() : 'Main:%d' : address field must be above &h%04x, found %s : %s\n", codeLineIndex + 1, DEFAULT_EXEC_ADDRESS, tokens[1].c_str(), input.c_str()); return false; } Compiler::setSpriteStripeMinAddress(minAddress); } // RAM fit type if(tokens.size() == 3) { if(tokens[2] == "ASCENDING") { Compiler::setSpriteStripeFitType(Memory::FitAscending); return true; } else if(tokens[2] == "DESCENDING") { Compiler::setSpriteStripeFitType(Memory::FitDescending); return true; } else { fprintf(stderr, "Pragmas::SPRITESTRIPECHUNKS() : 'Main:%d' : search direction field must be 'ascending or descending', found '%s' : %s\n", codeLineIndex + 1, tokens[2].c_str(), input.c_str()); return false; } } return true; } bool ENABLE6BITAUDIOEMU(const std::string& input, int codeLineIndex, size_t foundPos) { #ifdef STAND_ALONE UNREFERENCED_PARAM(foundPos); #endif if(Compiler::getCodeRomType() < Cpu::ROMv5a) { fprintf(stderr, "Pragmas::ENABLE6BITAUDIOEMU() : 'Main:%d' : version error, '_enable6BitAudioEmu_ ' only works with ROMv5a or greater; use '_codeRomType_ ROMv5a' : %s\n", codeLineIndex + 1, input.c_str()); return false; } #ifndef STAND_ALONE std::string pragma = input.substr(foundPos); Expression::stripNonStringWhitespace(pragma); std::vector tokens = Expression::tokenise(pragma, ',', false, true); if(tokens.size() != 1) { fprintf(stderr, "Pragmas::ENABLE6BITAUDIOEMU() : 'Main:%d' : syntax error, use '_enable6BitAudioEmu_ ' : %s\n", codeLineIndex + 1, input.c_str()); return false; } // ON/OFF bool enable = false; Expression::strToUpper(tokens[0]); if(tokens[0] == "ON") enable = true; else if(tokens[0] == "OFF") enable = false; else { fprintf(stderr, "Pragmas::ENABLE6BITAUDIOEMU() : 'Main:%d' : syntax error, use '_enable6BitAudioEmu_ ' : %s\n", codeLineIndex + 1, input.c_str()); return false; } Cpu::enable6BitSound(Cpu::ROMv5a, enable); return true; #else fprintf(stderr, "Pragmas::ENABLE6BITAUDIOEMU() : 'Main:%d' : syntax error, '_enable6BitAudioEmu_ ', only works in emulation mode : %s\n", codeLineIndex + 1, input.c_str()); return false; #endif } }