Ejemplo n.º 1
0
        /// <summary>
        /// Determines whether the project appears to have a PRG header.
        /// </summary>
        /// <param name="project">Project to check.</param>
        /// <returns>True if we think we found a PRG header.</returns>
        public static bool HasPrgHeader(DisasmProject project)
        {
            if (project.FileDataLength < 3 || project.FileDataLength > 65536 + 2)
            {
                // Must fit in 64KB of memory.  A 65538-byte file will work if the
                // first two bytes are the PRG header (and it starts at address zero).
                //Debug.WriteLine("PRG test: incompatible file length");
                return(false);
            }
            Anattrib attr0 = project.GetAnattrib(0);
            Anattrib attr1 = project.GetAnattrib(1);

            if (!(attr0.IsDataStart && attr1.IsData))
            {
                //Debug.WriteLine("PRG test: +0/1 not data");
                return(false);
            }
            if (attr0.Length != 2)
            {
                //Debug.WriteLine("PRG test: +0/1 not 16-bit value");
                return(false);
            }
            if (attr0.Symbol != null || attr1.Symbol != null)
            {
                //Debug.WriteLine("PRG test: +0/1 has label");
                return(false);
            }
            // The first part of the address map should be a two-byte region, either added
            // explicitly or a hole left at the start of the file.  Address doesn't matter.
            IEnumerator <AddressMap.AddressChange> iter = project.AddrMap.AddressChangeIterator;

            if (!iter.MoveNext())
            {
                Debug.Assert(false);
                return(false);
            }
            AddressMap.AddressChange change = iter.Current;
            if (change.Region.ActualLength != 2)
            {
                Debug.WriteLine("PRG test: first entry is not a two-byte region");
            }
            // Confirm there's a single address map entry at offset 2.  If there's more than
            // one we likely have a situation where the first one is a "full-file" region, and
            // the second determines the address.  This weird scenario causes problems with
            // code generation, so we just don't support it.
            if (project.AddrMap.GetEntries(0x000002).Count != 1)
            {
                //Debug.WriteLine("PRG test: wrong #of entries at +000002");
                return(false);
            }
            // See if the address at offset 2 matches the value at 0/1.
            int value01 = project.FileData[0] | (project.FileData[1] << 8);
            int addr2   = project.AddrMap.OffsetToAddress(0x000002);

            if (value01 != addr2)
            {
                //Debug.WriteLine("PRG test: +0/1 value is " + value01.ToString("x4") +
                //    ", address at +2 is " + addr2);
                return(false);
            }

            // TODO? confirm project fits in 64K of memory

            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gathers a list of symbols from the project's symbol table.
        /// </summary>
        /// <remarks>
        /// Remember that we need to set this up before code analysis runs, so many of the
        /// secondary data structures (like Anattribs) won't be available.
        /// </remarks>
        private List <PlSymbol> GeneratePlSymbolList()
        {
            List <PlSymbol> plSymbols = new List <PlSymbol>();
            SymbolTable     symTab    = mProject.SymbolTable;

            // UserLabels maps offset to Symbol.  Create the reverse mapping.
            Dictionary <Symbol, int> symbolOffsets =
                new Dictionary <Symbol, int>(mProject.UserLabels.Count);

            foreach (KeyValuePair <int, Symbol> kvp in mProject.UserLabels)
            {
                symbolOffsets[kvp.Value] = kvp.Key;
            }

            // Add in the address region pre-labels.
            IEnumerator <AddressMap.AddressChange> addrIter = mProject.AddrMap.AddressChangeIterator;

            while (addrIter.MoveNext())
            {
                AddressMap.AddressChange change = addrIter.Current;
                if (!change.IsStart)
                {
                    continue;
                }
                if (change.Region.HasValidPreLabel)
                {
                    Symbol newSym = new Symbol(change.Region.PreLabel,
                                               change.Region.PreLabelAddress, Symbol.Source.AddrPreLabel,
                                               Symbol.Type.ExternalAddr, Symbol.LabelAnnotation.None);
                    symbolOffsets[newSym] = change.Region.Offset;
                }
            }

            foreach (Symbol sym in symTab)
            {
                PlSymbol.Source plsSource;
                int             symOff, offset = -1;
                switch (sym.SymbolSource)
                {
                case Symbol.Source.User:
                    plsSource = PlSymbol.Source.User;
                    if (symbolOffsets.TryGetValue(sym, out symOff))
                    {
                        offset = symOff;
                    }
                    break;

                case Symbol.Source.AddrPreLabel:
                    plsSource = PlSymbol.Source.AddrPreLabel;
                    if (symbolOffsets.TryGetValue(sym, out symOff))
                    {
                        offset = symOff;
                    }
                    break;

                case Symbol.Source.Project:
                    plsSource = PlSymbol.Source.Project;
                    break;

                case Symbol.Source.Platform:
                    plsSource = PlSymbol.Source.Platform;
                    break;

                case Symbol.Source.Auto:
                case Symbol.Source.Variable:
                    // don't forward these to plugins
                    continue;

                default:
                    Debug.Assert(false);
                    continue;
                }
                PlSymbol.Type plsType;
                switch (sym.SymbolType)
                {
                case Symbol.Type.NonUniqueLocalAddr:
                    // don't forward these to plugins
                    continue;

                case Symbol.Type.LocalOrGlobalAddr:
                case Symbol.Type.GlobalAddr:
                case Symbol.Type.GlobalAddrExport:
                case Symbol.Type.ExternalAddr:
                    plsType = PlSymbol.Type.Address;
                    break;

                case Symbol.Type.Constant:
                    plsType = PlSymbol.Type.Constant;
                    break;

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

                int    width = -1;
                string tag   = string.Empty;
                if (sym is DefSymbol)
                {
                    DefSymbol defSym = sym as DefSymbol;
                    width = defSym.DataDescriptor.Length;
                    tag   = defSym.Tag;
                }

                plSymbols.Add(new PlSymbol(sym.Label, sym.Value, width, plsSource, plsType, tag,
                                           offset));
            }

            return(plSymbols);
        }
Ejemplo n.º 3
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);
        }