#include #include #include #include #include #include #include #include #include #include #include "memory.h" #include "cpu.h" #include "assembler.h" #include "compiler.h" #include "linker.h" namespace Linker { std::map> _subIncludeFiles; std::map _internalSubMap; // TODO: use std::map std::vector _internalSubs = { {0x0000, 0x0000, "romCheck" , "", false, false}, {0x0000, 0x0000, "romExec" , "", false, false}, {0x0000, 0x0000, "romRead" , "", false, false}, {0x0000, 0x0000, "realTimeStub" , "", false, false}, {0x0000, 0x0000, "convertEqOp" , "", false, false}, {0x0000, 0x0000, "convertNeOp" , "", false, false}, {0x0000, 0x0000, "convertLeOp" , "", false, false}, {0x0000, 0x0000, "convertGeOp" , "", false, false}, {0x0000, 0x0000, "convertLtOp" , "", false, false}, {0x0000, 0x0000, "convertGtOp" , "", false, false}, {0x0000, 0x0000, "convert8Arr2d" , "", false, false}, {0x0000, 0x0000, "convert8Arr3d" , "", false, false}, {0x0000, 0x0000, "convert16Arr2d" , "", false, false}, {0x0000, 0x0000, "convert16Arr3d" , "", false, false}, {0x0000, 0x0000, "setRealTimeProc0" , "", false, false}, {0x0000, 0x0000, "setRealTimeProc1" , "", false, false}, {0x0000, 0x0000, "setRealTimeProc2" , "", false, false}, {0x0000, 0x0000, "loadRegs" , "", false, false}, {0x0000, 0x0000, "saveRegs" , "", false, false}, {0x0000, 0x0000, "copyBytes" , "", false, false}, {0x0000, 0x0000, "copyWords" , "", false, false}, {0x0000, 0x0000, "copyLoaderImages" , "", false, false}, {0x0000, 0x0000, "resetVars" , "", false, false}, {0x0000, 0x0000, "absolute" , "", false, false}, {0x0000, 0x0000, "sign" , "", false, false}, {0x0000, 0x0000, "integerMin" , "", false, false}, {0x0000, 0x0000, "integerMax" , "", false, false}, {0x0000, 0x0000, "integerClamp" , "", false, false}, {0x0000, 0x0000, "power16bit" , "", false, false}, {0x0000, 0x0000, "power16bitExt" , "", false, false}, {0x0000, 0x0000, "multiply16bit" , "", false, false}, {0x0000, 0x0000, "multiply16bit_1" , "", false, false}, {0x0000, 0x0000, "divide16bit" , "", false, false}, {0x0000, 0x0000, "divide16bit_1" , "", false, false}, {0x0000, 0x0000, "rand16bit" , "", false, false}, {0x0000, 0x0000, "randMod16bit" , "", false, false}, {0x0000, 0x0000, "shiftLeft4bit" , "", false, false}, {0x0000, 0x0000, "shiftLeft8bit" , "", false, false}, {0x0000, 0x0000, "shiftRight1bit" , "", false, false}, {0x0000, 0x0000, "shiftRight2bit" , "", false, false}, {0x0000, 0x0000, "shiftRight3bit" , "", false, false}, {0x0000, 0x0000, "shiftRight4bit" , "", false, false}, {0x0000, 0x0000, "shiftRight5bit" , "", false, false}, {0x0000, 0x0000, "shiftRight6bit" , "", false, false}, {0x0000, 0x0000, "shiftRight7bit" , "", false, false}, {0x0000, 0x0000, "shiftRight8bit" , "", false, false}, {0x0000, 0x0000, "shiftRightSgn1bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn2bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn3bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn4bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn5bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn6bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn7bit", "", false, false}, {0x0000, 0x0000, "shiftRightSgn8bit", "", false, false}, {0x0000, 0x0000, "getArrayByte" , "", false, false}, {0x0000, 0x0000, "setArrayByte" , "", false, false}, {0x0000, 0x0000, "getArrayInt16" , "", false, false}, {0x0000, 0x0000, "setArrayInt16" , "", false, false}, {0x0000, 0x0000, "getArrayInt16Low" , "", false, false}, {0x0000, 0x0000, "setArrayInt16Low" , "", false, false}, {0x0000, 0x0000, "getArrayInt16High", "", false, false}, {0x0000, 0x0000, "setArrayInt16High", "", false, false}, {0x0000, 0x0000, "readIntVar" , "", false, false}, {0x0000, 0x0000, "readStrVar" , "", false, false}, {0x0000, 0x0000, "gotoNumericLabel" , "", false, false}, {0x0000, 0x0000, "gosubNumericLabel", "", false, false}, {0x0000, 0x0000, "scanlineMode" , "", false, false}, {0x0000, 0x0000, "waitVBlank" , "", false, false}, {0x0000, 0x0000, "waitVBlanks" , "", false, false}, {0x0000, 0x0000, "resetVideoFlags" , "", false, false}, {0x0000, 0x0000, "resetVideoTable" , "", false, false}, {0x0000, 0x0000, "initClearFuncs" , "", false, false}, {0x0000, 0x0000, "clearScreen" , "", false, false}, {0x0000, 0x0000, "clearRect" , "", false, false}, {0x0000, 0x0000, "clearLine" , "", false, false}, {0x0000, 0x0000, "clearVertBlinds" , "", false, false}, {0x0000, 0x0000, "clearCursorRow" , "", false, false}, {0x0000, 0x0000, "readPixel" , "", false, false}, {0x0000, 0x0000, "drawPixel" , "", false, false}, {0x0000, 0x0000, "drawHLine" , "", false, false}, {0x0000, 0x0000, "drawVLine" , "", false, false}, {0x0000, 0x0000, "drawLine" , "", false, false}, {0x0000, 0x0000, "drawLineExt" , "", false, false}, {0x0000, 0x0000, "drawLineLoop" , "", false, false}, {0x0000, 0x0000, "drawLineLoadXY" , "", false, false}, {0x0000, 0x0000, "drawLineSlow" , "", false, false}, {0x0000, 0x0000, "drawLineSlowExt" , "", false, false}, {0x0000, 0x0000, "drawLineSlowLoop" , "", false, false}, {0x0000, 0x0000, "drawLineSlowSwap" , "", false, false}, {0x0000, 0x0000, "drawVTLine" , "", false, false}, {0x0000, 0x0000, "drawVTLineExt" , "", false, false}, {0x0000, 0x0000, "drawVTLineLoop" , "", false, false}, {0x0000, 0x0000, "drawVTLineLoadXY" , "", false, false}, {0x0000, 0x0000, "drawCircle" , "", false, false}, {0x0000, 0x0000, "drawCircleExt1" , "", false, false}, {0x0000, 0x0000, "drawCircleExt2" , "", false, false}, {0x0000, 0x0000, "drawCircleF" , "", false, false}, {0x0000, 0x0000, "drawRect" , "", false, false}, {0x0000, 0x0000, "drawRectF" , "", false, false}, {0x0000, 0x0000, "drawPoly" , "", false, false}, {0x0000, 0x0000, "drawPolyRel" , "", false, false}, {0x0000, 0x0000, "setPolyRelFlipX" , "", false, false}, {0x0000, 0x0000, "setPolyRelFlipY" , "", false, false}, {0x0000, 0x0000, "atLineCursor" , "", false, false}, {0x0000, 0x0000, "drawSprite_" , "", false, false}, {0x0000, 0x0000, "drawSprite" , "", false, false}, {0x0000, 0x0000, "drawSpriteX" , "", false, false}, {0x0000, 0x0000, "drawSpriteY" , "", false, false}, {0x0000, 0x0000, "drawSpriteXY" , "", false, false}, {0x0000, 0x0000, "getSpriteLUT" , "", false, false}, {0x0000, 0x0000, "setMidiStream" , "", false, false}, {0x0000, 0x0000, "resetMidi" , "", false, false}, {0x0000, 0x0000, "playMidi" , "", false, false}, {0x0000, 0x0000, "playMidiVol" , "", false, false}, {0x0000, 0x0000, "midiStartNote" , "", false, false}, {0x0000, 0x0000, "midiGetNote" , "", false, false}, {0x0000, 0x0000, "resetMusic" , "", false, false}, {0x0000, 0x0000, "playMusic" , "", false, false}, {0x0000, 0x0000, "musicGetNote" , "", false, false}, {0x0000, 0x0000, "musicPlayNote" , "", false, false}, {0x0000, 0x0000, "soundAllOff" , "", false, false}, {0x0000, 0x0000, "soundOff" , "", false, false}, {0x0000, 0x0000, "soundOn" , "", false, false}, {0x0000, 0x0000, "soundOnV" , "", false, false}, {0x0000, 0x0000, "soundMod" , "", false, false}, {0x0000, 0x0000, "input" , "", false, false}, {0x0000, 0x0000, "inputExt1" , "", false, false}, {0x0000, 0x0000, "inputExt2" , "", false, false}, {0x0000, 0x0000, "inputCursor" , "", false, false}, {0x0000, 0x0000, "inputKeys" , "", false, false}, {0x0000, 0x0000, "inputIntVar" , "", false, false}, {0x0000, 0x0000, "inputStrVar" , "", false, false}, {0x0000, 0x0000, "inputReturn" , "", false, false}, {0x0000, 0x0000, "inputDelete" , "", false, false}, {0x0000, 0x0000, "inputPrint" , "", false, false}, {0x0000, 0x0000, "inputNewline" , "", false, false}, {0x0000, 0x0000, "printInit" , "", false, false}, {0x0000, 0x0000, "printText" , "", false, false}, {0x0000, 0x0000, "printLeft" , "", false, false}, {0x0000, 0x0000, "printRight" , "", false, false}, {0x0000, 0x0000, "printMid" , "", false, false}, {0x0000, 0x0000, "printLower" , "", false, false}, {0x0000, 0x0000, "printUpper" , "", false, false}, {0x0000, 0x0000, "printDigit" , "", false, false}, {0x0000, 0x0000, "printInt16" , "", false, false}, {0x0000, 0x0000, "printChr" , "", false, false}, {0x0000, 0x0000, "printChar" , "", false, false}, {0x0000, 0x0000, "printClip" , "", false, false}, {0x0000, 0x0000, "printHex" , "", false, false}, {0x0000, 0x0000, "printSpc" , "", false, false}, {0x0000, 0x0000, "atTextCursor" , "", false, false}, {0x0000, 0x0000, "newLineScroll" , "", false, false}, {0x0000, 0x0000, "integerStr" , "", false, false}, {0x0000, 0x0000, "stringChr" , "", false, false}, {0x0000, 0x0000, "stringSpc" , "", false, false}, {0x0000, 0x0000, "stringHex" , "", false, false}, {0x0000, 0x0000, "stringCopy" , "", false, false}, {0x0000, 0x0000, "stringCmp" , "", false, false}, {0x0000, 0x0000, "stringAdd" , "", false, false}, {0x0000, 0x0000, "stringConcat" , "", false, false}, {0x0000, 0x0000, "stringConcatLut" , "", false, false}, {0x0000, 0x0000, "stringLeft" , "", false, false}, {0x0000, 0x0000, "stringRight" , "", false, false}, {0x0000, 0x0000, "stringMid" , "", false, false}, {0x0000, 0x0000, "stringLower" , "", false, false}, {0x0000, 0x0000, "stringUpper" , "", false, false}, {0x0000, 0x0000, "stringDigit" , "", false, false}, {0x0000, 0x0000, "stringInt" , "", false, false}, {0x0000, 0x0000, "tickTime" , "", false, false}, {0x0000, 0x0000, "handleTime" , "", false, false}, {0x0000, 0x0000, "timeDigits" , "", false, false}, {0x0000, 0x0000, "timeString" , "", false, false}, {0x0000, 0x0000, "bcdAdd" , "", false, false}, {0x0000, 0x0000, "bcdSub" , "", false, false}, {0x0000, 0x0000, "bcdInt" , "", false, false}, {0x0000, 0x0000, "bcdDigits" , "", false, false}, {0x0000, 0x0000, "bcdCmp" , "", false, false}, {0x0000, 0x0000, "bcdCmpExt" , "", false, false}, {0x0000, 0x0000, "bcdCpy" , "", false, false}, }; std::vector _subIncludesROMv1 = { "math.i" , "memory.i" , "flow_control.i", "clear_screen.i", "conv_conds.i" , "graphics.i" , "audio.i" , "input.i" , "print_text.i" , "string.i" , "numeric.i" , "time.i" , }; std::vector _subIncludesROMv2 = { "math.i" , "memory.i" , "flow_control.i" , "clear_screen_ROMv2.i", "conv_conds.i" , "graphics_ROMv2.i" , "audio.i" , "input.i" , "print_text_ROMv2.i" , "string.i" , "numeric.i" , "time.i" , }; std::vector _subIncludesROMv3 = { "math.i" , "memory.i" , "flow_control.i" , "clear_screen_ROMv2.i", "conv_conds.i" , "graphics_ROMv2.i" , "sprite_ROMv3.i" , "audio.i" , "input.i" , "print_text_ROMv3.i" , "string.i" , "numeric.i" , "time.i" , }; std::vector _subIncludesROMv4 = { "math.i" , "memory.i" , "flow_control.i" , "clear_screen_ROMv2.i", "conv_conds.i" , "graphics_ROMv2.i" , "sprite_ROMv3.i" , "audio.i" , "input.i" , "print_text_ROMv3.i" , "numeric.i" , "time.i" , }; std::vector _subIncludesROMv5a = { "math_ROMv5a.i" , "memory_ROMv5a.i" , "flow_control_ROMv5a.i", "clear_screen_ROMv5a.i", "conv_conds_ROMv5a.i" , "graphics_ROMv5a.i" , "sprite_ROMv5a.i" , "audio_ROMv5a.i" , "input_ROMv5a.i" , "print_text_ROMv5a.i" , "string_ROMv5a.i" , "numeric_ROMv5a.i" , "time_ROMv5a.i" , }; bool getInternalSub(const std::string& name, Compiler::InternalSub& internalSub) { for(int i=0; i& tokens, const std::string& subName) { for(int i=0; i tokens = Expression::tokeniseLine(_subIncludeFiles[includeName][i]); for(int j=0; j= 2 && tokens[0] == "%SUB" && tokens[1] == subName) { buildingSub = true; } else if(buildingSub && tokens.size() >= 1 && tokens[0] == "%ENDS") { buildingSub = false; break; } else if(buildingSub) { for(int j=0; j& includeVarsDone, std::vector& code, int subIndex) { if(_subIncludeFiles.find(includeName) == _subIncludeFiles.end()) { fprintf(stderr, "Linker::getInternalSubCode() : Include file was never loaded : '%s'\n", includeName.c_str()); return false; } std::string subName = _internalSubs[subIndex]._name; // Check if include vars already done bool varsDone = false; for(int i=0; i tokens = Expression::tokenise(line, ' '); for(int j=0; j lineTokens; while(!infile.eof()) { std::string lineToken; std::getline(infile, lineToken); lineTokens.push_back(lineToken); if(!infile.good() && !infile.eof()) { fprintf(stderr, "Linker::loadInclude() : Bad lineToken : '%s' : in '%s' : on line %d\n", lineToken.c_str(), filename.c_str(), numLines+1); return false; } numLines++; } _subIncludeFiles[filename] = lineTokens; return true; } bool parseIncludes(void) { // Load include files into memory if(Compiler::getCodeRomType() >= Cpu::ROMv5a) { for(int i=0; i= Cpu::ROMv4) { for(int i=0; i= Cpu::ROMv3) { for(int i=0; i= Cpu::ROMv2) { for(int i=0; i= Cpu::ROMv5a) { for(int j=0; j= Cpu::ROMv4) { for(int j=0; j= Cpu::ROMv3) { for(int j=0; j= Cpu::ROMv2) { for(int j=0; j= Cpu::ROMv1) { for(int j=0; j= 2 && Compiler::getCodeLines()[i]._vasm.size()) { // Vasm code for(int j=0; j tokens = Expression::tokenise(Compiler::getCodeLines()[i]._vasm[j]._code, ' '); for(int k=0; k includeVarsDone; RESTART_COLLECTION: for(int i=0; i code; // This is a BASIC compiler, it can't possibly work without at least one GOTO if(getInternalSubCode(_internalSubs[i]._includeName, includeVarsDone, code, i)) goto RESTART_COLLECTION; includeVarsDone.push_back(_internalSubs[i]._includeName); for(int j=0; j internalSubs; std::copy(_internalSubMap.begin(), _internalSubMap.end(), std::back_inserter>(internalSubs)); // Sort vector, (prioritise by sub size) std::sort(internalSubs.begin(), internalSubs.end(), [](const SubIndexSize& a, const SubIndexSize& b) { if(a.second != b.second) return (a.second > b.second); return (a.first < b.first); }); // Allocate memory for runtime for(auto it=internalSubs.begin(); it!=internalSubs.end(); ++it) { uint16_t address; if(Memory::getNextCodeAddress(Memory::FitDescending, Compiler::getRuntimeStart(), _internalSubs[it->first]._size, address)) { Memory::takeFreeRAM(address, _internalSubs[it->first]._size, true); // Save end of runtime/strings if(address < Compiler::getRuntimeEnd()) Compiler::setRuntimeEnd(address); fprintf(stderr, "* %-20s : 0x%04x : %2d bytes\n", _internalSubs[it->first]._name.c_str(), address, _internalSubs[it->first]._size); _internalSubs[it->first]._address = address; } } fprintf(stderr, "*******************************************************\n"); fprintf(stderr, "* Re-Linking \n"); fprintf(stderr, "*******************************************************\n"); fprintf(stderr, "* Start : End : Size \n"); fprintf(stderr, "*******************************************************\n"); fprintf(stderr, "* 0x%04x : 0x%04x : %5d bytes \n", Compiler::getRuntimeStart() & (Memory::getSizeRAM() - 1), Compiler::getRuntimeEnd(), runtimeSize); fprintf(stderr, "*******************************************************\n"); } void outputInternalSubs(void) { Compiler::getOutput().push_back("\n"); Compiler::getOutput().push_back(";****************************************************************************************************************************************\n"); Compiler::getOutput().push_back(";****************************************************************************************************************************************\n"); Compiler::getOutput().push_back(";* Internal runtime, DO NOT MODIFY PAST THIS POINT, modifications must be made in the original include files *\n"); Compiler::getOutput().push_back(";****************************************************************************************************************************************\n"); Compiler::getOutput().push_back(";****************************************************************************************************************************************\n"); Compiler::getOutput().push_back("\n"); for(int i=0; i