예제 #1
0
        /// <summary>
        /// Generates assembly source.
        ///
        /// This code is common to all generators.
        /// </summary>
        /// <param name="gen">Reference to generator object (presumably the caller).</param>
        /// <param name="sw">Text output sink.</param>
        /// <param name="worker">Background worker object, for progress updates and
        ///   cancelation requests.</param>
        public static void Generate(IGenerator gen, StreamWriter sw, BackgroundWorker worker)
        {
            DisasmProject proj      = gen.Project;
            Formatter     formatter = gen.SourceFormatter;
            int           offset    = 0;

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

            LocalVariableLookup lvLookup = new LocalVariableLookup(proj.LvTables, proj,
                                                                   gen.Localizer.LabelMap, gen.Quirks.LeadingUnderscoreSpecial,
                                                                   gen.Quirks.NoRedefinableSymbols);

            GenerateHeader(gen, sw);

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

            int lastProgress = 0;

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

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

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

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

                List <DefSymbol> lvars = lvLookup.GetVariablesDefinedAtOffset(offset);
                if (lvars != null)
                {
                    // table defined here
                    gen.OutputLocalVariableTable(offset, lvars,
                                                 lvLookup.GetMergedTableAtOffset(offset));
                }

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

                        prevFlags = curFlags;
                    }

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

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

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

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

                // Update progress meter.  We don't want to spam it, so just ping it 10x.
                int curProgress = (offset * 10) / proj.FileData.Length;
                if (lastProgress != curProgress)
                {
                    if (worker.CancellationPending)
                    {
                        Debug.WriteLine("GenCommon got cancellation request");
                        return;
                    }
                    lastProgress = curProgress;
                    worker.ReportProgress(curProgress * 10);
                    //System.Threading.Thread.Sleep(500);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Generates assembly source.
        ///
        /// This code is common to all generators.
        /// </summary>
        /// <param name="gen">Reference to generator object (presumably the caller).</param>
        /// <param name="sw">Text output sink.</param>
        /// <param name="worker">Background worker object, for progress updates and
        ///   cancelation requests.</param>
        public static void Generate(IGenerator gen, StreamWriter sw, BackgroundWorker worker)
        {
            DisasmProject proj      = gen.Project;
            Formatter     formatter = gen.SourceFormatter;
            int           offset    = gen.StartOffset;

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

            LocalVariableLookup lvLookup = new LocalVariableLookup(proj.LvTables, proj,
                                                                   gen.Localizer.LabelMap, gen.Quirks.LeadingUnderscoreSpecial,
                                                                   gen.Quirks.NoRedefinableSymbols);

            GenerateHeader(gen, sw);

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

            int lastProgress = 0;

            // Create an address map iterator and advance it to match gen.StartOffset.
            IEnumerator <AddressMap.AddressChange> addrIter = proj.AddrMap.AddressChangeIterator;

            while (addrIter.MoveNext())
            {
                if (addrIter.Current.IsStart && addrIter.Current.Offset >= offset)
                {
                    break;
                }
            }

            bool arDirectPending = false;

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

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

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

                // Check for address range starts.  There may be more than one at a given offset.
                AddressMap.AddressChange change = addrIter.Current;
                while (change != null && change.Offset == offset)
                {
                    if (change.IsStart)
                    {
                        gen.OutputArDirective(change);
                        arDirectPending = true;
                        addrIter.MoveNext();
                        change = addrIter.Current;
                    }
                    else
                    {
                        break;
                    }
                }

                // Reached end of start directives.  Write the last one.
                if (arDirectPending)
                {
                    gen.FlushArDirectives();
                    arDirectPending = false;
                }

                List <DefSymbol> lvars = lvLookup.GetVariablesDefinedAtOffset(offset);
                if (lvars != null)
                {
                    // table defined here
                    gen.OutputLocalVariableTable(offset, lvars,
                                                 lvLookup.GetMergedTableAtOffset(offset));
                }

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

                        prevFlags = curFlags;
                    }

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

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

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

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

                // Check for address region ends.  There may be more than one at a given offset.
                // The end-region offset will be the last byte of the instruction or data item,
                // so it should be one less than the updated offset.
                //
                // If we encounter a region start, we'll handle that at the top of the next
                // loop iteration.
                while (change != null && change.Offset + 1 == offset)
                {
                    if (!change.IsStart)
                    {
                        gen.OutputArDirective(change);
                        arDirectPending = true;
                        addrIter.MoveNext();
                        change = addrIter.Current;
                    }
                    else
                    {
                        break;
                    }
                }

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

            Debug.Assert(offset == proj.FileDataLength);
        }