예제 #1
0
 /// <summary>
 /// Cycle modifier description.
 /// </summary>
 /// <param name="modBit">A single-bit item from the CycleMod enum.</param>
 /// <returns>Description string, or question marks if not found.</returns>
 public string GetCycleModDescription(OpDef.CycleMod modBit)
 {
     if (mCycleModDescriptions.TryGetValue(modBit, out string desc))
     {
         return(desc);
     }
     else
     {
         return("???");
     }
 }
예제 #2
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;
            }
        }
예제 #3
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));
            }
        }
예제 #4
0
        /// <summary>
        /// Returns the number of cycles required to execute the instruction.  If the value
        /// is negative, the negated value represents the minimum number of cycles for an
        /// instruction with variable timing.
        ///
        /// The value returned will factor in any CPU-specific aspects.
        /// </summary>
        /// <param name="opNum">Instruction opcode value.</param>
        /// <returns>Cycle count.</returns>
        public int GetCycles(int opNum, StatusFlags flags, OpDef.BranchTaken branchTaken,
                             bool branchCrossesPage)
        {
            // The irrelevant modifiers have already been stripped out.
            OpDef.CycleMod mods   = mCycleMods[opNum];
            int            cycles = mCycleCounts[opNum];

            // Walk through the various cycle mods.  If we can evaluate them definitively,
            // do so now and remove them from the set.

            // The M/X flags are defined to be in one state or the other, even when the flag
            // value is indeterminate, because we have to be able to size immediate operands
            // appropriately.  So there's no ambiguity here even when there's ambiguity.  We
            // make a similar statement about the E flag.
            if ((mods & OpDef.CycleMod.OneIfM0) != 0)
            {
                if (!flags.ShortM)
                {
                    cycles++;
                }
                mods &= ~OpDef.CycleMod.OneIfM0;
            }
            if ((mods & OpDef.CycleMod.TwoIfM0) != 0)
            {
                if (!flags.ShortM)
                {
                    cycles += 2;
                }
                mods &= ~OpDef.CycleMod.TwoIfM0;
            }
            if ((mods & OpDef.CycleMod.OneIfX0) != 0)
            {
                if (!flags.ShortX)
                {
                    cycles++;
                }
                mods &= ~OpDef.CycleMod.OneIfX0;
            }
            if ((mods & OpDef.CycleMod.OneIfE0) != 0)
            {
                if (flags.E == 0)
                {
                    cycles++;
                }
                mods &= ~OpDef.CycleMod.OneIfE0;
            }

            // Some of these can be known, some can't.
            if ((mods & OpDef.CycleMod.OneIfD1) != 0)
            {
                if (flags.D == 1)
                {
                    cycles++;
                }
                if (flags.D == 0 || flags.D == 1)
                {
                    mods &= ~OpDef.CycleMod.OneIfD1;
                }
            }
            if ((mods & OpDef.CycleMod.OneIfBranchTaken) != 0)
            {
                if (branchTaken == OpDef.BranchTaken.Always)
                {
                    cycles++;
                }
                if (branchTaken != OpDef.BranchTaken.Indeterminate)
                {
                    mods &= ~OpDef.CycleMod.OneIfBranchTaken;
                }
            }
            if ((mods & OpDef.CycleMod.OneIfBranchPage) != 0)
            {
                if (branchCrossesPage && flags.E != 0)
                {
                    cycles++;   // +1 unless we're in native mode on 65816
                }
                mods &= ~OpDef.CycleMod.OneIfBranchPage;
            }

            // We can't evaluate OneIfDpNonzero, OneIfIndexPage, or MinusOneIfNoPage.
            // OneIf65C02 was handled earlier.
            // TODO(maybe): in some cases we can know that the index doesn't cross a
            //   page boundary by checking the address, e.g. "LDA $2000,X" can't cross.

            if (mods != 0)
            {
                // Some unresolved mods remain.
                cycles = -cycles;
            }
            return(cycles);
        }