Beispiel #1
0
        /// <summary>
        /// Formats a single-character operand.  Output will be a delimited printable character
        /// when possible, a hex value when the converted character is unprintable.
        /// </summary>
        /// <param name="value">Value to format.  Could be a 16-bit immediate value.</param>
        /// <param name="enc">Character encoding to use for value.</param>
        /// <returns>Formatted string.</returns>
        public string FormatCharacterValue(int value, CharEncoding.Encoding enc)
        {
            if (value < 0 || value > 0xff)
            {
                return(FormatHexValue(value, 2));
            }

            DelimiterDef delimDef = mFormatConfig.mCharDelimiters.Get(enc);

            if (delimDef == null)
            {
                return(FormatHexValue(value, 2));
            }

            string fmt = delimDef.FormatStr;

            Debug.Assert(fmt != null);

            CharEncoding.Convert conv;
            switch (enc)
            {
            case CharEncoding.Encoding.Ascii:
                conv = CharEncoding.ConvertAscii;
                break;

            case CharEncoding.Encoding.HighAscii:
                conv = CharEncoding.ConvertHighAscii;
                break;

            case CharEncoding.Encoding.C64Petscii:
                conv = CharEncoding.ConvertC64Petscii;
                break;

            case CharEncoding.Encoding.C64ScreenCode:
                conv = CharEncoding.ConvertC64ScreenCode;
                break;

            default:
                return(FormatHexValue(value, 2));
            }

            char ch = conv((byte)value);

            if (ch == CharEncoding.UNPRINTABLE_CHAR || ch == delimDef.OpenDelim ||
                ch == delimDef.CloseDelim)
            {
                // We might be able to do better with delimiter clashes, e.g. '\'', but
                // that's assembler-specific.
                return(FormatHexValue(value, 2));
            }
            else
            {
                // Possible optimization: replace fmt with a prefix/suffix pair, and just concat
                return(string.Format(fmt, ch));
            }
        }
Beispiel #2
0
        // IGenerator
        public void UpdateCharacterEncoding(FormatDescriptor dfd)
        {
            CharEncoding.Encoding newEnc = PseudoOp.SubTypeToEnc(dfd.FormatSubType);
            if (newEnc == CharEncoding.Encoding.Unknown)
            {
                // probably not a character operand
                return;
            }
            if (newEnc != mCurrentEncoding)
            {
                switch (newEnc)
                {
                case CharEncoding.Encoding.Ascii:
                    OutputLine(string.Empty, ".enc", '"' + ASCII_ENC_NAME + '"', string.Empty);
                    break;

                case CharEncoding.Encoding.HighAscii:
                    // If this is a numeric operand (not string), and we're currently in
                    // ASCII mode, the "| $80" in the delimiter will handle this without
                    // the need for a .enc.  Much less clutter for sources that have plain
                    // ASCII strings but test high ASCII constants.
                    if (mCurrentEncoding == CharEncoding.Encoding.Ascii && !dfd.IsString)
                    {
                        newEnc = mCurrentEncoding;
                    }
                    else
                    {
                        OutputLine(string.Empty, ".enc", '"' + HIGH_ASCII_ENC_NAME + '"',
                                   string.Empty);
                    }
                    break;

                case CharEncoding.Encoding.C64Petscii:
                    OutputLine(string.Empty, ".enc", "\"none\"", string.Empty);
                    break;

                case CharEncoding.Encoding.C64ScreenCode:
                    OutputLine(string.Empty, ".enc", "\"screen\"", string.Empty);
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                mCurrentEncoding = newEnc;
            }
        }
Beispiel #3
0
        // IGenerator
        public void OutputAsmConfig()
        {
            CpuDef cpuDef = Project.CpuDef;
            string cpuStr;

            if (cpuDef.Type == CpuDef.CpuType.Cpu65816)
            {
                cpuStr = "65816";
            }
            else if (cpuDef.Type == CpuDef.CpuType.Cpu65C02)
            {
                cpuStr = "65c02";
            }
            else if (cpuDef.Type == CpuDef.CpuType.CpuW65C02)
            {
                cpuStr = "w65c02";
            }
            else if (cpuDef.Type == CpuDef.CpuType.Cpu6502 && cpuDef.HasUndocumented)
            {
                cpuStr = "6502i";
            }
            else
            {
                cpuStr = "6502";
            }

            OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(".cpu"),
                       '\"' + cpuStr + '\"', string.Empty);

            // C64 PETSCII and C64 screen codes are built in.  Define ASCII if we also
            // need that.
            mCurrentEncoding = CharEncoding.Encoding.C64Petscii;

            CheckAsciiFormats(out bool hasAscii, out bool hasHighAscii);
            if (hasHighAscii)
            {
                OutputLine(string.Empty, ".enc", '"' + HIGH_ASCII_ENC_NAME + '"', string.Empty);
                OutputLine(string.Empty, ".cdef", "$20,$7e,$a0", string.Empty);
                mCurrentEncoding = CharEncoding.Encoding.HighAscii;
            }
            if (hasAscii)
            {
                OutputLine(string.Empty, ".enc", '"' + ASCII_ENC_NAME + '"', string.Empty);
                OutputLine(string.Empty, ".cdef", "$20,$7e,$20", string.Empty);
                mCurrentEncoding = CharEncoding.Encoding.Ascii;
            }
        }
Beispiel #4
0
 public void Set(CharEncoding.Encoding enc, DelimiterDef def)
 {
     mDelimiters[enc] = def;
 }
Beispiel #5
0
 /// <summary>
 /// Returns the specified DelimiterDef, or null if not found.
 /// </summary>
 public DelimiterDef Get(CharEncoding.Encoding enc)
 {
     mDelimiters.TryGetValue(enc, out DelimiterDef def);
     return(def);
 }
Beispiel #6
0
        /// <summary>
        /// Format a numeric operand value according to the specified sub-format.
        /// </summary>
        /// <param name="formatter">Text formatter.</param>
        /// <param name="symbolTable">Full table of project symbols.</param>
        /// <param name="lvLookup">Local variable lookup object.  May be null if not
        ///   formatting an instruction.</param>
        /// <param name="labelMap">Symbol label remap, for local label conversion.  May be
        ///   null.</param>
        /// <param name="dfd">Operand format descriptor.</param>
        /// <param name="offset">Offset of start of instruction or data pseudo-op, for
        ///   variable name lookup.  Okay to pass -1 when not formatting an instruction.</param>
        /// <param name="operandValue">Operand's value.  For most things this comes directly
        ///   out of the code, for relative branches it's a 24-bit absolute address.</param>
        /// <param name="operandLen">Length of operand, in bytes.  For an instruction, this
        ///   does not include the opcode byte.  For a relative branch, this will be 2.</param>
        /// <param name="flags">Special handling.</param>
        public static string FormatNumericOperand(Formatter formatter, SymbolTable symbolTable,
                                                  LocalVariableLookup lvLookup, Dictionary <string, string> labelMap,
                                                  FormatDescriptor dfd, int offset, int operandValue, int operandLen,
                                                  FormatNumericOpFlags flags)
        {
            Debug.Assert(operandLen > 0);
            int hexMinLen = operandLen * 2;

            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.None:
            case FormatDescriptor.SubType.Hex:
            case FormatDescriptor.SubType.Address:
                return(formatter.FormatHexValue(operandValue, hexMinLen));

            case FormatDescriptor.SubType.Decimal:
                return(formatter.FormatDecimalValue(operandValue));

            case FormatDescriptor.SubType.Binary:
                return(formatter.FormatBinaryValue(operandValue, hexMinLen * 4));

            case FormatDescriptor.SubType.Ascii:
            case FormatDescriptor.SubType.HighAscii:
            case FormatDescriptor.SubType.C64Petscii:
            case FormatDescriptor.SubType.C64Screen:
                CharEncoding.Encoding enc = SubTypeToEnc(dfd.FormatSubType);
                return(formatter.FormatCharacterValue(operandValue, enc));

            case FormatDescriptor.SubType.Symbol:
                if (lvLookup != null && dfd.SymbolRef.IsVariable)
                {
                    Debug.Assert(operandLen == 1);          // only doing 8-bit stuff
                    DefSymbol defSym = lvLookup.GetSymbol(offset, dfd.SymbolRef);
                    if (defSym != null)
                    {
                        StringBuilder sb = new StringBuilder();
                        FormatNumericSymbolCommon(formatter, defSym, null,
                                                  dfd, operandValue, operandLen, flags, sb);
                        return(sb.ToString());
                    }
                    else
                    {
                        Debug.WriteLine("Local variable format failed");
                        Debug.Assert(false);
                        return(formatter.FormatHexValue(operandValue, hexMinLen));
                    }
                }
                else if (symbolTable.TryGetNonVariableValue(dfd.SymbolRef.Label,
                                                            out Symbol sym))
                {
                    StringBuilder sb = new StringBuilder();

                    switch (formatter.ExpressionMode)
                    {
                    case Formatter.FormatConfig.ExpressionMode.Common:
                        FormatNumericSymbolCommon(formatter, sym, labelMap,
                                                  dfd, operandValue, operandLen, flags, sb);
                        break;

                    case Formatter.FormatConfig.ExpressionMode.Cc65:
                        FormatNumericSymbolCc65(formatter, sym, labelMap,
                                                dfd, operandValue, operandLen, flags, sb);
                        break;

                    case Formatter.FormatConfig.ExpressionMode.Merlin:
                        FormatNumericSymbolMerlin(formatter, sym, labelMap,
                                                  dfd, operandValue, operandLen, flags, sb);
                        break;

                    default:
                        Debug.Assert(false, "Unknown expression mode " +
                                     formatter.ExpressionMode);
                        return("???");
                    }

                    return(sb.ToString());
                }
                else
                {
                    return(formatter.FormatHexValue(operandValue, hexMinLen));
                }

            default:
                // should not see REMOVE or ASCII_GENERIC here
                Debug.Assert(false);
                return("???");
            }
        }