?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. /*
  2.  
  3.   SjASMPlus Z80 Cross Compiler - modified - RELOCATE extension
  4.  
  5.   Copyright (c) 2006 Sjoerd Mastijn (original SW)
  6.   Copyright (c) 2020 Peter Ped Helcmanovsky (RELOCATE extension)
  7.  
  8.   This software is provided 'as-is', without any express or implied warranty.
  9.   In no event will the authors be held liable for any damages arising from the
  10.   use of this software.
  11.  
  12.   Permission is granted to anyone to use this software for any purpose,
  13.   including commercial applications, and to alter it and redistribute it freely,
  14.   subject to the following restrictions:
  15.  
  16.   1. The origin of this software must not be misrepresented; you must not claim
  17.          that you wrote the original software. If you use this software in a product,
  18.          an acknowledgment in the product documentation would be appreciated but is
  19.          not required.
  20.  
  21.   2. Altered source versions must be plainly marked as such, and must not be
  22.          misrepresented as being the original software.
  23.  
  24.   3. This notice may not be removed or altered from any source distribution.
  25.  
  26. */
  27.  
  28. // relocate.cpp
  29.  
  30. #include "sjdefs.h"
  31.  
  32. // local implementation stuff (shouldn't be visible through the header)
  33. namespace Relocation {
  34.         // when some part of opcode needs relocation, add its offset to the relocation table
  35.         static void addOffsetToRelocate(const aint offset);
  36.  
  37.         static void refreshMaxTableCount();
  38.  
  39.         // local implementation specific data
  40.         static constexpr aint ALTERNATIVE_OFFSET_WORD = +0x0272;        // must have at least one bit set in low three due to how some tests are written
  41.         static constexpr aint ALTERNATIVE_OFFSET_HIGH = +0x0300;
  42.         static TextFilePos startPos;                            // sourcefile position of last correct RELOCATE_START
  43.         static size_t maxTableCount = 0;                        // maximum count of relocation data
  44.         static std::vector<word> offsets;                       // offsets collected during current pass
  45.         static std::vector<word> offsetsPrevious;       // offsets from pass2 (to be exported if pass3 is incomplete)
  46.         static bool warnAboutContentChange = false;     // if any change in content between passes should be reported
  47.  
  48.         // public API variables
  49.         aint alternative_offset = 0;    // offset to add to label value when evaluating alternatives
  50.         EType type = OFF;                               // type of relocation block when inside
  51.         bool areLabelsOffset = false;   // when the Labels should return the alternative value
  52.         bool isResultAffected = false;  // when one of previous expression results was affected by it
  53.         EType deltaType = OFF;                  // when isResultAffected && difference was precisely "+offset" or "+(offset>>8)"
  54. }
  55.  
  56. // when some part of opcode needs relocation, add its offset to the relocation table
  57. static void Relocation::addOffsetToRelocate(const aint offset) {
  58.         // if table was already emitted from previous pass copy, warn about value discrepancies
  59.         if (warnAboutContentChange) {
  60.                 const size_t newIndex = offsets.size();
  61.                 if (offsetsPrevious.size() <= newIndex || offsetsPrevious[newIndex] != offset) {
  62.                         Warning("Relocation table seems internally inconsistent", "table content differs in last pass");
  63.                         warnAboutContentChange = false;
  64.                 }
  65.         }
  66.         // add new offset to the relocation table
  67.         offsets.push_back(offset);
  68. }
  69.  
  70. void Relocation::resolveRelocationAffected(const aint opcodeRelOffset, EType minType) {
  71.         if (type < minType) return;
  72.         if (!isResultAffected) return;
  73.         isResultAffected = false;                               // mark as processed
  74.         if (minType <= deltaType) {
  75.                 if (INT_MAX == opcodeRelOffset) return;
  76.                 const aint address = (DISP_INSIDE_RELOCATE == PseudoORG) ? adrdisp : CurAddress;
  77.                 addOffsetToRelocate(address + opcodeRelOffset + type - deltaType);
  78.                 return;
  79.         }
  80.         // difference is not fixable by simple "+offset" relocator or in current mode
  81.         WarningById(deltaType ? W_REL_UNSTABLE : W_REL_DIVERTS);
  82. }
  83.  
  84. bool Relocation::checkAndWarn(bool doError) {
  85.         // if nothing is affected by relocation, do nothing here
  86.         if (!Relocation::isResultAffected) return false;
  87.         // some result did set the "affected" flag, warn about it
  88.         Relocation::isResultAffected = false;
  89.         if (doError) {
  90.                 Error("Relocation makes one of the expressions unstable, use non-relocatable values only");
  91.         } else {
  92.                 WarningById(W_REL_UNSTABLE);
  93.         }
  94.         return true;
  95. }
  96.  
  97. // directives implementation
  98.  
  99. static void Relocation::refreshMaxTableCount() {
  100.         if (maxTableCount < offsets.size()) {
  101.                 maxTableCount = offsets.size();
  102.         }
  103.         // add the relocate_count and relocate_size symbols only when RELOCATE feature was used
  104.         if (type || maxTableCount) {
  105.                 isResultAffected = false;
  106.                 deltaType = OFF;
  107.                 LabelTable.Insert("relocate_count", maxTableCount, LABEL_IS_DEFL);
  108.                 LabelTable.Insert("relocate_size", maxTableCount * 2, LABEL_IS_DEFL);
  109.         }
  110. }
  111.  
  112. void Relocation::dirRELOCATE_START() {
  113.         bool isHigh = !SkipBlanks(lp) && cmphstr(lp, "high");
  114.         if (type) {
  115.                 sourcePosStack.push_back(startPos);
  116.                 Error("Relocation block already started here");
  117.                 sourcePosStack.pop_back();
  118.                 return;
  119.         }
  120.         const aint new_offset = isHigh ? ALTERNATIVE_OFFSET_HIGH : ALTERNATIVE_OFFSET_WORD;
  121.         if (alternative_offset && alternative_offset != new_offset) {
  122.                 Error("HIGH mode can't be mixed with regular mode");
  123.                 return;
  124.         }
  125.         alternative_offset = new_offset;
  126.         type = isHigh ? HIGH : REGULAR;
  127.         assert(!sourcePosStack.empty());
  128.         startPos = sourcePosStack.back();
  129.         refreshMaxTableCount();
  130. }
  131.  
  132. void Relocation::dirRELOCATE_END() {
  133.         if (!type) {
  134.                 Error("Relocation block start for this end is missing");
  135.                 return;
  136.         }
  137.         if (DISP_INSIDE_RELOCATE == PseudoORG) {
  138.                 Error("End the current DISP block first");
  139.                 return;
  140.         }
  141.         type = OFF;
  142.         refreshMaxTableCount();
  143. }
  144.  
  145. void Relocation::dirRELOCATE_TABLE() {
  146.         aint subtract_offset = 0;
  147.         if (!SkipBlanks(lp)) {  // should be either empty remaining of line, or <subtract_offset>
  148.                 if (!ParseExpressionNoSyntaxError(lp, subtract_offset)) {
  149.                         Error("[RELOCATE_TABLE] Syntax error in <subtract_offset>", bp, SUPPRESS);
  150.                         return;
  151.                 }
  152.         }
  153.         refreshMaxTableCount();
  154.         // dump the table into machine code output
  155.         for (size_t offsetIndex = 0; offsetIndex < maxTableCount; ++offsetIndex) {
  156.                 // select offset from current pass table if possible, but use "offsetsPrevious" as backup
  157.                 const auto offset = (offsetIndex < offsets.size()) ? offsets[offsetIndex] : offsetsPrevious[offsetIndex];
  158.                 EmitWord(offset - subtract_offset);
  159.         }
  160.         warnAboutContentChange = (LASTPASS == pass);    // set in last pass to check consistency
  161. }
  162.  
  163. void Relocation::InitPass() {
  164.         // check if the relocation block is still open (missing RELOCATION_END in source)
  165.         if (type) {
  166.                 sourcePosStack.push_back(startPos);
  167.                 Error("Missing end of relocation block started here");
  168.                 sourcePosStack.pop_back();
  169.         }
  170.         // keep copy of final offsets table from previous pass
  171.         offsetsPrevious = offsets;
  172.         // set the final count as the new maximum count (doesn't matter if it is smaller/bigger than old)
  173.         maxTableCount = offsets.size();
  174.         // clear the table for next pass and init the state
  175.         offsets.clear();
  176.         type = OFF;
  177. }
  178.  
  179. //eof relocate.cpp
  180.