Esempio n. 1
0
        // IGenerator
        public void OutputDataOp(int offset)
        {
            Formatter formatter = SourceFormatter;

            byte[]   data = Project.FileData;
            Anattrib attr = Project.GetAnattrib(offset);

            string labelStr = string.Empty;

            if (attr.Symbol != null)
            {
                labelStr = mLocalizer.ConvLabel(attr.Symbol.Label);
            }

            string commentStr = SourceFormatter.FormatEolComment(Project.Comments[offset]);
            string opcodeStr, operandStr;

            FormatDescriptor dfd = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            int length = dfd.Length;

            Debug.Assert(length > 0);

            bool multiLine = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.Default:
                if (length != 1)
                {
                    Debug.Assert(false);
                    length = 1;
                }
                opcodeStr = sDataOpNames.DefineData1;
                int operand = RawData.GetWord(data, offset, length, false);
                operandStr = formatter.FormatHexValue(operand, length * 2);
                break;

            case FormatDescriptor.Type.NumericLE:
                opcodeStr  = sDataOpNames.GetDefineData(length);
                operand    = RawData.GetWord(data, offset, length, false);
                operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                           mLocalizer.LabelMap, dfd, operand, length,
                                                           PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                break;

            case FormatDescriptor.Type.NumericBE:
                opcodeStr = sDataOpNames.GetDefineBigData(length);
                if ((string.IsNullOrEmpty(opcodeStr)))
                {
                    // Nothing defined, output as comma-separated single-byte values.
                    GenerateShortSequence(offset, length, out opcodeStr, out operandStr);
                }
                else
                {
                    operand    = RawData.GetWord(data, offset, length, true);
                    operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                               mLocalizer.LabelMap, dfd, operand, length,
                                                               PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                }
                break;

            case FormatDescriptor.Type.Fill:
                opcodeStr  = sDataOpNames.Fill;
                operandStr = length + "," + formatter.FormatHexValue(data[offset], 2);
                break;

            case FormatDescriptor.Type.Dense:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputDenseHex(offset, length, labelStr, commentStr);
                break;

            case FormatDescriptor.Type.Uninit:
            case FormatDescriptor.Type.Junk:
                // The ca65 .align directive has a dependency on the alignment of the
                // segment as a whole.  We're not currently declaring multiple segments,
                // so we can't use .align without generating complaints.
                int fillVal = Helper.CheckRangeHoldsSingleValue(data, offset, length);
                if (fillVal >= 0 && (length > 1 || fillVal == 0x00))
                {
                    // If multi-byte, or single byte and zero, treat same as Fill.
                    opcodeStr  = sDataOpNames.Fill;
                    operandStr = length + "," + formatter.FormatHexValue(fillVal, 2);
                }
                else
                {
                    // treat same as Dense
                    multiLine = true;
                    opcodeStr = operandStr = null;
                    OutputDenseHex(offset, length, labelStr, commentStr);
                }
                break;

            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringNullTerm:
            case FormatDescriptor.Type.StringL8:
            case FormatDescriptor.Type.StringL16:
            case FormatDescriptor.Type.StringDci:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputString(offset, labelStr, commentStr);
                break;

            default:
                opcodeStr  = "???";
                operandStr = "***";
                break;
            }

            if (!multiLine)
            {
                opcodeStr = formatter.FormatPseudoOp(opcodeStr);
                OutputLine(labelStr, opcodeStr, operandStr, commentStr);
            }
        }
Esempio n. 2
0
        private void OutputString(int offset, string labelStr, string commentStr)
        {
            // Normal ASCII strings are straightforward: they're just part of a .byte
            // directive, and can mix with anything else in the .byte.
            //
            // For CString we can use .asciiz, but only if the string fits on one line
            // and doesn't include delimiters.  For L8String and L16String we can
            // define simple macros, but their use has a similar restriction.  High-ASCII
            // strings also require a macro.
            //
            // We might be able to define a macro for DCI and Reverse as well.
            //
            // The limitation on strings with delimiters arises because (1) I don't see a
            // way to escape them within a string, and (2) the simple macro workarounds
            // only take a single argument, not a comma-separated list of stuff.
            //
            // Some ideas here:
            // https://groups.google.com/forum/#!topic/comp.sys.apple2.programmer/5Wkw8mUPcU0

            Anattrib         attr = Project.GetAnattrib(offset);
            FormatDescriptor dfd  = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            Debug.Assert(dfd.IsString);
            Debug.Assert(dfd.Length > 0);

            CharEncoding.Convert charConv;
            bool isHighAscii = false;

            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.Ascii:
                charConv = CharEncoding.ConvertAscii;
                break;

            case FormatDescriptor.SubType.HighAscii:
                if (dfd.FormatType != FormatDescriptor.Type.StringGeneric)
                {
                    OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                    return;
                }
                charConv    = CharEncoding.ConvertHighAscii;
                isHighAscii = true;
                break;

            case FormatDescriptor.SubType.C64Petscii:
            case FormatDescriptor.SubType.C64Screen:
            default:
                OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                return;
            }

            Formatter formatter = SourceFormatter;

            byte[] data          = Project.FileData;
            int    leadingBytes  = 0;
            int    trailingBytes = 0;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringDci:
                break;

            case FormatDescriptor.Type.StringNullTerm:
                trailingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL8:
                leadingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL16:
                leadingBytes = 2;
                break;

            default:
                Debug.Assert(false);
                return;
            }

            StringOpFormatter stropf = new StringOpFormatter(SourceFormatter,
                                                             Formatter.DOUBLE_QUOTE_DELIM, StringOpFormatter.RawOutputStyle.CommaSep, charConv,
                                                             false);

            stropf.FeedBytes(data, offset, dfd.Length - trailingBytes, leadingBytes,
                             StringOpFormatter.ReverseMode.Forward);

            string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric);

            if (isHighAscii)
            {
                // Does this fit the narrow definition of what we can do with a macro?
                Debug.Assert(dfd.FormatType == FormatDescriptor.Type.StringGeneric);
                if (stropf.Lines.Count == 1 && !stropf.HasEscapedText)
                {
                    if (!mHighAsciiMacroOutput)
                    {
                        mHighAsciiMacroOutput = true;
                        // Output a macro for high-ASCII strings.
                        //
                        // TODO(maybe): the preferred way to do this is apparently
                        // ".macpack apple2" to load some standard macros, then e.g.
                        // scrcode "My high-ASCII string".  The macro takes 9 arguments and
                        // recognizes characters and numbers, so it should be possible to
                        // mix strings, string delimiters, and control chars so long as the
                        // argument count is not exceeded.
                        OutputLine(".macro", "HiAscii", "Arg", string.Empty);
                        OutputLine(string.Empty, ".repeat", ".strlen(Arg), I", string.Empty);
                        OutputLine(string.Empty, ".byte", ".strat(Arg, I) | $80", string.Empty);
                        OutputLine(string.Empty, ".endrep", string.Empty, string.Empty);
                        OutputLine(".endmacro", string.Empty, string.Empty, string.Empty);
                    }
                    opcodeStr = formatter.FormatPseudoOp("HiAscii");
                }
                else
                {
                    // didn't work out, dump hex
                    OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                    return;
                }
            }

            if (dfd.FormatType == FormatDescriptor.Type.StringNullTerm)
            {
                if (stropf.Lines.Count == 1 && !stropf.HasEscapedText)
                {
                    // Keep it.
                    opcodeStr = sDataOpNames.StrNullTerm;
                }
                else
                {
                    // Didn't fit, so re-emit it, this time with the terminating null byte.
                    stropf.Reset();
                    stropf.FeedBytes(data, offset, dfd.Length, leadingBytes,
                                     StringOpFormatter.ReverseMode.Forward);
                }
            }

            foreach (string str in stropf.Lines)
            {
                OutputLine(labelStr, opcodeStr, str, commentStr);
                labelStr = commentStr = string.Empty;       // only show on first
            }
        }
Esempio n. 3
0
        private static void GenerateInstruction(IGenerator gen, StreamWriter sw, int offset,
                                                int instrBytes, bool doAddCycles)
        {
            DisasmProject proj      = gen.Project;
            Formatter     formatter = gen.SourceFormatter;

            byte[]   data = proj.FileData;
            Anattrib attr = proj.GetAnattrib(offset);

            string labelStr = string.Empty;

            if (attr.Symbol != null)
            {
                labelStr = gen.Localizer.ConvLabel(attr.Symbol.Label);
            }

            OpDef op       = proj.CpuDef.GetOpDef(data[offset]);
            int   operand  = op.GetOperand(data, offset, attr.StatusFlags);
            int   instrLen = op.GetLength(attr.StatusFlags);

            OpDef.WidthDisambiguation wdis = OpDef.WidthDisambiguation.None;
            if (op.IsWidthPotentiallyAmbiguous)
            {
                wdis = OpDef.GetWidthDisambiguation(instrLen, operand);
            }
            if (gen.Quirks.SinglePassAssembler && wdis == OpDef.WidthDisambiguation.None &&
                (op.AddrMode == OpDef.AddressMode.DP ||
                 op.AddrMode == OpDef.AddressMode.DPIndexX) ||
                op.AddrMode == OpDef.AddressMode.DPIndexY)
            {
                // Could be a forward reference to a direct-page label.
                if (IsForwardLabelReference(gen, offset))
                {
                    wdis = OpDef.WidthDisambiguation.ForceDirect;
                }
            }

            string opcodeStr = formatter.FormatOpcode(op, wdis);

            string formattedOperand = null;
            int    operandLen       = instrLen - 1;

            PseudoOp.FormatNumericOpFlags opFlags = PseudoOp.FormatNumericOpFlags.None;
            bool isPcRelBankWrap = false;

            // Tweak branch instructions.  We want to show the absolute address rather
            // than the relative offset (which happens with the OperandAddress assignment
            // below), and 1-byte branches should always appear as a 4-byte hex value.
            if (op.AddrMode == OpDef.AddressMode.PCRel)
            {
                Debug.Assert(attr.OperandAddress >= 0);
                operandLen = 2;
                opFlags    = PseudoOp.FormatNumericOpFlags.IsPcRel;
            }
            else if (op.AddrMode == OpDef.AddressMode.PCRelLong ||
                     op.AddrMode == OpDef.AddressMode.StackPCRelLong)
            {
                opFlags = PseudoOp.FormatNumericOpFlags.IsPcRel;
            }
            else if (op.AddrMode == OpDef.AddressMode.Imm ||
                     op.AddrMode == OpDef.AddressMode.ImmLongA ||
                     op.AddrMode == OpDef.AddressMode.ImmLongXY)
            {
                opFlags = PseudoOp.FormatNumericOpFlags.HasHashPrefix;
            }
            if (opFlags == PseudoOp.FormatNumericOpFlags.IsPcRel)
            {
                int branchDist = attr.Address - attr.OperandAddress;
                isPcRelBankWrap = branchDist > 32767 || branchDist < -32768;
            }

            // 16-bit operands outside bank 0 need to include the bank when computing
            // symbol adjustment.
            int operandForSymbol = operand;

            if (attr.OperandAddress >= 0)
            {
                operandForSymbol = attr.OperandAddress;
            }

            // Check Length to watch for bogus descriptors.  (ApplyFormatDescriptors() should
            // now be screening bad descriptors out, so we may not need the Length test.)
            if (attr.DataDescriptor != null && attr.Length == attr.DataDescriptor.Length)
            {
                // Format operand as directed.
                if (op.AddrMode == OpDef.AddressMode.BlockMove)
                {
                    // Special handling for the double-operand block move.
                    string opstr1 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                  gen.Localizer.LabelMap, attr.DataDescriptor, operand >> 8, 1,
                                                                  PseudoOp.FormatNumericOpFlags.None);
                    string opstr2 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                  gen.Localizer.LabelMap, attr.DataDescriptor, operand & 0xff, 1,
                                                                  PseudoOp.FormatNumericOpFlags.None);
                    if (gen.Quirks.BlockMoveArgsReversed)
                    {
                        string tmp = opstr1;
                        opstr1 = opstr2;
                        opstr2 = tmp;
                    }
                    formattedOperand = opstr1 + "," + opstr2;
                }
                else
                {
                    formattedOperand = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                     gen.Localizer.LabelMap, attr.DataDescriptor,
                                                                     operandForSymbol, operandLen, opFlags);
                }
            }
            else
            {
                // Show operand value in hex.
                if (op.AddrMode == OpDef.AddressMode.BlockMove)
                {
                    int arg1, arg2;
                    if (gen.Quirks.BlockMoveArgsReversed)
                    {
                        arg1 = operand & 0xff;
                        arg2 = operand >> 8;
                    }
                    else
                    {
                        arg1 = operand >> 8;
                        arg2 = operand & 0xff;
                    }
                    formattedOperand = formatter.FormatHexValue(arg1, 2) + "," +
                                       formatter.FormatHexValue(arg2, 2);
                }
                else
                {
                    if (operandLen == 2)
                    {
                        // This is necessary for 16-bit operands, like "LDA abs" and "PEA val",
                        // when outside bank zero.  The bank is included in the operand address,
                        // but we don't want to show it here.
                        operandForSymbol &= 0xffff;
                    }
                    formattedOperand = formatter.FormatHexValue(operandForSymbol, operandLen * 2);
                }
            }
            string operandStr = formatter.FormatOperand(op, formattedOperand, wdis);

            string eolComment = proj.Comments[offset];

            if (doAddCycles)
            {
                bool branchCross = (attr.Address & 0xff00) != (operandForSymbol & 0xff00);
                int  cycles      = proj.CpuDef.GetCycles(op.Opcode, attr.StatusFlags, attr.BranchTaken,
                                                         branchCross);
                if (cycles > 0)
                {
                    eolComment = cycles.ToString() + "  " + eolComment;
                }
                else
                {
                    eolComment = (-cycles).ToString() + "+ " + eolComment;
                }
            }
            string commentStr = formatter.FormatEolComment(eolComment);

            string replMnemonic = gen.ModifyOpcode(offset, op);

            if (attr.Length != instrBytes)
            {
                // This instruction has another instruction inside it.  Throw out what we
                // computed and just output as bytes.
                gen.GenerateShortSequence(offset, instrBytes, out opcodeStr, out operandStr);
            }
            else if (isPcRelBankWrap && gen.Quirks.NoPcRelBankWrap)
            {
                // Some assemblers have trouble generating PC-relative operands that wrap
                // around the bank.  Output as raw hex.
                gen.GenerateShortSequence(offset, instrBytes, out opcodeStr, out operandStr);
            }
            else if (op.AddrMode == OpDef.AddressMode.BlockMove &&
                     gen.Quirks.BlockMoveArgsReversed)
            {
                // On second thought, just don't even output the wrong thing.
                gen.GenerateShortSequence(offset, instrBytes, out opcodeStr, out operandStr);
            }
            else if (replMnemonic == null)
            {
                // No mnemonic exists for this opcode.
                gen.GenerateShortSequence(offset, instrBytes, out opcodeStr, out operandStr);
            }
            else if (replMnemonic != string.Empty)
            {
                // A replacement mnemonic has been provided.
                opcodeStr = formatter.FormatMnemonic(replMnemonic, wdis);
            }
            gen.OutputLine(labelStr, opcodeStr, operandStr, commentStr);

            // Assemblers like Merlin32 try to be helpful and track SEP/REP, but they do the
            // wrong thing if we're in emulation mode.  Force flags back to short.
            if (proj.CpuDef.HasEmuFlag && gen.Quirks.TracksSepRepNotEmu && op == OpDef.OpREP_Imm)
            {
                if ((operand & 0x30) != 0 && attr.StatusFlags.E == 1)
                {
                    gen.OutputRegWidthDirective(offset, 0, 0, 1, 1);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Generates assembly source.
        ///
        /// This code is common to all generators.
        /// </summary>
        /// <param name="gen">Reference to generator object (presumably the caller).</param>
        /// <param name="sw">Text output sink.</param>
        /// <param name="worker">Background worker object, for progress updates and
        ///   cancelation requests.</param>
        public static void Generate(IGenerator gen, StreamWriter sw, BackgroundWorker worker)
        {
            DisasmProject proj      = gen.Project;
            Formatter     formatter = gen.SourceFormatter;
            int           offset    = 0;

            bool doAddCycles = gen.Settings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);

            GenerateHeader(gen, sw);

            // Used for M/X flag tracking.
            StatusFlags prevFlags = StatusFlags.AllIndeterminate;

            int lastProgress = 0;

            while (offset < proj.FileData.Length)
            {
                Anattrib attr = proj.GetAnattrib(offset);

                if (attr.IsInstructionStart && offset > 0 &&
                    proj.GetAnattrib(offset - 1).IsData)
                {
                    // Transition from data to code.  (Don't add blank line for inline data.)
                    gen.OutputLine(string.Empty);
                }

                // Long comments come first.
                if (proj.LongComments.TryGetValue(offset, out MultiLineComment longComment))
                {
                    List <string> formatted = longComment.FormatText(formatter, string.Empty);
                    foreach (string str in formatted)
                    {
                        gen.OutputLine(str);
                    }
                }

                // Check for address change.
                int orgAddr = proj.AddrMap.Get(offset);
                if (orgAddr >= 0)
                {
                    gen.OutputOrgDirective(offset, orgAddr);
                }

                if (attr.IsInstructionStart)
                {
                    // Generate M/X reg width directive, if necessary.
                    // NOTE: we can suppress the initial directive if we know what the
                    // target assembler's default assumption is.  Probably want to handle
                    // that in the ORG output handler.
                    if (proj.CpuDef.HasEmuFlag)
                    {
                        StatusFlags curFlags = attr.StatusFlags;
                        curFlags.M = attr.StatusFlags.ShortM ? 1 : 0;
                        curFlags.X = attr.StatusFlags.ShortX ? 1 : 0;
                        if (curFlags.M != prevFlags.M || curFlags.X != prevFlags.X)
                        {
                            // changed, output directive
                            gen.OutputRegWidthDirective(offset, prevFlags.M, prevFlags.X,
                                                        curFlags.M, curFlags.X);
                        }

                        prevFlags = curFlags;
                    }

                    // Look for embedded instructions.
                    int len;
                    for (len = 1; len < attr.Length; len++)
                    {
                        if (proj.GetAnattrib(offset + len).IsInstructionStart)
                        {
                            break;
                        }
                    }

                    // Output instruction.
                    GenerateInstruction(gen, sw, offset, len, doAddCycles);

                    if (attr.DoesNotContinue)
                    {
                        gen.OutputLine(string.Empty);
                    }

                    offset += len;
                }
                else
                {
                    gen.OutputDataOp(offset);
                    offset += attr.Length;
                }

                // Update progress meter.  We don't want to spam it, so just ping it 10x.
                int curProgress = (offset * 10) / proj.FileData.Length;
                if (lastProgress != curProgress)
                {
                    if (worker.CancellationPending)
                    {
                        Debug.WriteLine("GenCommon got cancellation request");
                        return;
                    }
                    lastProgress = curProgress;
                    worker.ReportProgress(curProgress * 10);
                    //System.Threading.Thread.Sleep(500);
                }
            }
        }
Esempio n. 5
0
        // IGenerator
        public void OutputDataOp(int offset)
        {
            Formatter formatter = SourceFormatter;

            byte[]   data = Project.FileData;
            Anattrib attr = Project.GetAnattrib(offset);

            string labelStr = string.Empty;

            if (attr.Symbol != null)
            {
                labelStr = mLocalizer.ConvLabel(attr.Symbol.Label);
            }

            string commentStr = SourceFormatter.FormatEolComment(Project.Comments[offset]);
            string opcodeStr, operandStr;

            FormatDescriptor dfd = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            int length = dfd.Length;

            Debug.Assert(length > 0);

            bool multiLine = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.Default:
                if (length != 1)
                {
                    Debug.Assert(false);
                    length = 1;
                }
                opcodeStr = sDataOpNames.DefineData1;
                int operand = RawData.GetWord(data, offset, length, false);
                operandStr = formatter.FormatHexValue(operand, length * 2);
                break;

            case FormatDescriptor.Type.NumericLE:
                opcodeStr = sDataOpNames.GetDefineData(length);
                operand   = RawData.GetWord(data, offset, length, false);
                if (length == 1 && dfd.IsStringOrCharacter &&
                    (operand & 0x7f) == '{' || (operand & 0x7f) == '}')
                {
                    // Merlin32 can't handle "DFB '{'", so just output hex.
                    operandStr = formatter.FormatHexValue(operand, length * 2);
                }
                else
                {
                    operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                               mLocalizer.LabelMap, dfd, operand, length,
                                                               PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                }
                break;

            case FormatDescriptor.Type.NumericBE:
                opcodeStr = sDataOpNames.GetDefineBigData(length);
                if ((string.IsNullOrEmpty(opcodeStr)))
                {
                    // Nothing defined, output as comma-separated single-byte values.
                    GenerateShortSequence(offset, length, out opcodeStr, out operandStr);
                }
                else
                {
                    operand    = RawData.GetWord(data, offset, length, true);
                    operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                               mLocalizer.LabelMap, dfd, operand, length,
                                                               PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                }
                break;

            case FormatDescriptor.Type.Fill:
                opcodeStr = sDataOpNames.Fill;
                if (data[offset] == 0)
                {
                    operandStr = length.ToString();
                }
                else
                {
                    operandStr = length + "," + formatter.FormatHexValue(data[offset], 2);
                }
                break;

            case FormatDescriptor.Type.Dense:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputDenseHex(offset, length, labelStr, commentStr);
                break;

            case FormatDescriptor.Type.Junk:
                int fillVal = Helper.CheckRangeHoldsSingleValue(data, offset, length);
                if (fillVal >= 0)
                {
                    opcodeStr = sDataOpNames.Fill;
                    if (dfd.FormatSubType == FormatDescriptor.SubType.Align256 &&
                        GenCommon.CheckJunkAlign(offset, dfd, Project.AddrMap))
                    {
                        // special syntax for page alignment
                        if (fillVal == 0)
                        {
                            operandStr = "\\";
                        }
                        else
                        {
                            operandStr = "\\," + formatter.FormatHexValue(fillVal, 2);
                        }
                    }
                    else
                    {
                        if (fillVal == 0)
                        {
                            operandStr = length.ToString();
                        }
                        else
                        {
                            operandStr = length + "," + formatter.FormatHexValue(fillVal, 2);
                        }
                    }
                }
                else
                {
                    // treat same as Dense
                    multiLine = true;
                    opcodeStr = operandStr = null;
                    OutputDenseHex(offset, length, labelStr, commentStr);
                }
                break;

            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringNullTerm:
            case FormatDescriptor.Type.StringL8:
            case FormatDescriptor.Type.StringL16:
            case FormatDescriptor.Type.StringDci:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputString(offset, labelStr, commentStr);
                break;

            default:
                opcodeStr  = "???";
                operandStr = "***";
                break;
            }

            if (!multiLine)
            {
                opcodeStr = formatter.FormatPseudoOp(opcodeStr);
                OutputLine(labelStr, opcodeStr, operandStr, commentStr);
            }
        }
Esempio n. 6
0
        private void OutputString(int offset, string labelStr, string commentStr)
        {
            // This gets complicated.
            //
            // For Dci, L8String, and L16String, the entire string needs to fit in the
            // operand of one line.  If it can't, we need to separate the length byte/word
            // or inverted character out, and just dump the rest as ASCII.  Computing the
            // line length requires factoring delimiter character escapes.  (NOTE: contrary
            // to the documentation, STR and STRL do include trailing hex characters in the
            // length calculation, so it's possible to escape delimiters.)
            //
            // For Reverse, we can span lines, but only if we emit the lines in
            // backward order.  Also, Merlin doesn't allow hex to be embedded in a REV
            // operation, so we can't use REV if the string contains a delimiter.
            //
            // For aesthetic purposes, zero-length CString, L8String, and L16String
            // should be output as DFB/DW zeroes rather than an empty string -- makes
            // it easier to read.
            //
            // NOTE: we generally assume that the input is in the correct format, e.g.
            // the length byte in a StringL8 matches dfd.Length, and the high bits in DCI strings
            // have the right pattern.  If not, we will generate bad output.  This would need
            // to be scanned and corrected at a higher level.

            Anattrib         attr = Project.GetAnattrib(offset);
            FormatDescriptor dfd  = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            Debug.Assert(dfd.IsString);
            Debug.Assert(dfd.Length > 0);

            // We can sort of do parts of C64 stuff, but it's probably more readable to just
            // output a commented blob than something where only the capital letters are readable.
            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.Ascii:
            case FormatDescriptor.SubType.HighAscii:
                break;

            case FormatDescriptor.SubType.C64Petscii:
            case FormatDescriptor.SubType.C64Screen:
            default:
                OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                return;
            }

            Formatter formatter = SourceFormatter;

            byte[] data = Project.FileData;
            StringOpFormatter.ReverseMode revMode = StringOpFormatter.ReverseMode.Forward;
            int    leadingBytes = 0;
            string opcodeStr;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
                opcodeStr = sDataOpNames.StrGeneric;
                break;

            case FormatDescriptor.Type.StringReverse:
                opcodeStr = sDataOpNames.StrReverse;
                revMode   = StringOpFormatter.ReverseMode.LineReverse;
                break;

            case FormatDescriptor.Type.StringNullTerm:
                opcodeStr = sDataOpNames.StrGeneric;            // no pseudo-op for this
                if (dfd.Length == 1)
                {
                    // Empty string.  Just output the length byte(s) or null terminator.
                    GenerateShortSequence(offset, 1, out string opcode, out string operand);
                    OutputLine(labelStr, opcode, operand, commentStr);
                    return;
                }
                break;

            case FormatDescriptor.Type.StringL8:
                opcodeStr    = sDataOpNames.StrLen8;
                leadingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL16:
                opcodeStr    = sDataOpNames.StrLen16;
                leadingBytes = 2;
                break;

            case FormatDescriptor.Type.StringDci:
                opcodeStr = sDataOpNames.StrDci;
                break;

            default:
                Debug.Assert(false);
                return;
            }

            // Merlin 32 uses single-quote for low ASCII, double-quote for high ASCII.
            CharEncoding.Convert charConv;
            char delim;

            if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii)
            {
                charConv = CharEncoding.ConvertHighAscii;
                delim    = '"';
            }
            else
            {
                charConv = CharEncoding.ConvertAscii;
                delim    = '\'';
            }

            StringOpFormatter stropf = new StringOpFormatter(SourceFormatter,
                                                             new Formatter.DelimiterDef(delim),
                                                             StringOpFormatter.RawOutputStyle.DenseHex, MAX_OPERAND_LEN, charConv);

            if (dfd.FormatType == FormatDescriptor.Type.StringDci)
            {
                // DCI is awkward because the character encoding flips on the last byte.  Rather
                // than clutter up StringOpFormatter for this rare item, we just accept low/high
                // throughout.
                stropf.CharConv = CharEncoding.ConvertLowAndHighAscii;
            }

            // Feed bytes in, skipping over the leading length bytes.
            stropf.FeedBytes(data, offset + leadingBytes,
                             dfd.Length - leadingBytes, 0, revMode);
            Debug.Assert(stropf.Lines.Count > 0);

            // See if we need to do this over.
            bool redo = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringNullTerm:
                break;

            case FormatDescriptor.Type.StringReverse:
                if (stropf.HasEscapedText)
                {
                    // can't include escaped characters in REV
                    opcodeStr = sDataOpNames.StrGeneric;
                    revMode   = StringOpFormatter.ReverseMode.Forward;
                    redo      = true;
                }
                break;

            case FormatDescriptor.Type.StringL8:
                if (stropf.Lines.Count != 1)
                {
                    // single-line only
                    opcodeStr    = sDataOpNames.StrGeneric;
                    leadingBytes = 1;
                    redo         = true;
                }
                break;

            case FormatDescriptor.Type.StringL16:
                if (stropf.Lines.Count != 1)
                {
                    // single-line only
                    opcodeStr    = sDataOpNames.StrGeneric;
                    leadingBytes = 2;
                    redo         = true;
                }
                break;

            case FormatDescriptor.Type.StringDci:
                if (stropf.Lines.Count != 1)
                {
                    // single-line only
                    opcodeStr       = sDataOpNames.StrGeneric;
                    stropf.CharConv = charConv;
                    redo            = true;
                }
                break;

            default:
                Debug.Assert(false);
                return;
            }

            if (redo)
            {
                //Debug.WriteLine("REDO off=+" + offset.ToString("x6") + ": " + dfd.FormatType);

                // This time, instead of skipping over leading length bytes, we include them
                // explicitly.
                stropf.Reset();
                stropf.FeedBytes(data, offset, dfd.Length, leadingBytes, revMode);
            }

            opcodeStr = formatter.FormatPseudoOp(opcodeStr);

            foreach (string str in stropf.Lines)
            {
                OutputLine(labelStr, opcodeStr, str, commentStr);
                labelStr = commentStr = string.Empty;       // only show on first
            }
        }
Esempio n. 7
0
        private void OutputString(int offset, string labelStr, string commentStr)
        {
            // This gets complicated.
            //
            // For Dci, L8String, and L16String, the entire string needs to fit in the
            // operand of one line.  If it can't, we need to separate the length byte/word
            // or inverted character out, and just dump the rest as ASCII.  Computing the
            // line length requires factoring delimiter character escapes.  (NOTE: contrary
            // to the documentation, STR and STRL do include trailing hex characters in the
            // length calculation, so it's possible to escape delimiters.)
            //
            // For Reverse, we can span lines, but only if we emit the lines in
            // backward order.  Also, Merlin doesn't allow hex to be embedded in a REV
            // operation, so we can't use REV if the string contains a delimiter.
            //
            // DciReverse is deprecated, but we can handle it as a Reverse string with a
            // trailing byte on a following line.
            //
            // For aesthetic purposes, zero-length CString, L8String, and L16String
            // should be output as DFB/DW zeroes rather than an empty string -- makes
            // it easier to read.

            Formatter formatter = SourceFormatter;

            byte[]           data = Project.FileData;
            Anattrib         attr = Project.GetAnattrib(offset);
            FormatDescriptor dfd  = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String);
            Debug.Assert(dfd.Length > 0);

            bool    highAscii     = false;
            int     showZeroes    = 0;
            int     leadingBytes  = 0;
            int     trailingBytes = 0;
            bool    showLeading   = false;
            bool    showTrailing  = false;
            RevMode revMode       = RevMode.Forward;

            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.None:
                highAscii = (data[offset] & 0x80) != 0;
                break;

            case FormatDescriptor.SubType.Dci:
                highAscii = (data[offset] & 0x80) != 0;
                break;

            case FormatDescriptor.SubType.Reverse:
                highAscii = (data[offset] & 0x80) != 0;
                revMode   = RevMode.Reverse;
                break;

            case FormatDescriptor.SubType.DciReverse:
                highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0;
                revMode   = RevMode.Reverse;
                break;

            case FormatDescriptor.SubType.CString:
                highAscii = (data[offset] & 0x80) != 0;
                if (dfd.Length == 1)
                {
                    showZeroes = 1;         // empty null-terminated string
                }
                trailingBytes = 1;
                showTrailing  = true;
                break;

            case FormatDescriptor.SubType.L8String:
                if (dfd.Length > 1)
                {
                    highAscii = (data[offset + 1] & 0x80) != 0;
                }
                else
                {
                    //showZeroes = 1;
                }
                leadingBytes = 1;
                break;

            case FormatDescriptor.SubType.L16String:
                if (dfd.Length > 2)
                {
                    highAscii = (data[offset + 2] & 0x80) != 0;
                }
                else
                {
                    //showZeroes = 2;
                }
                leadingBytes = 2;
                break;

            default:
                Debug.Assert(false);
                return;
            }

            if (showZeroes != 0)
            {
                // Empty string.  Just output the length byte(s) or null terminator.
                GenerateShortSequence(offset, showZeroes, out string opcode, out string operand);
                OutputLine(labelStr, opcode, operand, commentStr);
                return;
            }

            // Merlin 32 uses single-quote for low ASCII, double-quote for high ASCII.  When
            // quoting the delimiter we use a hexadecimal value.  We need to bear in mind that
            // we're forcing the characters to low ASCII, but the actual character being
            // escaped might be in high ASCII.  Hence delim vs. delimReplace.
            char         delim        = highAscii ? '"' : '\'';
            char         delimReplace = highAscii ? ((char)(delim | 0x80)) : delim;
            StringGather gath         = null;

            // Run the string through so we can see if it'll fit on one line.  As a minor
            // optimization, we skip this step for "generic" strings, which are probably
            // the most common thing.
            if (dfd.FormatSubType != FormatDescriptor.SubType.None)
            {
                gath = new StringGather(this, labelStr, "???", commentStr, delim,
                                        delimReplace, StringGather.ByteStyle.DenseHex, MAX_OPERAND_LEN, true);
                FeedGath(gath, data, offset, dfd.Length, revMode, leadingBytes, showLeading,
                         trailingBytes, showTrailing);
                Debug.Assert(gath.NumLinesOutput > 0);
            }

            string opcodeStr;

            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.None:
                opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                break;

            case FormatDescriptor.SubType.Dci:
                if (gath.NumLinesOutput == 1)
                {
                    opcodeStr = highAscii ? sDataOpNames.StrDciHi : sDataOpNames.StrDci;
                }
                else
                {
                    opcodeStr     = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                    trailingBytes = 1;
                    showTrailing  = true;
                }
                break;

            case FormatDescriptor.SubType.Reverse:
                if (gath.HasDelimiter)
                {
                    // can't include escaped delimiters in REV
                    opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                    revMode   = RevMode.Forward;
                }
                else if (gath.NumLinesOutput > 1)
                {
                    opcodeStr = highAscii ? sDataOpNames.StrReverseHi : sDataOpNames.StrReverse;
                    revMode   = RevMode.BlockReverse;
                }
                else
                {
                    opcodeStr = highAscii ? sDataOpNames.StrReverseHi : sDataOpNames.StrReverse;
                    Debug.Assert(revMode == RevMode.Reverse);
                }
                break;

            case FormatDescriptor.SubType.DciReverse:
                // Mostly punt -- output as ASCII with special handling for first byte.
                opcodeStr    = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                revMode      = RevMode.Forward;
                leadingBytes = 1;
                showLeading  = true;
                break;

            case FormatDescriptor.SubType.CString:
                //opcodeStr = sDataOpNames.StrNullTerm[highAscii ? 1 : 0];
                opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                break;

            case FormatDescriptor.SubType.L8String:
                if (gath.NumLinesOutput == 1)
                {
                    opcodeStr = highAscii ? sDataOpNames.StrLen8Hi : sDataOpNames.StrLen8;
                }
                else
                {
                    opcodeStr    = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                    leadingBytes = 1;
                    showLeading  = true;
                }
                break;

            case FormatDescriptor.SubType.L16String:
                if (gath.NumLinesOutput == 1)
                {
                    opcodeStr = highAscii ? sDataOpNames.StrLen16Hi : sDataOpNames.StrLen16;
                }
                else
                {
                    opcodeStr    = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
                    leadingBytes = 2;
                    showLeading  = true;
                }
                break;

            default:
                Debug.Assert(false);
                return;
            }

            opcodeStr = formatter.FormatPseudoOp(opcodeStr);

            // Create a new StringGather, with the final opcode choice.
            gath = new StringGather(this, labelStr, opcodeStr, commentStr, delim,
                                    delimReplace, StringGather.ByteStyle.DenseHex, MAX_OPERAND_LEN, false);
            FeedGath(gath, data, offset, dfd.Length, revMode, leadingBytes, showLeading,
                     trailingBytes, showTrailing);
        }
Esempio n. 8
0
        // IGenerator
        public void OutputDataOp(int offset)
        {
            Formatter formatter = SourceFormatter;

            byte[]   data = Project.FileData;
            Anattrib attr = Project.GetAnattrib(offset);

            string labelStr = string.Empty;

            if (attr.Symbol != null)
            {
                labelStr = mLocalizer.ConvLabel(attr.Symbol.Label);
            }

            string commentStr = SourceFormatter.FormatEolComment(Project.Comments[offset]);
            string opcodeStr, operandStr;

            FormatDescriptor dfd = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            int length = dfd.Length;

            Debug.Assert(length > 0);

            bool multiLine = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.Default:
                if (length != 1)
                {
                    Debug.Assert(false);
                    length = 1;
                }
                opcodeStr = sDataOpNames.DefineData1;
                int operand = RawData.GetWord(data, offset, length, false);
                operandStr = formatter.FormatHexValue(operand, length * 2);
                break;

            case FormatDescriptor.Type.NumericLE:
                opcodeStr  = sDataOpNames.GetDefineData(length);
                operand    = RawData.GetWord(data, offset, length, false);
                operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                           mLocalizer.LabelMap, dfd, operand, length,
                                                           PseudoOp.FormatNumericOpFlags.None);
                break;

            case FormatDescriptor.Type.NumericBE:
                opcodeStr = sDataOpNames.GetDefineBigData(length);
                if (opcodeStr == null)
                {
                    // Nothing defined, output as comma-separated single-byte values.
                    GenerateShortSequence(offset, length, out opcodeStr, out operandStr);
                }
                else
                {
                    operand    = RawData.GetWord(data, offset, length, true);
                    operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                               mLocalizer.LabelMap, dfd, operand, length,
                                                               PseudoOp.FormatNumericOpFlags.None);
                }
                break;

            case FormatDescriptor.Type.Fill:
                opcodeStr  = sDataOpNames.Fill;
                operandStr = length + "," + formatter.FormatHexValue(data[offset], 2);
                break;

            case FormatDescriptor.Type.Dense:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputDenseHex(offset, length, labelStr, commentStr);
                break;

            case FormatDescriptor.Type.String:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputString(offset, labelStr, commentStr);
                break;

            default:
                opcodeStr  = "???";
                operandStr = "***";
                break;
            }

            if (!multiLine)
            {
                opcodeStr = formatter.FormatPseudoOp(opcodeStr);
                OutputLine(labelStr, opcodeStr, operandStr, commentStr);
            }
        }
Esempio n. 9
0
        private void OutputString(int offset, string labelStr, string commentStr)
        {
            // Generic strings whose encoding matches the configured text encoding are output
            // with a simple .text directive.
            //
            // CString and L8String have directives (.null, .ptext), but we can only use
            // them if the string fits on one line and doesn't include delimiters.
            //
            // We might be able to define a macro for Reverse.
            //
            // We don't currently switch character encodings in the middle of a file.  We could
            // do so to flip between PETSCII, screen codes, low ASCII, and high ASCII, but it
            // adds a lot of noise and it's unclear that this is generally useful.

            Anattrib         attr = Project.GetAnattrib(offset);
            FormatDescriptor dfd  = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            Debug.Assert(dfd.IsString);
            Debug.Assert(dfd.Length > 0);

            CharEncoding.Convert charConv = null;
            CharEncoding.Convert dciConv  = null;
            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.Ascii:
                charConv = CharEncoding.ConvertAscii;
                dciConv  = CharEncoding.ConvertLowAndHighAscii;
                break;

            case FormatDescriptor.SubType.HighAscii:
                charConv = CharEncoding.ConvertHighAscii;
                dciConv  = CharEncoding.ConvertLowAndHighAscii;
                break;

            case FormatDescriptor.SubType.C64Petscii:
                charConv = CharEncoding.ConvertC64Petscii;
                dciConv  = CharEncoding.ConvertLowAndHighC64Petscii;
                break;

            case FormatDescriptor.SubType.C64Screen:
                charConv = CharEncoding.ConvertC64ScreenCode;
                dciConv  = CharEncoding.ConvertLowAndHighC64ScreenCode;
                break;

            default:
                break;
            }
            if (charConv == null)
            {
                OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                return;
            }

            // Issue a .enc, if needed.
            UpdateCharacterEncoding(dfd);

            Formatter formatter = SourceFormatter;

            byte[] data = Project.FileData;
            int    hiddenLeadingBytes = 0;
            int    shownLeadingBytes  = 0;
            int    trailingBytes      = 0;
            string opcodeStr;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
                opcodeStr = sDataOpNames.StrGeneric;
                break;

            case FormatDescriptor.Type.StringNullTerm:
                opcodeStr     = sDataOpNames.StrNullTerm;
                trailingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL8:
                opcodeStr          = sDataOpNames.StrLen8;
                hiddenLeadingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL16:
                opcodeStr         = sDataOpNames.StrGeneric;
                shownLeadingBytes = 2;
                break;

            case FormatDescriptor.Type.StringDci:
                opcodeStr = sDataOpNames.StrDci;
                if ((Project.FileData[offset] & 0x80) != 0)
                {
                    // ".shift" directive only works for strings where the low bit starts
                    // clear and ends high.
                    OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                    return;
                }
                break;

            default:
                Debug.Assert(false);
                return;
            }

            StringOpFormatter stropf = new StringOpFormatter(SourceFormatter,
                                                             Formatter.DOUBLE_QUOTE_DELIM, StringOpFormatter.RawOutputStyle.CommaSep,
                                                             MAX_OPERAND_LEN, charConv);

            if (dfd.FormatType == FormatDescriptor.Type.StringDci)
            {
                // DCI is awkward because the character encoding flips on the last byte.  Rather
                // than clutter up StringOpFormatter for this rare item, we just accept low/high
                // throughout.
                stropf.CharConv = dciConv;
            }

            // Feed bytes in, skipping over hidden bytes (leading L8, trailing null).
            stropf.FeedBytes(data, offset + hiddenLeadingBytes,
                             dfd.Length - hiddenLeadingBytes - trailingBytes, shownLeadingBytes,
                             StringOpFormatter.ReverseMode.Forward);
            Debug.Assert(stropf.Lines.Count > 0);

            // See if we need to do this over.
            bool redo = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringL16:
                // All good the first time.
                break;

            case FormatDescriptor.Type.StringNullTerm:
            case FormatDescriptor.Type.StringL8:
            case FormatDescriptor.Type.StringDci:
                if (stropf.Lines.Count != 1)
                {
                    // Must be single-line.
                    opcodeStr       = sDataOpNames.StrGeneric;
                    stropf.CharConv = charConv;     // undo DCI hack
                    redo            = true;
                }
                break;

            default:
                Debug.Assert(false);
                return;
            }

            if (redo)
            {
                //Debug.WriteLine("REDO off=+" + offset.ToString("x6") + ": " + dfd.FormatType);

                // This time, instead of skipping over leading length bytes, we include them
                // explicitly.
                stropf.Reset();
                stropf.FeedBytes(data, offset, dfd.Length, hiddenLeadingBytes,
                                 StringOpFormatter.ReverseMode.Forward);
            }

            opcodeStr = formatter.FormatPseudoOp(opcodeStr);

            foreach (string str in stropf.Lines)
            {
                OutputLine(labelStr, opcodeStr, str, commentStr);
                labelStr = commentStr = string.Empty;       // only show on first
            }
        }
Esempio n. 10
0
        // IGenerator
        public void OutputDataOp(int offset)
        {
            Formatter formatter = SourceFormatter;

            byte[]   data = Project.FileData;
            Anattrib attr = Project.GetAnattrib(offset);

            string labelStr = string.Empty;

            if (attr.Symbol != null)
            {
                labelStr = mLocalizer.ConvLabel(attr.Symbol.Label);
            }

            string commentStr = SourceFormatter.FormatEolComment(Project.Comments[offset]);
            string opcodeStr, operandStr;

            FormatDescriptor dfd = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            int length = dfd.Length;

            Debug.Assert(length > 0);

            bool multiLine = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.Default:
                if (length != 1)
                {
                    Debug.Assert(false);
                    length = 1;
                }
                opcodeStr = sDataOpNames.DefineData1;
                int operand = RawData.GetWord(data, offset, length, false);
                operandStr = formatter.FormatHexValue(operand, length * 2);
                break;

            case FormatDescriptor.Type.NumericLE:
                opcodeStr = sDataOpNames.GetDefineData(length);
                operand   = RawData.GetWord(data, offset, length, false);
                UpdateCharacterEncoding(dfd);
                operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                           mLocalizer.LabelMap, dfd, operand, length,
                                                           PseudoOp.FormatNumericOpFlags.None);
                break;

            case FormatDescriptor.Type.NumericBE:
                opcodeStr = sDataOpNames.GetDefineBigData(length);
                if ((string.IsNullOrEmpty(opcodeStr)))
                {
                    // Nothing defined, output as comma-separated single-byte values.
                    GenerateShortSequence(offset, length, out opcodeStr, out operandStr);
                }
                else
                {
                    UpdateCharacterEncoding(dfd);
                    operand    = RawData.GetWord(data, offset, length, true);
                    operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
                                                               mLocalizer.LabelMap, dfd, operand, length,
                                                               PseudoOp.FormatNumericOpFlags.None);
                }
                break;

            case FormatDescriptor.Type.Fill:
                opcodeStr  = sDataOpNames.Fill;
                operandStr = length + "," + formatter.FormatHexValue(data[offset], 2);
                break;

            case FormatDescriptor.Type.Dense:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputDenseHex(offset, length, labelStr, commentStr);
                break;

            case FormatDescriptor.Type.Junk:
                int fillVal = Helper.CheckRangeHoldsSingleValue(data, offset, length);
                if (fillVal >= 0 && GenCommon.CheckJunkAlign(offset, dfd, Project.AddrMap))
                {
                    // .align <expression>[, <fill>]
                    opcodeStr = sDataOpNames.Align;
                    int alignVal = 1 << FormatDescriptor.AlignmentToPower(dfd.FormatSubType);
                    operandStr = alignVal.ToString() +
                                 "," + formatter.FormatHexValue(fillVal, 2);
                }
                else if (fillVal >= 0)
                {
                    // treat same as Fill
                    opcodeStr  = sDataOpNames.Fill;
                    operandStr = length + "," + formatter.FormatHexValue(fillVal, 2);
                }
                else
                {
                    // treat same as Dense
                    multiLine = true;
                    opcodeStr = operandStr = null;
                    OutputDenseHex(offset, length, labelStr, commentStr);
                }
                break;

            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringNullTerm:
            case FormatDescriptor.Type.StringL8:
            case FormatDescriptor.Type.StringL16:
            case FormatDescriptor.Type.StringDci:
                multiLine = true;
                opcodeStr = operandStr = null;
                OutputString(offset, labelStr, commentStr);
                break;

            default:
                opcodeStr  = "???";
                operandStr = "***";
                break;
            }

            if (!multiLine)
            {
                opcodeStr = formatter.FormatPseudoOp(opcodeStr);
                OutputLine(labelStr, opcodeStr, operandStr, commentStr);
            }
        }
Esempio n. 11
0
        private void OutputString(int offset, string labelStr, string commentStr)
        {
            Formatter formatter = SourceFormatter;

            byte[]           data = Project.FileData;
            Anattrib         attr = Project.GetAnattrib(offset);
            FormatDescriptor dfd  = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            Debug.Assert(dfd.IsString);
            Debug.Assert(dfd.Length > 0);

            string opcodeStr;

            CharEncoding.Convert charConv;
            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.Ascii:
                opcodeStr = sDataOpNames.StrGeneric;
                charConv  = CharEncoding.ConvertAscii;
                break;

            case FormatDescriptor.SubType.HighAscii:
                opcodeStr = sDataOpNames.StrGeneric;
                charConv  = CharEncoding.ConvertHighAscii;
                break;

            case FormatDescriptor.SubType.C64Petscii:
                opcodeStr = "!pet";
                charConv  = CharEncoding.ConvertC64Petscii;
                break;

            case FormatDescriptor.SubType.C64Screen:
                opcodeStr = "!scr";
                charConv  = CharEncoding.ConvertC64ScreenCode;
                break;

            default:
                Debug.Assert(false);
                OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                return;
            }

            int leadingBytes = 0;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringNullTerm:
            case FormatDescriptor.Type.StringDci:
                // Last byte may be output as hex.
                break;

            case FormatDescriptor.Type.StringL8:
                // Length byte will be output as hex.
                leadingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL16:
                // Length byte will be output as hex.
                leadingBytes = 2;
                break;

            default:
                Debug.Assert(false);
                return;
            }

            StringOpFormatter stropf = new StringOpFormatter(SourceFormatter,
                                                             Formatter.DOUBLE_QUOTE_DELIM, StringOpFormatter.RawOutputStyle.CommaSep,
                                                             MAX_OPERAND_LEN, charConv);

            stropf.FeedBytes(data, offset, dfd.Length, leadingBytes,
                             StringOpFormatter.ReverseMode.Forward);

            if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii && stropf.HasEscapedText)
            {
                // Can't !xor the output, because while it works for string data it
                // also flips the high bits on the unprintable bytes we output as raw hex.
                OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                return;
            }

            if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii)
            {
                OutputLine(string.Empty, "!xor", "$80 {", string.Empty);
            }
            foreach (string str in stropf.Lines)
            {
                OutputLine(labelStr, opcodeStr, str, commentStr);
                labelStr = commentStr = string.Empty;       // only show on first
            }
            if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii)
            {
                OutputLine(string.Empty, "}", string.Empty, string.Empty);
            }
        }