Пример #1
0
        /// <summary>
        /// Outputs formatted data in an unformatted way, because the code generator couldn't
        /// figure out how to do something better.
        /// </summary>
        private void OutputNoJoy(int offset, int length, string labelStr, string commentStr)
        {
            byte[] data = Project.FileData;
            Debug.Assert(length > 0);
            Debug.Assert(offset >= 0 && offset < data.Length);

            bool singleValue = true;
            byte val         = data[offset];

            for (int i = 1; i < length; i++)
            {
                if (data[offset + i] != val)
                {
                    singleValue = false;
                    break;
                }
            }

            if (singleValue && length > 1)
            {
                string opcodeStr  = SourceFormatter.FormatPseudoOp(sDataOpNames.Fill);
                string operandStr = length + "," + SourceFormatter.FormatHexValue(val, 2);
                OutputLine(labelStr, opcodeStr, operandStr, commentStr);
            }
            else
            {
                OutputDenseHex(offset, length, labelStr, commentStr);
            }
        }
Пример #2
0
 // IGenerator
 public void OutputOrgDirective(int offset, int address)
 {
     // 64tass separates the "compile offset", which determines where the output fits
     // into the generated binary, and "program counter", which determines the code
     // the assembler generates.  Since we need to explicitly specify every byte in
     // the output file, the compile offset isn't very useful.  We want to set it once
     // before the first line of code, then leave it alone.
     //
     // Any subsequent ORG changes are made to the program counter, and take the form
     // of a pair of ops (.logical <addr> to open, .here to end).  Omitting the .here
     // causes an error.
     if (offset == 0)
     {
         // Set the "compile offset" to the initial address.
         OutputLine("*", "=", SourceFormatter.FormatHexValue(Project.AddrMap.Get(0), 4),
                    string.Empty);
     }
     else
     {
         if (mNeedHereOp)
         {
             OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(HERE_PSEUDO_OP),
                        string.Empty, string.Empty);
         }
         OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
                    SourceFormatter.FormatHexValue(address, 4), string.Empty);
         mNeedHereOp = true;
     }
 }
Пример #3
0
        // IGenerator
        public void OutputOrgDirective(int offset, int address)
        {
            // If there's only one address range, just set the "real" PC.  If there's more
            // than one we can run out of space if the source file has a chunk in high memory
            // followed by a chunk in low memory, because the "real" PC determines when the
            // 64KB bank is overrun.
            if (offset == 0)
            {
                // first one
                if (Project.AddrMap.Count == 1)
                {
                    OutputLine("*", "=", SourceFormatter.FormatHexValue(address, 4), string.Empty);
                    return;
                }
                else
                {
                    // set the real PC to address zero to ensure we get a full 64KB
                    OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
                }
            }

            if (mInPseudoPcBlock)
            {
                // close previous block
                OutputLine(string.Empty, CLOSE_PSEUDOPC, string.Empty, string.Empty);
            }
            OutputLine(string.Empty, sDataOpNames.OrgDirective,
                       SourceFormatter.FormatHexValue(address, 4) + " {", string.Empty);
            mInPseudoPcBlock = true;
        }
Пример #4
0
        // IGenerator
        public void OutputOrgDirective(int offset, int address)
        {
            // Linear search for offset.  List should be small, so this should be quick.
            int index = 0;

            foreach (AddressMap.AddressMapEntry ame in Project.AddrMap)
            {
                if (ame.Offset == offset)
                {
                    break;
                }
                index++;
            }

            mLineBuilder.Clear();
            TextUtil.AppendPaddedString(mLineBuilder, ";", 0);
            // using +1 to make it look like the comment ';' shifted it over
            TextUtil.AppendPaddedString(mLineBuilder, SourceFormatter.FormatPseudoOp(".segment"),
                                        mColumnWidths[0] + 1);
            TextUtil.AppendPaddedString(mLineBuilder, string.Format("\"SEG{0:D3}\"", index),
                                        mColumnWidths[0] + mColumnWidths[1] + 1);
            OutputLine(mLineBuilder.ToString());

            OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
                       SourceFormatter.FormatHexValue(address, 4), string.Empty);
        }
Пример #5
0
 // IGenerator
 public void FlushArDirectives()
 {
     // Output pending directives.  There will always be something to do here unless
     // we were in "relative" mode.
     Debug.Assert(mNextAddress >= 0 || mIsInRelative);
     if (mNextAddress >= 0)
     {
         OutputLine(string.Empty,
                    SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
                    SourceFormatter.FormatHexValue(mNextAddress, 4),
                    string.Empty);
     }
     mNextAddress  = -1;
     mIsInRelative = false;
 }
Пример #6
0
        // IGenerator
        public void GenerateShortSequence(int offset, int length, out string opcode,
                                          out string operand)
        {
            Debug.Assert(length >= 1 && length <= 4);

            // Use a comma-separated list of individual hex bytes.
            opcode = sDataOpNames.DefineData1;

            StringBuilder sb = new StringBuilder(length * 4);

            for (int i = 0; i < length; i++)
            {
                if (i != 0)
                {
                    sb.Append(',');
                }
                sb.Append(SourceFormatter.FormatHexValue(Project.FileData[offset + i], 2));
            }
            operand = sb.ToString();
        }
Пример #7
0
 // IGenerator
 public void OutputOrgDirective(int offset, int address)
 {
     // For the first one, set the "real" PC.  For all subsequent directives, set the
     // "pseudo" PC.
     if (offset == 0)
     {
         OutputLine("*", "=", SourceFormatter.FormatHexValue(address, 4), string.Empty);
     }
     else
     {
         if (mInPseudoPcBlock)
         {
             // close previous block
             OutputLine(string.Empty, CLOSE_PSEUDOPC, string.Empty, string.Empty);
         }
         OutputLine(string.Empty, sDataOpNames.OrgDirective,
                    SourceFormatter.FormatHexValue(address, 4) + " {", string.Empty);
         mInPseudoPcBlock = true;
     }
 }
Пример #8
0
        // IGenerator
        public void OutputArDirective(CommonUtil.AddressMap.AddressChange change)
        {
            // This is similar in operation to the AsmTass64 implementation.  See comments there.
            Debug.Assert(mPcDepth >= 0);
            int nextAddress = change.Address;

            if (nextAddress == Address.NON_ADDR)
            {
                // Start non-addressable regions at zero to ensure they don't overflow bank.
                nextAddress = 0;
            }
            if (change.IsStart)
            {
                if (change.Region.HasValidPreLabel)
                {
                    string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
                    OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
                }
                if (mPcDepth == 0 && mFirstIsOpen)
                {
                    mPcDepth++;

                    // Set the "real" PC for the first address change.  If we're in "loadable"
                    // mode, just set "*=".  If we're in "streaming" mode, we set "*=" to zero
                    // and then use a pseudo-PC.
                    if (mOutputMode == OutputMode.Loadable)
                    {
                        OutputLine("*", "=", SourceFormatter.FormatHexValue(nextAddress, 4),
                                   string.Empty);
                        return;
                    }
                    else
                    {
                        // set the real PC to address zero to ensure we get a full 64KB
                        OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
                    }
                }
                AddressMap.AddressRegion region = change.Region;
                string addrStr;
                if (region.HasValidIsRelative)
                {
                    int    diff = nextAddress - region.PreLabelAddress;
                    string pfxStr;
                    if (diff >= 0)
                    {
                        pfxStr = "*+";
                    }
                    else
                    {
                        pfxStr = "*-";
                        diff   = -diff;
                    }
                    addrStr = pfxStr + SourceFormatter.FormatHexValue(diff, 4);
                }
                else
                {
                    addrStr = SourceFormatter.FormatHexValue(nextAddress, 4);
                }
                OutputLine(string.Empty,
                           SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
                           addrStr + " {",
                           string.Empty);
                mPcDepth++;
            }
            else
            {
                mPcDepth--;
                if (mPcDepth > 0 || !mFirstIsOpen)
                {
                    // close previous block
                    OutputLine(string.Empty,
                               SourceFormatter.FormatPseudoOp(sDataOpNames.ArEndDirective),
                               string.Empty, string.Empty);
                    //";" + SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective));
                }
                else
                {
                    // mark initial "*=" region as closed, but don't output anything
                    mFirstIsOpen = false;
                }
            }
        }
Пример #9
0
 // IGenerator
 public void OutputOrgDirective(int address)
 {
     OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
                SourceFormatter.FormatHexValue(address, 4), string.Empty);
 }
Пример #10
0
        // IGenerator
        public void OutputArDirective(CommonUtil.AddressMap.AddressChange change)
        {
            // 64tass separates the "compile offset", which determines where the output fits
            // into the generated binary, and "program counter", which determines the code
            // the assembler generates.  Since we need to explicitly specify every byte in
            // the output file, having a distinct compile offset isn't useful here.  We want
            // to set it once before the first line of code, then leave it alone.
            //
            // Any subsequent ORG changes are made to the program counter, and take the form
            // of a pair of ops (".logical <addr>" to open, ".here" to end).  Omitting the .here
            // causes an error.
            //
            // If this is a "streamable" file, meaning it won't actually load into 64K of RAM
            // without wrapping around, then we skip the "* = addr" (same as "* = 0") and just
            // start with ".logical" segments.
            //
            // The assembler's approach is best represented by having an address region that
            // spans the entire file, with one or more "logical" regions inside.  In practice
            // (especially for multi-bank 65816 code) that may not be the case, but the
            // assembler is still expecting us to start with a "* =" and then fit everything
            // inside that.  So we treat the first region specially, whether or not it wraps
            // the rest of the file.
            Debug.Assert(mPcDepth >= 0);
            int nextAddress = change.Address;

            if (nextAddress == Address.NON_ADDR)
            {
                // Start non-addressable regions at zero to ensure they don't overflow bank.
                nextAddress = 0;
            }
            if (change.IsStart)
            {
                if (change.Region.HasValidPreLabel)
                {
                    string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
                    OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
                }
                if (mPcDepth == 0 && mFirstIsOpen)
                {
                    mPcDepth++;

                    // Set the "real" PC for the first address change.  If we're in "loadable"
                    // mode, just set "*=".  If we're in "streaming" mode, we set "*=" to zero
                    // and then use a pseudo-PC.
                    if (mOutputMode == OutputMode.Loadable)
                    {
                        OutputLine("*", "=",
                                   SourceFormatter.FormatHexValue(nextAddress, 4), string.Empty);
                        return;
                    }
                    else
                    {
                        // Set the real PC to address zero to ensure we get a full 64KB.  The
                        // assembler assumes this as a default, so it can be omitted.
                        //OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
                    }
                }

                AddressMap.AddressRegion region = change.Region;
                string addrStr;
                if (region.HasValidIsRelative)
                {
                    int    diff = nextAddress - region.PreLabelAddress;
                    string pfxStr;
                    if (diff >= 0)
                    {
                        pfxStr = "*+";
                    }
                    else
                    {
                        pfxStr = "*-";
                        diff   = -diff;
                    }
                    addrStr = pfxStr + SourceFormatter.FormatHexValue(diff, 4);
                }
                else
                {
                    addrStr = SourceFormatter.FormatHexValue(nextAddress, 4);
                }
                OutputLine(string.Empty,
                           SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
                           addrStr,
                           string.Empty);
                mPcDepth++;
            }
            else
            {
                mPcDepth--;
                if (mPcDepth > 0 || !mFirstIsOpen)
                {
                    // close previous block
                    OutputLine(string.Empty,
                               SourceFormatter.FormatPseudoOp(sDataOpNames.ArEndDirective),
                               string.Empty, string.Empty);
                }
                else
                {
                    // mark initial "*=" region as closed, but don't output anything
                    mFirstIsOpen = false;
                }
            }
        }
Пример #11
0
        // IGenerator
        public void OutputArDirective(CommonUtil.AddressMap.AddressChange change)
        {
            int nextAddress = change.Address;

            if (nextAddress == Address.NON_ADDR)
            {
                // Start non-addressable regions at zero to ensure they don't overflow bank.
                nextAddress = 0;
            }

            if (change.IsStart)
            {
                AddressMap.AddressRegion region = change.Region;
                if (region.HasValidPreLabel || region.HasValidIsRelative)
                {
                    // Need to output the previous ORG, if one is pending.
                    if (mNextAddress >= 0)
                    {
                        OutputLine(string.Empty,
                                   SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
                                   SourceFormatter.FormatHexValue(mNextAddress, 4),
                                   string.Empty);
                    }
                }
                if (region.HasValidPreLabel)
                {
                    string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
                    OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
                }
                if (region.HasValidIsRelative)
                {
                    // Found a valid IsRelative.  Switch to "relative mode" if not there already.
                    mIsInRelative = true;
                }
                if (mIsInRelative)
                {
                    // Once we see a region with IsRelative set, we output regions as we
                    // find them until the next Flush.
                    string addrStr;
                    if (region.HasValidIsRelative)
                    {
                        int    diff = nextAddress - region.PreLabelAddress;
                        string pfxStr;
                        if (diff >= 0)
                        {
                            pfxStr = "*+";
                        }
                        else
                        {
                            pfxStr = "*-";
                            diff   = -diff;
                        }
                        addrStr = pfxStr + SourceFormatter.FormatHexValue(diff, 4);
                    }
                    else
                    {
                        addrStr = SourceFormatter.FormatHexValue(nextAddress, 4);
                    }
                    OutputLine(string.Empty,
                               SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
                               addrStr, string.Empty);

                    mNextAddress = -1;
                    return;
                }
            }

            mNextAddress = nextAddress;
        }