Ejemplo n.º 1
0
	void SetupArguments (OpDef def)
	{
		// Attributes related to the InputArg's type are inferred automatically
		// and are not exposed to the client.
		var inferred_input_args = new Dictionary<string, bool> ();
		required_attrs = new List<OpDef.AttrDef> ();
		optional_attrs = new List<OpDef.AttrDef> ();

		foreach (var argdef in def.input_arg) {
			if (argdef.type_attr != "")
				inferred_input_args [argdef.type_attr] = true;
			else if (argdef.type_list_attr != "")
				inferred_input_args [argdef.type_list_attr] = true;
			if (argdef.number_attr != "")
				inferred_input_args [argdef.number_attr] = true;
		}
		foreach (var attr in def.attr) {
			if (inferred_input_args.ContainsKey (attr.name))
				continue;
			if (attr.default_value == null)
				required_attrs.Add (attr);
			else
				optional_attrs.Add (attr);
		}
		have_return_value = def.output_arg.Count > 0;
	}
Ejemplo n.º 2
0
        // Generates arguments:
        //   * Input arguments (TFOutput or TFOutput [])
        //   * All required attributes
        //   * variadic optional arguments
        string FillArguments(OpDef def)
        {
            var    sb    = new StringBuilder();
            string comma = "";

            foreach (var inarg in def.input_arg)
            {
                string type = "TF_Output" + (IsListArg(inarg) ? "[]" : "");

                sb.AppendFormat($"{comma}{type} {ParamMap(inarg.name)}");
                comma = ", ";
            }
            foreach (var attr in required_attrs)
            {
                sb.AppendFormat($"{comma}{CSharpType(attr.type)} {ParamMap(attr.name)}");
                comma = ", ";
            }

            foreach (var attr in optional_attrs)
            {
                bool reftype      = IsReferenceType(attr.type);
                var  cstype       = CSharpType(attr.type);
                var  cstypesuffix = reftype ? "" : "?";

                sb.AppendFormat($"{comma}{cstype}{cstypesuffix} {attr.name} = null");
                comma = ", ";
            }
            if (sb.Length != 0)
            {
                sb.Append(", ");
            }
            return(sb.ToString());
        }
Ejemplo n.º 3
0
 // IGenerator
 public string ReplaceMnemonic(OpDef op)
 {
     if ((op == OpDef.OpWDM_WDM || op == OpDef.OpBRK_StackInt) && mAsmVersion <= V2_17)
     {
         // cc65 v2.17 doesn't support WDM, and assembles BRK <arg> to opcode $05.
         // https://github.com/cc65/cc65/issues/715
         // https://github.com/cc65/cc65/issues/716
         return(null);
     }
     else if (op.IsUndocumented)
     {
         if (sUndocMap.TryGetValue(op.Mnemonic, out string newValue))
         {
             if ((op.Mnemonic == OpName.ANC && op.Opcode != 0x0b) ||
                 (op.Mnemonic == OpName.HLT && op.Opcode != 0x02))
             {
                 // There are multiple opcodes for the same thing.  cc65 outputs
                 // one specific thing, so we need to match that, and just do a hex
                 // dump for the others.
                 return(null);
             }
             return(newValue);
         }
         return(null);
     }
     else
     {
         return(string.Empty);
     }
 }
Ejemplo n.º 4
0
        // IGenerator
        public string ModifyOpcode(int offset, OpDef op)
        {
            if (op.IsUndocumented)
            {
                return(null);
            }

            // The assembler works correctly if the symbol is defined as a two-digit hex
            // value (e.g. "foo equ $80") but fails if it's four (e.g. "foo equ $0080").  We
            // output symbols with minimal digits, but we have no control over labels when
            // the code has a zero-page EQU.  So if the operand is a reference to a user
            // label, we need to output the instruction as hex.
            if (op == OpDef.OpPEI_StackDPInd ||
                op == OpDef.OpSTY_DPIndexX ||
                op == OpDef.OpSTX_DPIndexY ||
                op.AddrMode == OpDef.AddressMode.DPIndLong ||
                op.AddrMode == OpDef.AddressMode.DPInd ||
                op.AddrMode == OpDef.AddressMode.DPIndexXInd)
            {
                FormatDescriptor dfd = Project.GetAnattrib(offset).DataDescriptor;
                if (dfd != null && dfd.HasSymbol)
                {
                    // It has a symbol.  See if the symbol target is a label (auto or user).
                    if (Project.SymbolTable.TryGetValue(dfd.SymbolRef.Label, out Symbol sym))
                    {
                        if (sym.IsInternalLabel)
                        {
                            return(null);
                        }
                    }
                }
            }

            return(string.Empty);
        }
Ejemplo n.º 5
0
	// Produces the C# inline documentation
	void GenDocs (OpDef oper)
	{
		p ("/// <summary>");
		Comment (oper.summary);
		p ("/// </summary>");
		foreach (var input in oper.input_arg) {
			p ($"/// <param name=\"{ParamMap (input.name)}\">");
			Comment (input.description);
			p ($"/// </param>");
		}
#if DOCS
		if (!return_is_tfoutput) {
			foreach (var attr in oper.output_arg) {
				if (String.IsNullOrEmpty (attr.description))
					continue;
				p ($"/// <param name=\"{ParamMap (attr.name)}\">");
				Comment (attr.description);
				p ($"/// </param>");
			}
		}
#endif
		p ("/// <param name=\"operName\">");
		p ($"///   If specified, the created operation in the graph will be this one, otherwise it will be named '{oper.name}'.");
		p ("/// </param>");
		foreach (var attr in optional_attrs) {
			p ($"/// <param name=\"{ParamMap (attr.name)}\">");
			Comment ("Optional argument");
			Comment (attr.description);
			p ($"/// </param>");
		}
		foreach (var attr in required_attrs) {
			p ($"/// <param name=\"{ParamMap (attr.name)}\">");
			Comment (attr.description);
			p ($"/// </param>");
		}
		p ($"/// <returns>");
		if (have_return_value) {
			if (oper.output_arg.Count == 1) {
				Comment (oper.output_arg.First ().description);
				Comment ("The TFOperation can be fetched from the resulting TFOutput, by fethching the Operation property from the result.");
			} else {
				Comment ("Returns a tuple with multiple values, as follows:");
				foreach (var arg in oper.output_arg) {
					Comment (ParamMap (arg.name) + ": " + arg.description);
				}

				Comment ("The TFOperation can be fetched from any of the TFOutputs returned in the tuple values, by fethching the Operation property.");
			}
		} else {
			Comment ("Returns the description of the operation");
		}
		p ($"/// </returns>");

		if (!String.IsNullOrEmpty (oper.description)) {
			p ("/// <remarks>");
			Comment (oper.description);
			p ("/// </remarks>");
		}
	}
Ejemplo n.º 6
0
    // Produces the C# inline documentation
    void GenDocs(OpDef oper)
    {
        p("/// <summary>");
        Comment(oper.summary);
        p("/// </summary>");
        foreach (var input in oper.input_arg)
        {
            if (String.IsNullOrEmpty(input.description))
            {
                continue;
            }
            p($"/// <param name=\"{ParamMap(input.name)}\">");
            Comment(input.description);
            p($"/// </param>");
        }
        if (!return_is_tfoutput)
        {
            foreach (var attr in oper.output_arg)
            {
                if (String.IsNullOrEmpty(attr.description))
                {
                    continue;
                }
                p($"/// <param name=\"{ParamMap (attr.name)}\">");
                Comment(attr.description);
                p($"/// </param>");
            }
        }
        p("/// <param name=\"operName\">");
        p($"///   If specified, the created operation in the graph will be this one, otherwise it will be named '{oper.name}'.");
        p("/// </param>");
        foreach (var attr in optional_attrs)
        {
            if (String.IsNullOrEmpty(attr.description))
            {
                continue;
            }
            p($"/// <param name=\"{ParamMap (attr.name)}\">");
            Comment("Optional argument");
            Comment(attr.description);
            p($"/// </param>");
        }

        if (return_is_tfoutput)
        {
            p($"/// <returns>");
            Comment(oper.output_arg.First().description);
            p($"/// </returns>");
        }
        if (!String.IsNullOrEmpty(oper.description))
        {
            p("/// <remarks>");
            Comment(oper.description);
            p("/// </remarks>");
        }
    }
Ejemplo n.º 7
0
    void SetupArguments(OpDef def)
    {
        // Attributes related to the InputArg's type are inferred automatically
        // and are not exposed to the client.
        var inferred_input_args = new Dictionary <string, bool> ();

        required_attrs = new List <OpDef.AttrDef> ();
        optional_attrs = new List <OpDef.AttrDef> ();

        foreach (var argdef in def.input_arg)
        {
            if (argdef.type_attr != "")
            {
                inferred_input_args [argdef.type_attr] = true;
            }
            else if (argdef.type_list_attr != "")
            {
                inferred_input_args [argdef.type_list_attr] = true;
            }
            if (argdef.number_attr != "")
            {
                inferred_input_args [argdef.number_attr] = true;
            }
        }
        foreach (var attr in def.attr)
        {
            if (inferred_input_args.ContainsKey(attr.name))
            {
                continue;
            }
            if (attr.default_value == null)
            {
                required_attrs.Add(attr);
            }
            else
            {
                optional_attrs.Add(attr);
            }
        }
        // API: currently, if we have a single ref TFOutput result, we make the signature of the
        // function return that TFOutput instead of the TFOperation (as you can get the TFOperation
        // from the TFOutput anyways.
        //
        // When we move to tuples, we could probably put everything in a Tuple result, but for now
        // mult-return functions will just return all outputs on ref variables, instead of the first
        // as a ref, and the rest as TFOutputs.
        //
        // This means that we generate methods like this:
        //    TFOutput Constant (....)
        // when there is a single output
        //
        //    TFOperation Foo (..)
        // When there is no result or more than one result.
        return_is_tfoutput = def.output_arg.Count == 1;
    }
Ejemplo n.º 8
0
 // IGenerator
 public string ReplaceMnemonic(OpDef op)
 {
     if (op.IsUndocumented)
     {
         return(null);
     }
     else
     {
         return(string.Empty);
     }
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Formats the instruction operand.
        /// </summary>
        /// <param name="op">Opcode definition (needed for address mode).</param>
        /// <param name="contents">Label or numeric operand value.</param>
        /// <param name="wdis">Width disambiguation value.</param>
        /// <returns>Formatted string.</returns>
        public string FormatOperand(OpDef op, string contents, OpDef.WidthDisambiguation wdis)
        {
            Debug.Assert(((int)op.AddrMode & 0xff) == (int)op.AddrMode);
            int key = (int)op.AddrMode | ((int)wdis << 8);

            if (!mOperandFormats.TryGetValue(key, out string format))
            {
                format = mOperandFormats[key] = GenerateOperandFormat(op.AddrMode, wdis);
            }
            return(string.Format(format, contents));
        }
Ejemplo n.º 10
0
 // IGenerator
 public string ModifyOpcode(int offset, OpDef op)
 {
     if (op == OpDef.OpBRK_StackInt)
     {
         if (mAsmVersion < V2_18)
         {
             // cc65 v2.17 assembles BRK <arg> to opcode $05
             // https://github.com/cc65/cc65/issues/716
             return(null);
         }
         else if (Project.CpuDef.Type != CpuDef.CpuType.Cpu65816)
         {
             // cc65 v2.18 only supports BRK <arg> on 65816 (?!)
             return(null);
         }
         else
         {
             return(string.Empty);
         }
     }
     else if (op == OpDef.OpWDM_WDM && mAsmVersion < V2_18)
     {
         // cc65 v2.17 doesn't support WDM
         // https://github.com/cc65/cc65/issues/715
         return(null);
     }
     else if (op.IsUndocumented)
     {
         if (sUndocMap.TryGetValue(op.Mnemonic, out string newValue))
         {
             if ((op.Mnemonic == OpName.ANC && op.Opcode != 0x0b) ||
                 (op.Mnemonic == OpName.JAM && op.Opcode != 0x02))
             {
                 // There are multiple opcodes for the same thing.  cc65 outputs
                 // one specific thing, so we need to match that, and just do a hex
                 // dump for the others.
                 return(null);
             }
             return(newValue);
         }
         // Unmapped values include DOP, TOP, and the alternate SBC.  Output hex.
         return(null);
     }
     else
     {
         return(string.Empty);
     }
 }
Ejemplo n.º 11
0
        public EditOperand(int offset, DisasmProject project, Asm65.Formatter formatter)
        {
            InitializeComponent();

            mProject   = project;
            mFormatter = formatter;

            // Configure the appearance.
            mAttr = mProject.GetAnattrib(offset);
            OpDef op = mProject.CpuDef.GetOpDef(mProject.FileData[offset]);

            mInstructionLength = mAttr.Length;
            mPreviewHexDigits  = (mAttr.Length - 1) * 2;
            if (mAttr.OperandAddress >= 0)
            {
                // Use this as the operand value when available.  This lets us present
                // relative branch instructions in the expected form.
                mOperandValue = mAttr.OperandAddress;

                if (op.AddrMode == OpDef.AddressMode.PCRel)
                {
                    mPreviewHexDigits = 4;
                    mIsPcRelative     = true;
                }
                else if (op.AddrMode == OpDef.AddressMode.PCRelLong ||
                         op.AddrMode == OpDef.AddressMode.StackPCRelLong)
                {
                    mIsPcRelative = true;
                }
            }
            else
            {
                int opVal = op.GetOperand(mProject.FileData, offset, mAttr.StatusFlags);
                mOperandValue = opVal;
                if (op.AddrMode == OpDef.AddressMode.BlockMove)
                {
                    // MVN and MVP screw things up by having two operands in one instruction.
                    // We deal with this by passing in the value from the second byte
                    // (source bank) as the value, and applying the chosen format to both bytes.
                    mIsBlockMove      = true;
                    mOperandValue     = opVal >> 8;
                    mPreviewHexDigits = 2;
                }
            }
            mIsExtendedImmediate = op.IsExtendedImmediate;   // Imm, PEA, MVN/MVP
            mShowHashPrefix      = op.IsImmediate;           // just Imm
        }
Ejemplo n.º 12
0
 // IGenerator
 public string ModifyOpcode(int offset, OpDef op)
 {
     if (op.IsUndocumented)
     {
         if (Project.CpuDef.Type == CpuDef.CpuType.Cpu65C02 ||
             Project.CpuDef.Type == CpuDef.CpuType.CpuW65C02)
         {
             // none of the "LDD" stuff is handled
             return(null);
         }
         if ((op.Mnemonic == OpName.ANC && op.Opcode != 0x0b) ||
             (op.Mnemonic == OpName.JAM && op.Opcode != 0x02))
         {
             // There are multiple opcodes that match the mnemonic.  Output the
             // mnemonic for the first one and hex for the rest.
             return(null);
         }
         else if (op.Mnemonic == OpName.NOP || op.Mnemonic == OpName.DOP ||
                  op.Mnemonic == OpName.TOP)
         {
             // the various undocumented no-ops aren't handled
             return(null);
         }
         else if (op.Mnemonic == OpName.SBC)
         {
             // this is the alternate reference to SBC
             return(null);
         }
         else if (op == OpDef.OpSHA_DPIndIndexY)
         {
             // not recognized ($93)
             if (mAsmVersion < V1_55)
             {
                 return(null);
             }
         }
     }
     if (op == OpDef.OpWDM_WDM)
     {
         // 64tass v1.53 doesn't know what this is.
         // 64tass v1.55 doesn't like this to have an operand.
         // Output as hex.
         return(null);
     }
     return(string.Empty);        // indicate original is fine
 }
Ejemplo n.º 13
0
 private static void InternalValidate(CpuDef cdef)
 {
     for (int i = 0; i < 256; i++)
     {
         OpDef op = cdef.mOpDefs[i];
         if (op.Opcode != i && op.AddrMode != OpDef.AddressMode.Unknown)
         {
             throw new Exception("CpuDef for " + cdef.Type + ": entry 0x" +
                                 i.ToString("x") + " has value " + op.Opcode.ToString("x"));
         }
         if (op.AddrMode != OpDef.AddressMode.Unknown && op.Cycles == 0)
         {
             throw new Exception("Instruction 0x" + i.ToString("x2") + ": " +
                                 op + " missing cycles");
         }
     }
 }
Ejemplo n.º 14
0
 // IGenerator
 public string ModifyOpcode(int offset, OpDef op)
 {
     if (op.IsUndocumented)
     {
         if (Project.CpuDef.Type == CpuDef.CpuType.Cpu65C02 ||
             Project.CpuDef.Type == CpuDef.CpuType.CpuW65C02)
         {
             // none of the "LDD" stuff is handled
             return(null);
         }
         if ((op.Mnemonic == OpName.ANC && op.Opcode != 0x0b) ||
             (op.Mnemonic == OpName.JAM && op.Opcode != 0x02))
         {
             // There are multiple opcodes that match the mnemonic.  Output the
             // mnemonic for the first one and hex for the rest.
             return(null);
         }
         else if (op.Mnemonic == OpName.NOP || op.Mnemonic == OpName.DOP ||
                  op.Mnemonic == OpName.TOP)
         {
             // the various undocumented no-ops aren't handled
             return(null);
         }
         else if (op.Mnemonic == OpName.SBC)
         {
             // this is the alternate reference to SBC
             return(null);
         }
         else if (op == OpDef.OpALR_Imm)
         {
             // ACME wants "ASR" instead for $4b
             return("asr");
         }
         else if (op == OpDef.OpLAX_Imm)
         {
             // ACME spits out an error on $ab
             return(null);
         }
     }
     if (op == OpDef.OpWDM_WDM || op == OpDef.OpBRK_StackInt)
     {
         // ACME doesn't like these to have an operand.  Output as hex.
         return(null);
     }
     return(string.Empty);        // indicate original is fine
 }
Ejemplo n.º 15
0
        /// <summary>
        /// Formats the instruction opcode mnemonic, and caches the result.
        ///
        /// It may be necessary to modify the mnemonic for some assemblers, e.g. LDA from a
        /// 24-bit address might need to be LDAL, even if the high byte is nonzero.
        /// </summary>
        /// <param name="op">Opcode to format</param>
        /// <param name="wdis">Width disambiguation specifier.</param>
        /// <returns>Formatted string.</returns>
        public string FormatOpcode(OpDef op, OpDef.WidthDisambiguation wdis)
        {
            // TODO(someday): using op.Opcode as the key is a bad idea, as the operation may
            // not be the same on different CPUs.  We currently rely on the caller to discard
            // the Formatter when the CPU definition changes.  We'd be better off keying off of
            // the OpDef object and factoring wdis in some other way.
            int key = op.Opcode | ((int)wdis << 8);

            if (!mOpcodeStrings.TryGetValue(key, out string opcodeStr))
            {
                // Not found, generate value.
                opcodeStr = FormatMnemonic(op.Mnemonic, wdis);

                // Memoize.
                mOpcodeStrings[key] = opcodeStr;
            }
            return(opcodeStr);
        }
Ejemplo n.º 16
0
        // IGenerator
        public string ModifyOpcode(int offset, OpDef op)
        {
            if (op.IsUndocumented)
            {
                return(null);
            }
            if (Project.CpuDef.Type == CpuDef.CpuType.CpuW65C02)
            {
                if ((op.Opcode & 0x0f) == 0x07 || (op.Opcode & 0x0f) == 0x0f)
                {
                    // BBR, BBS, RMB, SMB not supported
                    return(null);
                }
            }

            // The assembler works correctly if the symbol is defined as a two-digit hex
            // value (e.g. "foo equ $80") but fails if it's four (e.g. "foo equ $0080").  We
            // output symbols with minimal digits, but this doesn't help if the code itself
            // lives on zero page.  If the operand is a reference to a zero-page user label,
            // we need to output the instruction as hex.
            // More info: https://github.com/apple2accumulator/merlin32/issues/8
            if (op == OpDef.OpPEI_StackDPInd ||
                op == OpDef.OpSTY_DPIndexX ||
                op == OpDef.OpSTX_DPIndexY ||
                op.AddrMode == OpDef.AddressMode.DPIndLong ||
                op.AddrMode == OpDef.AddressMode.DPInd ||
                op.AddrMode == OpDef.AddressMode.DPIndexXInd)
            {
                FormatDescriptor dfd = Project.GetAnattrib(offset).DataDescriptor;
                if (dfd != null && dfd.HasSymbol)
                {
                    // It has a symbol.  See if the symbol target is a label (auto or user).
                    if (Project.SymbolTable.TryGetValue(dfd.SymbolRef.Label, out Symbol sym))
                    {
                        if (sym.IsInternalLabel)
                        {
                            return(null);
                        }
                    }
                }
            }

            return(string.Empty);
        }
Ejemplo n.º 17
0
        private void SetupArguments(OpDef opDef)
        {
            // Attributes related to the InputArg's type are not exposed.
            var inferredInputArgs = new List <string>();

            _requiredAttrs = new List <OpDef.AttrDef>();
            _optionalAttrs = new List <OpDef.AttrDef>();

            foreach (var argdef in opDef.InputArgs)
            {
                if (argdef.TypeAttr != "")
                {
                    inferredInputArgs.Add(argdef.TypeAttr);
                }

                if (argdef.TypeListAttr != "")
                {
                    inferredInputArgs.Add(argdef.TypeListAttr);
                }

                if (argdef.NumberAttr != "")
                {
                    inferredInputArgs.Add(argdef.NumberAttr);
                }
            }

            foreach (var attr in opDef.Attrs)
            {
                if (!inferredInputArgs.Contains(attr.Name))
                {
                    if (attr.DefaultValue == null)
                    {
                        _requiredAttrs.Add(attr);
                    }
                    else
                    {
                        _optionalAttrs.Add(attr);
                    }
                }
            }

            _haveReturnValue = opDef.OutputArgs.Count > 0;
        }
Ejemplo n.º 18
0
        private string FillArguments(OpDef opDef)
        {
            var    sb    = new StringBuilder();
            string comma = "";

            foreach (var inArg in opDef.InputArgs)
            {
                string type = "Output!" + (IsListArg(inArg) ? "[]" : "");
                sb.AppendFormat($"{comma}{type} {ParamMap(inArg.Name)}");
                comma = ", ";
            }

            foreach (var attr in _requiredAttrs)
            {
                bool isRefType    = IsReferenceType(attr.Type);
                var  cstype       = CSharpType(attr.Type);
                var  cstypeSuffix = isRefType ? "!" : "";
                sb.AppendFormat($"{comma}{cstype}{cstypeSuffix} {ParamMap(attr.Name)}");
                comma = ", ";
            }

            foreach (var attr in _optionalAttrs)
            {
                bool isRefType    = IsReferenceType(attr.Type);
                var  cstype       = CSharpType(attr.Type);
                var  cstypeSuffix = isRefType ? "" : "?";

                sb.AppendFormat($"{comma}{cstype}{cstypeSuffix} {ParamMap(attr.Name)} = null");
                comma = ", ";
            }

            if (sb.Length != 0)
            {
                sb.Append(", ");
            }

            return(sb.ToString());
        }
Ejemplo n.º 19
0
        private static String CodeGen(OpDef op)
        {
            String defaultStr = String.Format("{1}// Skipped function {0}", op.Name, _sixSpaces);

            if (op.Name.StartsWith("_"))
            {
                return(defaultStr);
            }

            //if (op.name.Equals("PaddingFIFOQueueV2"))
            {
                StringBuilder document = new StringBuilder(
                    String.Format("{0}{2}///<summary>{0}{2}///{1}{0}{2}///</summary>{0}",
                                  Environment.NewLine,
                                  CleanUpDescription(op.Summary),
                                  _sixSpaces));
                var outputs = op.OutputArg;

                String[] returnDescs = new string[outputs.Count];
                for (int i = 0; i < outputs.Count; i++)
                {
                    returnDescs[i] = String.Format("{4}///{3} {0}(type: {1}){2}",
                                                   outputs[i].Name,
                                                   outputs[i].Type,
                                                   String.IsNullOrEmpty(CleanUpDescription(outputs[i].Description))
                            ? "."
                            : ": " + CleanUpDescription(outputs[i].Description),
                                                   outputs.Count > 0 ? String.Format("[{0}]", i) : String.Empty,
                                                   _sixSpaces);
                }
                String returnDoc = String.Join(Environment.NewLine, returnDescs);
                returnDoc = String.Format("{2}///<return>{0}{1}{0}{2}///</return>{0}", Environment.NewLine, returnDoc, _sixSpaces);
                if (outputs.Count == 0)
                {
                    returnDoc = String.Empty;
                }


                String returnStr = "Operation";

                var inputs = op.InputArg;

                List <String> inputsStrList = new List <string>();
                foreach (var input in inputs)
                {
                    string inputDescription = CleanUpDescription(input.Description);
                    document.AppendFormat("{4}///<param name=\"{0}\">Input to the operation{3} {1}</param>{2}", FixParamName(input.Name), inputDescription, Environment.NewLine, String.IsNullOrEmpty(inputDescription) ? "." : ":", _sixSpaces);
                    inputsStrList.Add(String.Format(" {0} {1} ", "Output", FixParamName(input.Name)));
                }

                String inputsStr = String.Join(",", inputsStrList);

                var attr = op.Attr;
                List <OpDef.Types.AttrDef> unknownAttr = new List <OpDef.Types.AttrDef>();
                List <OpDef.Types.AttrDef> knownAttr   = new List <OpDef.Types.AttrDef>();
                foreach (var a in attr)
                {
                    if (IsTypeKnown(a.Type))
                    {
                        knownAttr.Add(a);
                    }
                    else
                    {
                        unknownAttr.Add(a);
                    }
                }

                var requiredAttr = knownAttr.FindAll(a => a.DefaultValue == null);
                var optionalAttr = knownAttr.FindAll(a => a.DefaultValue != null);

                foreach (var iarg in op.InputArg)
                {
                    if (iarg.TypeAttr != "")
                    {
                        requiredAttr.RemoveAll(a => a.Name.Equals(iarg.TypeAttr));
                        optionalAttr.RemoveAll(a => a.Name.Equals(iarg.TypeAttr));
                    }

                    if (iarg.TypeListAttr != "")
                    {
                        requiredAttr.RemoveAll(a => a.Name.Equals(iarg.TypeListAttr));
                        optionalAttr.RemoveAll(a => a.Name.Equals(iarg.TypeListAttr));
                    }

                    if (iarg.NumberAttr != "")
                    {
                        requiredAttr.RemoveAll(a => a.Name.Equals(iarg.NumberAttr));
                        optionalAttr.RemoveAll(a => a.Name.Equals(iarg.NumberAttr));
                    }
                }
                foreach (var required in requiredAttr)
                {
                    document.AppendFormat("{3}///<param name=\"{0}\">{1}</param>{2}", FixParamName(required.Name), CleanUpDescription(required.Description), Environment.NewLine, _sixSpaces);
                }
                foreach (var optional in optionalAttr)
                {
                    document.AppendFormat("{3}///<param name=\"{0}\">{1}</param>{2}", FixParamName(optional.Name), CleanUpDescription(optional.Description), Environment.NewLine, _sixSpaces);
                }

                document.AppendFormat("{0}///<param name=\"opName\">The name of the operation</param>{1}", _sixSpaces,
                                      Environment.NewLine);
                document.Append(returnDoc);

                if (unknownAttr.Count > 0)
                {
                    document.AppendFormat("{2}//The following attributes are not known: {1}{0}",
                                          Environment.NewLine,
                                          String.Join("; ", unknownAttr.ConvertAll(a => String.Format("{0}: {1}", a.Name, a.Type))),
                                          _sixSpaces);
                }

                String requiredStr = String.Join(",", requiredAttr.ConvertAll <String>(
                                                     a =>
                {
                    String isTypeList = IsTypeList(a.Type);
                    if (String.IsNullOrEmpty(isTypeList))
                    {
                        return(String.Format(" {0} {1}", _typeMap[a.Type], a.Name));
                    }
                    else
                    {
                        return(String.Format(" {0}[] {1}", _typeMap[isTypeList], a.Name));
                    }
                }));
                String optionalStr = String.Join(",", optionalAttr.ConvertAll <String>(
                                                     a =>
                {
                    String isTypeList = IsTypeList(a.Type);
                    if (String.IsNullOrEmpty(isTypeList))
                    {
                        if (_typeIsStruct[a.Type])
                        {
                            if (a.Type.Equals("int"))
                            {
                                return(String.Format(" {0} {1} = {2} ", _typeMap[a.Type], a.Name, a.DefaultValue.I));
                            }
                            else if (a.Type.Equals("bool"))
                            {
                                return(String.Format(" {0} {1} = {2} ", _typeMap[a.Type], a.Name, a.DefaultValue.B ? "true" : "false"));
                            }
                            else if (a.Type.Equals("float"))
                            {
                                String valueString = a.DefaultValue.F.ToString();
                                if (Single.IsPositiveInfinity(a.DefaultValue.F))
                                {
                                    valueString = "Single.PositiveInfinity";
                                }
                                else if (Single.IsNegativeInfinity(a.DefaultValue.F))
                                {
                                    valueString = "Single.NegativeInfinity";
                                }
                                else
                                {
                                    valueString = valueString + "f";
                                }

                                String res = String.Format(" {0} {1} = {2} ", _typeMap[a.Type], a.Name, valueString);
                                return(res);
                            }
                            else
                            {
                                return(String.Format(" {0}? {1} = null ", _typeMap[a.Type], a.Name));
                            }
                        }
                        else
                        {
                            return(String.Format(" {0} {1} = null ", _typeMap[a.Type], a.Name));
                        }
                    }
                    else
                    {
                        return(String.Format(" {0}[] {1} = null ", _typeMap[isTypeList], a.Name));
                    }
                }));

                List <string> paramList = new List <string>();
                if (!String.IsNullOrEmpty(inputsStr))
                {
                    paramList.Add(inputsStr);
                }
                if (!String.IsNullOrEmpty(requiredStr))
                {
                    paramList.Add(requiredStr);
                }
                if (!String.IsNullOrEmpty(optionalStr))
                {
                    paramList.Add(optionalStr);
                }
                paramList.Add(String.Format("String opName= \"{0}\"", op.Name));
                String paramStr = String.Join(",", paramList);

                StringBuilder body = new StringBuilder(String.Format(
                                                           "{2}OperationDescription desc = NewOperation(\"{0}\", opName);{1}",
                                                           op.Name,
                                                           Environment.NewLine,
                                                           _nineSpaces));
                List <String> addInputStringList = new List <string>();
                foreach (var i in inputs)
                {
                    addInputStringList.Add(String.Format("{1}desc.AddInput({0});", FixParamName(i.Name), _nineSpaces));
                }
                body.Append(String.Join(Environment.NewLine, addInputStringList));
                body.Append(Environment.NewLine);
                body.Append(String.Join(Environment.NewLine, requiredAttr.ConvertAll(RequiredAttrToString)));
                body.Append(Environment.NewLine);
                body.Append(String.Join(Environment.NewLine, optionalAttr.ConvertAll(OptionalAttrToString)));
                body.Append(Environment.NewLine);
                body.Append(String.Format("{0}return desc.FinishOperation();", _nineSpaces));
                String code = String.Format("{5}public {0} {1} ( {2} ) {3}{5}{{{3}{4}{3}{5}}} ", returnStr, op.Name, paramStr, Environment.NewLine, body.ToString(), _sixSpaces);
                return(String.Format("{0}{1}", document, code));
            }
        }
Ejemplo n.º 20
0
    /// <summary>
    /// Generate the specified oper.
    /// </summary>
    /// <param name="oper">Oper.</param>
    void Generate(OpDef oper)
    {
        SetupArguments(oper);
        GenDocs(oper);

        var    name = oper.name;
        string retType;

        if (have_return_value)
        {
            if (oper.output_arg.Count > 1)
            {
                var rb = new StringBuilder("(");
                foreach (var arg in oper.output_arg)
                {
                    rb.AppendFormat("TFOutput{0} {1}, ", IsListArg(arg) ? "[]" : "", ParamMap(arg.name));
                }
                rb.Remove(rb.Length - 2, 2);
                rb.Append(")");
                retType = rb.ToString();
            }
            else
            {
                retType = "TFOutput" + (IsListArg(oper.output_arg.First()) ? "[]" : "");
            }
        }
        else
        {
            retType = "TFOperation";
        }

        p($"public {retType} {name} ({FillArguments(oper)}string operName = null)");
        pi("{");
        bool needStatus = required_attrs.Concat(optional_attrs).Any(attr => attr.type.Contains("TFTensor"));

        p($"var desc = new TFOperationDesc (this, \"{oper.name}\", MakeName (\"{oper.name}\", operName));");
        foreach (var arg in oper.input_arg)
        {
            if (IsListArg(arg))
            {
                p($"desc.AddInputs ({ParamMap (arg.name)});");
            }
            else
            {
                p($"desc.AddInput ({ParamMap (arg.name)});");
            }
        }

        pi("foreach ( TFOperation control in CurrentDependencies )");
        p("desc.AddControlInput (control);");
        pd("");

        // If we have attributes
        if (required_attrs.Count > 0 || optional_attrs.Count > 0)
        {
            foreach (var attr in required_attrs)
            {
                SetAttribute(attr.type, attr.name, ParamMap(attr.name));
            }

            foreach (var attr in optional_attrs)
            {
                var reftype = IsReferenceType(attr.type);
                var csattr  = ParamMap(attr.name);
                if (reftype)
                {
                    pi($"if ({csattr} != null)");
                }
                else
                {
                    pi($"if ({csattr}.HasValue)");
                }
                SetAttribute(attr.type, attr.name, csattr + (reftype ? "" : ".Value"));
                pd("");
            }
        }

        p("var op = desc.FinishOperation ();");
        if (oper.output_arg.Count() > 0)
        {
            p("int _idx = 0;");
        }
        if (oper.output_arg.Any(x => IsListArg(x)))
        {
            p("int _n = 0;");
        }
        foreach (var arg in oper.output_arg)
        {
            if (IsListArg(arg))
            {
                var outputs = new StringBuilder();
                p($"_n = op.OutputListLength (\"{ParamMap (arg.name)}\");");
                p($"var {ParamMap (arg.name)} = new TFOutput [_n];");
                pi("for (int i = 0; i < _n; i++)");
                p($"{ParamMap (arg.name)} [i] = new TFOutput (op, _idx++);");
                pd("");
            }
            else
            {
                p($"var {ParamMap (arg.name)} = new TFOutput (op, _idx++);");
            }
        }

        if (have_return_value)
        {
            if (oper.output_arg.Count == 1)
            {
                p($"return {ParamMap (oper.output_arg.First ().name)};");
            }
            else
            {
                ;
                p("return (" + oper.output_arg.Select(x => ParamMap(x.name)).Aggregate((i, j) => (i + ", " + j)) + ");");
            }
        }
        else
        {
            p("return op;");
        }
        pd("}\n");
    }
Ejemplo n.º 21
0
        private static void GenerateInstruction(IGenerator gen, StreamWriter sw,
                                                LocalVariableLookup lvLookup, 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.  For ACME, we don't
                // care if it's forward or not.
                if ((gen.Quirks.SinglePassNoLabelCorrection && IsLabelReference(gen, offset)) ||
                    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.OmitLabelPrefixSuffix;
            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) != 0)
            {
                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)
            {
                FormatDescriptor dfd = gen.ModifyInstructionOperandFormat(offset,
                                                                          attr.DataDescriptor, operand);

                // 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, dfd, operand >> 8, 1,
                                                                  PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                    string opstr2 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                  gen.Localizer.LabelMap, dfd, operand & 0xff, 1,
                                                                  PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                    if (gen.Quirks.BlockMoveArgsReversed)
                    {
                        string tmp = opstr1;
                        opstr1 = opstr2;
                        opstr2 = tmp;
                    }
                    string hash = gen.Quirks.BlockMoveArgsNoHash ? "" : "#";
                    formattedOperand = hash + opstr1 + "," + hash + opstr2;
                }
                else
                {
                    if (attr.DataDescriptor.IsStringOrCharacter)
                    {
                        gen.UpdateCharacterEncoding(dfd);
                    }
                    formattedOperand = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                     lvLookup, gen.Localizer.LabelMap, dfd,
                                                                     offset, 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;
                    }
                    string hash = gen.Quirks.BlockMoveArgsNoHash ? "" : "#";
                    formattedOperand = hash + formatter.FormatHexValue(arg1, 2) + "," +
                                       hash + 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);

            if (gen.Quirks.StackIntOperandIsImmediate && op.AddrMode == OpDef.AddressMode.StackInt)
            {
                // COP $02 is standard, but some require COP #$02
                operandStr = '#' + operandStr;
            }

            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)
                {
                    if (!string.IsNullOrEmpty(eolComment))
                    {
                        eolComment = cycles.ToString() + "  " + eolComment;
                    }
                    else
                    {
                        eolComment = cycles.ToString();
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(eolComment))
                    {
                        eolComment = (-cycles).ToString() + "+ " + eolComment;
                    }
                    else
                    {
                        eolComment = (-cycles).ToString() + "+";
                    }
                }
            }
            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);
                }
            }
        }
Ejemplo n.º 22
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);
            }

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

            string formattedOperand = null;
            int    operandLen       = instrLen - 1;
            bool   isPcRel          = false;
            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;
                isPcRel    = true;
            }
            else if (op.AddrMode == OpDef.AddressMode.PCRelLong ||
                     op.AddrMode == OpDef.AddressMode.StackPCRelLong)
            {
                isPcRel = true;
            }
            if (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 (?)
            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, false);
                    string opstr2 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                  gen.Localizer.LabelMap, attr.DataDescriptor, operand & 0xff, 1, false);
                    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, isPcRel);
                }
            }
            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);

            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);
                }
            }
        }
Ejemplo n.º 23
0
 public OpGenException(OpDef op, string msg) : base($"Error generating code for op {op.name}: {msg}.")
 {
 }
Ejemplo n.º 24
0
        private static void GenerateInstruction(IGenerator gen, StreamWriter sw,
                                                LocalVariableLookup lvLookup, 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.  For ACME, we don't
                // care if it's forward or not.
                if ((gen.Quirks.SinglePassNoLabelCorrection && IsLabelReference(gen, offset)) ||
                    IsForwardLabelReference(gen, offset))
                {
                    wdis = OpDef.WidthDisambiguation.ForceDirect;
                }
            }
            if (wdis == OpDef.WidthDisambiguation.ForceLongMaybe &&
                gen.Quirks.SinglePassAssembler &&
                IsForwardLabelReference(gen, offset))
            {
                // Assemblers like cc65 can't tell if a symbol reference is Absolute or
                // Long if they haven't seen the symbol yet.  Irrelevant for ACME, which
                // doesn't currently handle 65816 outside bank 0.
                wdis = OpDef.WidthDisambiguation.ForceLong;
            }

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

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

            PseudoOp.FormatNumericOpFlags opFlags =
                PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix;
            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.
            // Unless we're outside bank 0 on 65816, in which case most assemblers require
            // them to be 6-byte hex values.
            if (op.AddrMode == OpDef.AddressMode.PCRel ||
                op.AddrMode == OpDef.AddressMode.DPPCRel)
            {
                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) != 0)
            {
                int branchDist = attr.Address - attr.OperandAddress;
                isPcRelBankWrap = branchDist > 32767 || branchDist < -32768;
            }
            if (op.IsAbsolutePBR)
            {
                opFlags |= PseudoOp.FormatNumericOpFlags.IsAbsolutePBR;
            }
            if (gen.Quirks.BankZeroAbsPBRRestrict)
            {
                // Hack to avoid having to define a new FormatConfig.ExpressionMode for 64tass.
                // Get rid of this 64tass gets its own exp mode.
                opFlags |= PseudoOp.FormatNumericOpFlags.Is64Tass;
            }

            // 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)
            {
                FormatDescriptor dfd = gen.ModifyInstructionOperandFormat(offset,
                                                                          attr.DataDescriptor, operand);

                // 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, dfd, operand >> 8, 1,
                                                                  PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                    string opstr2 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                  gen.Localizer.LabelMap, dfd, operand & 0xff, 1,
                                                                  PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
                    if (gen.Quirks.BlockMoveArgsReversed)
                    {
                        string tmp = opstr1;
                        opstr1 = opstr2;
                        opstr2 = tmp;
                    }
                    string hash = gen.Quirks.BlockMoveArgsNoHash ? "" : "#";
                    formattedOperand = hash + opstr1 + "," + hash + opstr2;
                }
                else if (op.AddrMode == OpDef.AddressMode.DPPCRel)
                {
                    // Special handling for double-operand BBR/BBS.  The instruction generally
                    // behaves like a branch, so format that first.
                    string branchStr = PseudoOp.FormatNumericOperand(formatter,
                                                                     proj.SymbolTable, gen.Localizer.LabelMap, dfd,
                                                                     operandForSymbol, operandLen, opFlags);
                    string dpStr = formatter.FormatHexValue(operand & 0xff, 2);
                    formattedOperand = dpStr + "," + branchStr;
                }
                else
                {
                    if (attr.DataDescriptor.IsStringOrCharacter)
                    {
                        gen.UpdateCharacterEncoding(dfd);
                    }
                    formattedOperand = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
                                                                     lvLookup, gen.Localizer.LabelMap, dfd,
                                                                     offset, 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;
                    }
                    string hash = gen.Quirks.BlockMoveArgsNoHash ? "" : "#";
                    formattedOperand = hash + formatter.FormatHexValue(arg1, 2) + "," +
                                       hash + formatter.FormatHexValue(arg2, 2);
                }
                else if (op.AddrMode == OpDef.AddressMode.DPPCRel)
                {
                    formattedOperand = formatter.FormatHexValue(operand & 0xff, 2) + "," +
                                       formatter.FormatHexValue(operandForSymbol, operandLen * 2);
                }
                else
                {
                    if (operandLen == 2 && !(op.IsAbsolutePBR && gen.Quirks.Need24BitsForAbsPBR) &&
                        (opFlags & PseudoOp.FormatNumericOpFlags.IsPcRel) == 0)
                    {
                        // 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.  We may need it for JSR/JMP though,
                        // and the bank is required for relative branch instructions.
                        operandForSymbol &= 0xffff;
                    }
                    formattedOperand = formatter.FormatHexValue(operandForSymbol, operandLen * 2);
                }
            }
            string operandStr = formatter.FormatOperand(op, formattedOperand, wdis);

            if (gen.Quirks.StackIntOperandIsImmediate &&
                op.AddrMode == OpDef.AddressMode.StackInt)
            {
                // COP $02 is standard, but some require COP #$02
                operandStr = '#' + operandStr;
            }

            // The BBR/BBS/RMB/SMB instructions include a bit index (0-7).  The standard way is
            // to make it part of the mnemonic, but some assemblers make it an argument.
            if (gen.Quirks.BitNumberIsArg && op.IsNumberedBitOp)
            {
                // Easy way: do some string manipulation.
                char bitIndex = opcodeStr[opcodeStr.Length - 1];
                opcodeStr  = opcodeStr.Substring(0, opcodeStr.Length - 1);
                operandStr = bitIndex.ToString() + "," + operandStr;
            }

            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)
                {
                    if (!string.IsNullOrEmpty(eolComment))
                    {
                        eolComment = cycles.ToString() + "  " + eolComment;
                    }
                    else
                    {
                        eolComment = cycles.ToString();
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(eolComment))
                    {
                        eolComment = (-cycles).ToString() + "+ " + eolComment;
                    }
                    else
                    {
                        eolComment = (-cycles).ToString() + "+";
                    }
                }
            }
            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.
                // TODO: in some odd situations we can split something that doesn't need
                //   to be split (see note at end of #107).  Working around the problem at
                //   this stage is a little awkward because I think we need to check for the
                //   presence of labels on one or more later lines.
                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.IsEmulationMode)
                {
                    gen.OutputRegWidthDirective(offset, 0, 0, 1, 1);
                }
            }
        }
Ejemplo n.º 25
0
        private void GenDocs(OpDef opDef)
        {
            var api = _apimap.Get(opDef.Name);

            P("/// <summary>");
            Comment(api.Summary);
            P("/// </summary>");
            foreach (var input in api.InArgs)
            {
                P($"/// <param name=\"{ParamMap(input.Name)}\">");
                Comment(input.Description);
                P($"/// </param>");
            }

            P("/// <param name=\"opName\">");
            P($"///   If specified, the created operation in the graph will be this one, otherwise it will be named '{opDef.Name}'.");
            P("/// </param>");

            foreach (var attr in _optionalAttrs)
            {
                P($"/// <param name=\"{ParamMap(attr.Name)}\">");
                Comment("Optional argument");

                Comment(api.Attrs.Where(x => x.Name == attr.Name).FirstOrDefault().Description);
                P($"/// </param>");
            }

            foreach (var attr in _requiredAttrs)
            {
                P($"/// <param name=\"{ParamMap(attr.Name)}\">");
                Comment(api.Attrs.Where(x => x.Name == attr.Name).FirstOrDefault().Description);
                P($"/// </param>");
            }

            P($"/// <returns>");

            if (_haveReturnValue)
            {
                if (opDef.OutputArgs.Count == 1)
                {
                    Comment(api.OutArgs.First().Description);
                    Comment("The Operation can be fetched from the resulting Output, by fetching the Operation property from the result.");
                }
                else
                {
                    Comment("Returns a tuple with multiple values, as follows:");
                    foreach (var arg in opDef.OutputArgs)
                    {
                        var oapi = api.OutArgs.Where(x => x.Name == arg.Name).FirstOrDefault();
                        Comment(ParamMap(arg.Name) + ": " + oapi.Description);
                    }

                    Comment("The Operation can be fetched from any of the Outputs returned in the tuple values, by fetching the Operation property.");
                }
            }
            else
            {
                Comment("Returns the description of the operation");
            }

            P($"/// </returns>");

            if (!String.IsNullOrEmpty(api.Description))
            {
                P("/// <remarks>");
                Comment(api.Description);
                P("/// </remarks>");
            }
        }
Ejemplo n.º 26
0
        private void Generate(OpDef opDef)
        {
            SetupArguments(opDef);
            GenDocs(opDef);

            var    name = opDef.Name;
            string retType;

            if (_haveReturnValue)
            {
                if (opDef.OutputArgs.Count > 1)
                {
                    var sb = new StringBuilder("(");

                    foreach (var arg in opDef.OutputArgs)
                    {
                        sb.AppendFormat("Output{0} {1}, ", IsListArg(arg) ? "[]" : "", ParamMap(arg.Name));
                    }

                    sb.Remove(sb.Length - 2, 2);
                    sb.Append(")");
                    retType = sb.ToString();
                }
                else
                {
                    retType = "Output" + (IsListArg(opDef.OutputArgs.First()) ? "[]" : "");
                }
            }
            else
            {
                retType = "Operation";
            }

            P($"public {retType} {name}({FillArguments(opDef)}string opName = null)");
            PI("{");
            bool needStatus = _requiredAttrs.Concat(_optionalAttrs).Any(attr => attr.Type.Contains("Tensor"));

            P($"var desc = new OperationDescription withGraph(this) OpType(\"{opDef.Name}\") OpName(MakeName(\"{opDef.Name}\", opName));");

            foreach (var arg in opDef.InputArgs)
            {
                if (IsListArg(arg))
                {
                    P($"desc.AddInputs({ParamMap(arg.Name)});");
                }
                else
                {
                    P($"desc.AddInput({ParamMap(arg.Name)});");
                }
            }

            P(" ");
            PI("foreach (Operation control in CurrentDependencies) {");
            P("desc.AddControlInput(control);");
            PD("}\n");

            // If we have attributes
            if (_requiredAttrs.Count > 0 || _optionalAttrs.Count > 0)
            {
                foreach (var attr in _requiredAttrs)
                {
                    SetAttribute(attr.Type, attr.Name, ParamMap(attr.Name));
                }

                if (_requiredAttrs.Count > 0)
                {
                    P("");
                }

                foreach (var attr in _optionalAttrs)
                {
                    var reftype = IsReferenceType(attr.Type);
                    var csattr  = ParamMap(attr.Name);

                    if (reftype)
                    {
                        PI($"if ({csattr} != null) {{");
                    }
                    else
                    {
                        PI($"if ({csattr}.HasValue) {{");
                    }

                    //SetAttribute(attr.Type, attr.Name, csattr + (reftype ? "" : ".Value"));
                    SetAttribute(attr.Type, attr.Name, csattr);
                    PD("}\n");
                }
            }

            PI("using (var status = new Status()) {");
            P("var (success, op) = desc.FinishOperation(status);");
            PI("if(!success) {");
            P($"throw new OpCreateException withOpType(\"{opDef.Name}\") Error(status.Message);");
            PD("}");

            if (opDef.OutputArgs.Count() > 0)
            {
                P("int _idx = 0;");
            }

            if (opDef.OutputArgs.Any(x => IsListArg(x)))
            {
                P("int _n = 0;");
            }

            foreach (var arg in opDef.OutputArgs)
            {
                if (IsListArg(arg))
                {
                    var outputs = new StringBuilder();
                    P($"_n = op.GetOutputListLength(\"{ParamMap(arg.Name)}\");");
                    P($"var {ParamMap(arg.Name)} = new Output[_n];");
                    PI("for (int i = 0; i < _n; i++) {");
                    P($"{ParamMap(arg.Name)} [i] = new Output withOp(op) Index(_idx++);");
                    PD("}\n");
                }
                else
                {
                    P($"var {ParamMap(arg.Name)} = new Output withOp(op) Index(_idx++);");
                }
            }

            if (_haveReturnValue)
            {
                if (opDef.OutputArgs.Count == 1)
                {
                    P($"return {ParamMap(opDef.OutputArgs.First().Name)};");
                }
                else
                {
                    ;
                    P("return (" + opDef.OutputArgs.Select(x => ParamMap(x.Name)).Aggregate((i, j) => (i + ", " + j)) + ");");
                }
            }
            else
            {
                P("return op;");
            }

            PD("}");
            PD("}\n");
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Generates the mCycleCounts and mCycleMods arrays.
        /// </summary>
        private void GenerateCycleCounts()
        {
            if (mCycleCounts != null)
            {
                return;
            }
            mCycleCounts = new int[256];
            mCycleMods   = new OpDef.CycleMod[256];

            // Figure out which mods apply for this CPU.
            OpDef.CycleMod ignoreMask = 0;
            switch (Type)
            {
            case CpuType.Cpu6502:
                ignoreMask = OpDef.CycleMod.OneIfM0 |
                             OpDef.CycleMod.TwoIfM0 |
                             OpDef.CycleMod.OneIfX0 |
                             OpDef.CycleMod.OneIfDpNonzero |
                             OpDef.CycleMod.OneIfD1 |
                             OpDef.CycleMod.OneIfE0 |
                             OpDef.CycleMod.OneIf65C02 |
                             OpDef.CycleMod.MinusOneIfNoPage |
                             OpDef.CycleMod.BlockMove;
                break;

            case CpuType.Cpu65C02:
                ignoreMask = OpDef.CycleMod.OneIfM0 |
                             OpDef.CycleMod.TwoIfM0 |
                             OpDef.CycleMod.OneIfX0 |
                             OpDef.CycleMod.OneIfDpNonzero |
                             OpDef.CycleMod.OneIfE0 |
                             OpDef.CycleMod.BlockMove;
                break;

            case CpuType.Cpu65816:
                ignoreMask = OpDef.CycleMod.OneIfD1 |
                             OpDef.CycleMod.OneIf65C02 |
                             OpDef.CycleMod.MinusOneIfNoPage;
                break;

            default:
                Debug.Assert(false, "unsupported cpu type " + Type);
                return;
            }

            // If an instruction has one or more applicable mods, declare it as variable.
            for (int i = 0; i < 256; i++)
            {
                OpDef          op         = mOpDefs[i];
                int            baseCycles = op.Cycles;
                OpDef.CycleMod mods       = op.CycleMods & ~ignoreMask;
                if ((mods & OpDef.CycleMod.OneIf65C02) != 0)
                {
                    // This isn't variable -- the instruction always takes one cycle longer
                    // on the 65C02.  (Applies to $6C, JMP (addr).)
                    Debug.Assert(Type == CpuType.Cpu65C02);
                    baseCycles++;
                    mods &= ~OpDef.CycleMod.OneIf65C02;
                }
                mCycleCounts[i] = baseCycles;
                mCycleMods[i]   = mods;
            }
        }
Ejemplo n.º 28
0
    /// <summary>
    /// Generate the specified oper.
    /// </summary>
    /// <param name="oper">Oper.</param>
    void Generate(OpDef oper)
    {
        SetupArguments(oper);
        GenDocs(oper);

        var    name = oper.name;
        string retType;

        if (return_is_tfoutput)
        {
            if (oper.output_arg.Any(x => IsListArg(x)))
            {
                retType = "TFOutput []";
            }
            else
            {
                retType = "TFOutput";
            }
        }
        else
        {
            retType = "TFOperation";
        }


        p($"public {retType} {name} ({FillArguments(oper)}string operName = null)");
        pi("{");
        bool needStatus = required_attrs.Concat(optional_attrs).Any(attr => attr.type.Contains("TFTensor"));

        p($"var desc = new TFOperationDesc (this, \"{oper.name}\", MakeName (\"{oper.name}\", operName));");
        foreach (var arg in oper.input_arg)
        {
            if (IsListArg(arg))
            {
                p($"desc.AddInputs ({ParamMap (arg.name)});");
            }
            else
            {
                p($"desc.AddInput ({ParamMap (arg.name)});");
            }
        }

        // If we have attributes
        if (required_attrs.Count > 0 || optional_attrs.Count > 0)
        {
            foreach (var attr in required_attrs)
            {
                SetAttribute(attr.type, attr.name, ParamMap(attr.name));
            }

            foreach (var attr in optional_attrs)
            {
                var reftype = IsReferenceType(attr.type);
                var csattr  = ParamMap(attr.name);
                if (reftype)
                {
                    pi($"if ({csattr} != null)");
                }
                else
                {
                    pi($"if ({csattr}.HasValue)");
                }
                SetAttribute(attr.type, attr.name, csattr + (reftype ? "" : ".Value"));
                pd("");
            }
        }

        p("var op = desc.FinishOperation ();");
        if (oper.output_arg.Any(x => IsListArg(x)))
        {
            p("int _idx = 0, _n = 0;");
            foreach (var arg in oper.output_arg)
            {
                string retDecl = "", retOutput;

                if (return_is_tfoutput)
                {
                    retDecl   = "var ";
                    retOutput = "_ret";
                }
                else
                {
                    retOutput = ParamMap(arg.name);
                }

                if (IsListArg(arg))
                {
                    var outputs = new StringBuilder();
                    p($"_n = op.OutputListLength (\"{arg.name}\");");
                    p($"{retDecl}{retOutput} = new TFOutput [_n];");
                    pi("for (int i = 0; i < _n; i++)");
                    p($"{retOutput} [i] = new TFOutput (op, _idx++);");
                    pd("");
                    if (return_is_tfoutput)
                    {
                        p($"return {retOutput};");
                    }
                }
                else
                {
                    if (return_is_tfoutput)
                    {
                        p($"return  new TFOutput (op, _idx++);");
                    }
                    else
                    {
                        p($"{retOutput} = new TFOutput (op, _idx++);");
                    }
                }
            }
        }
        else
        {
            int idx = 0;
            foreach (var arg in oper.output_arg)
            {
                if (return_is_tfoutput)
                {
                    p($"return new TFOutput (op, 0);");
                }
                else
                {
                    p($"{ParamMap (arg.name)} = new TFOutput (op, {idx++});");
                }
            }
        }
        if (!return_is_tfoutput)
        {
            p("return op;");
        }
        pd("}\n");
    }
Ejemplo n.º 29
0
        private void UpdateControls()
        {
            CpuItem item = (CpuItem)cpuSelectionComboBox.SelectedItem;

            if (item == null)
            {
                // initializing
                return;
            }

            // Push current choice to settings.
            AppSettings.Global.SetEnum(AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType),
                                       (int)item.Type);
            AppSettings.Global.SetBool(AppSettings.INSTCH_SHOW_UNDOC, mShowUndocumented);

            // Populate the items source.
            InstructionItems.Clear();
            CpuDef cpuDef = CpuDef.GetBestMatch(item.Type, true, false);

            for (int opc = 0; opc < 256; opc++)
            {
                OpDef op = cpuDef[opc];
                if (!mShowUndocumented && op.IsUndocumented)
                {
                    continue;
                }

                int    opLen       = op.GetLength(StatusFlags.AllIndeterminate);
                string sampleValue = "$12";
                if (op.AddrMode == OpDef.AddressMode.BlockMove)
                {
                    sampleValue = "#$12,#$34";
                }
                else if (opLen == 3)
                {
                    sampleValue = "$1234";
                }
                else if (opLen == 4)
                {
                    sampleValue = "$123456";
                }
                string instrSample = mFormatter.FormatMnemonic(op.Mnemonic,
                                                               OpDef.WidthDisambiguation.None) + " " +
                                     mFormatter.FormatOperand(op, sampleValue, OpDef.WidthDisambiguation.None);


                StringBuilder     flags         = new StringBuilder(8);
                const string      FLAGS         = "NVMXDIZC";
                Asm65.StatusFlags affectedFlags = op.FlagsAffected;
                for (int fl = 0; fl < 8; fl++)
                {
                    if (affectedFlags.GetBit((StatusFlags.FlagBits)(7 - fl)) >= 0)
                    {
                        flags.Append(FLAGS[fl]);
                    }
                    else
                    {
                        flags.Append("-");
                    }
                }

                string         cycles = op.Cycles.ToString();
                OpDef.CycleMod mods   = cpuDef.GetOpCycleMod(opc);
                if (mods != 0)
                {
                    cycles += '+';
                }

                InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(opc, 2),
                                                         instrSample, flags.ToString(), cycles,
                                                         mOpDesc.GetShortDescription(op.Mnemonic),
                                                         mOpDesc.GetAddressModeDescription(op.AddrMode),
                                                         op.IsUndocumented));
            }
        }
Ejemplo n.º 30
0
        private int FindAlternateTarget(int srcOffset, int targetOffset)
        {
            int origTargetOffset = targetOffset;

            // Is the target outside the instruction stream?  If it's just referencing data,
            // do a simple check and move on.
            if (!mAnattribs[targetOffset].IsInstruction)
            {
                // We want to use user-defined labels whenever possible.  If they're accessing
                // memory within a few bytes, use that.  We don't want to do this for
                // code references, though, or our branches will get all weird.
                // TODO(someday): make MAX user-configurable?  Seek forward as well as backward?
                const int MAX = 4;
                for (int probeOffset = targetOffset - 1;
                     probeOffset >= 0 && probeOffset != targetOffset - MAX; probeOffset--)
                {
                    Symbol sym = mAnattribs[probeOffset].Symbol;
                    if (sym != null && sym.SymbolSource == Symbol.Source.User)
                    {
                        // Found a nearby user label.  Make sure it's actually nearby.
                        int addrDiff = mAnattribs[targetOffset].Address -
                                       mAnattribs[probeOffset].Address;
                        if (addrDiff == targetOffset - probeOffset)
                        {
                            targetOffset = probeOffset;
                        }
                        else
                        {
                            Debug.WriteLine("NOT probing past address boundary change");
                        }
                        break;
                    }
                }
                return(targetOffset);
            }

            // Target is an instruction.  Is the source an instruction or data element
            // (e.g. ".dd2 <addr>").
            if (!mAnattribs[srcOffset].IsInstructionStart)
            {
                // Might be address-1 to set up an RTS.  If the target address isn't
                // an instruction start, check to see if the following byte is.
                if (!mAnattribs[targetOffset].IsInstructionStart &&
                    targetOffset + 1 < mAnattribs.Length &&
                    mAnattribs[targetOffset + 1].IsInstructionStart)
                {
                    LogD(srcOffset, "Offsetting address reference");
                    targetOffset++;
                }
                return(targetOffset);
            }

            // Source is an instruction, so we have an instruction referencing an instruction.
            // Could be a branch, an address push, or self-modifying code.
            OpDef op = mProject.CpuDef.GetOpDef(mProject.FileData[srcOffset]);

            if (op.IsBranch)
            {
                // Don't mess with jumps and branches -- always go directly to the
                // target address.
            }
            else if (op == OpDef.OpPEA_StackAbs || op == OpDef.OpPER_StackPCRelLong)
            {
                // They might be pushing address-1 to set up an RTS.  If the target address isn't
                // an instruction start, check to see if the following byte is.
                if (!mAnattribs[targetOffset].IsInstructionStart &&
                    targetOffset + 1 < mAnattribs.Length &&
                    mAnattribs[targetOffset + 1].IsInstructionStart)
                {
                    LogD(srcOffset, "Offsetting PEA/PER");
                    targetOffset++;
                }
            }
            else
            {
                // Data operation (LDA, STA, etc).  This could be self-modifying code, or
                // an indexed access with an offset base address (LDA addr-1,Y) to an
                // adjacent data area.  Check to see if there's data right after this.
                bool nearbyData = false;
                for (int i = targetOffset + 1; i <= targetOffset + 2; i++)
                {
                    if (i < mAnattribs.Length && !mAnattribs[i].IsInstruction)
                    {
                        targetOffset = i;
                        nearbyData   = true;
                        break;
                    }
                }
                if (!nearbyData && !mAnattribs[targetOffset].IsInstructionStart)
                {
                    // There's no data nearby, and the target is not the start of the
                    // instruction, so this is probably self-modifying code.  We want
                    // the label to be on the opcode, so back up to the instruction start.
                    while (!mAnattribs[--targetOffset].IsInstructionStart)
                    {
                        // Should not be possible to move past the start of the file,
                        // since we know we're in the middle of an instruction.
                        Debug.Assert(targetOffset > 0);
                    }
                }
            }

            if (targetOffset != origTargetOffset)
            {
                LogV(srcOffset, "Creating instruction ref adj=" +
                     (origTargetOffset - targetOffset));
            }

            return(targetOffset);
        }