// IGenerator public void Configure(DisasmProject project, string workDirectory, string fileNameBase, AssemblerVersion asmVersion, AppSettings settings) { Debug.Assert(project != null); Debug.Assert(!string.IsNullOrEmpty(workDirectory)); Debug.Assert(!string.IsNullOrEmpty(fileNameBase)); Project = project; Quirks = new AssemblerQuirks(); if (asmVersion != null) { mAsmVersion = asmVersion.Version; // Use the actual version. } else { mAsmVersion = V1_0; // No assembler installed, use default. } Quirks.NoPcRelBankWrap = true; Quirks.TracksSepRepNotEmu = true; mWorkDirectory = workDirectory; mFileNameBase = fileNameBase; Settings = settings; mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); AssemblerConfig config = AssemblerConfig.GetConfig(settings, AssemblerInfo.Id.Merlin32); mColumnWidths = (int[])config.ColumnWidths.Clone(); }
// IGenerator public void Configure(DisasmProject project, string workDirectory, string fileNameBase, AssemblerVersion asmVersion, AppSettings settings) { Debug.Assert(project != null); Debug.Assert(!string.IsNullOrEmpty(workDirectory)); Debug.Assert(!string.IsNullOrEmpty(fileNameBase)); Project = project; Quirks = new AssemblerQuirks(); if (asmVersion != null) { // Use the actual version. If it's > 2.17 we'll try to take advantage of // bug fixes. mAsmVersion = asmVersion.Version; } else { // No assembler installed. Use 2.17. mAsmVersion = V2_17; } if (mAsmVersion <= V2_17) { // cc65 v2.17: https://github.com/cc65/cc65/issues/717 Quirks.BlockMoveArgsReversed = true; // cc65 v2.17: https://github.com/cc65/cc65/issues/754 Quirks.NoPcRelBankWrap = true; } mWorkDirectory = workDirectory; mFileNameBase = fileNameBase; Settings = settings; mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); }
private static void GenerateHeader(IGenerator gen, StreamWriter sw) { DisasmProject proj = gen.Project; Formatter formatter = gen.SourceFormatter; // Check for header comment. if (proj.LongComments.TryGetValue(DisplayList.Line.HEADER_COMMENT_OFFSET, out MultiLineComment headerComment)) { List <string> formatted = headerComment.FormatText(formatter, string.Empty); foreach (string str in formatted) { gen.OutputLine(str); } } gen.OutputAsmConfig(); // Format symbols. foreach (DefSymbol defSym in proj.ActiveDefSymbolList) { // Use an operand length of 1 so things are shown as concisely as possible. string valueStr = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable, gen.Localizer.LabelMap, defSym.DataDescriptor, defSym.Value, 1, false); gen.OutputEquDirective(defSym.Label, valueStr, defSym.Comment); } // If there was at least one symbol, output a blank line. if (proj.ActiveDefSymbolList.Count != 0) { gen.OutputLine(string.Empty); } }
/// <summary> /// Constructor. lvt will be null when creating a new entry. /// </summary> public EditLocalVariableTable(Window owner, DisasmProject project, Formatter formatter, LocalVariableTable lvt, int offset) { InitializeComponent(); Owner = owner; DataContext = this; mProject = project; mFormatter = formatter; mSymbolTable = project.SymbolTable; mOffset = NewOffset = offset; if (lvt != null) { mWorkTable = new LocalVariableTable(lvt); mIsNotNewTable = true; } else { mWorkTable = new LocalVariableTable(); } for (int i = 0; i < mWorkTable.Count; i++) { DefSymbol defSym = mWorkTable[i]; Variables.Add(CreateFormattedSymbol(defSym)); } }
private bool PrepareNewProject(string dataPathName, SystemDef sysDef) { DisasmProject proj = new DisasmProject(); mDataPathName = dataPathName; mProjectPathName = string.Empty; byte[] fileData = null; try { fileData = LoadDataFile(dataPathName); } catch (Exception ex) { Debug.WriteLine("PrepareNewProject exception: " + ex); string message = Res.Strings.OPEN_DATA_FAIL_CAPTION; string caption = Res.Strings.OPEN_DATA_FAIL_MESSAGE + ": " + ex.Message; MessageBox.Show(caption, message, MessageBoxButton.OK, MessageBoxImage.Error); return(false); } proj.UseMainAppDomainForPlugins = mUseMainAppDomainForPlugins; proj.Initialize(fileData.Length); proj.PrepForNew(fileData, Path.GetFileName(dataPathName)); proj.LongComments.Add(DisplayListGen.Line.HEADER_COMMENT_OFFSET, new MultiLineComment("6502bench SourceGen v" + App.ProgramVersion)); // The system definition provides a set of defaults that can be overridden. // We pull everything of interest out and then discard the object. proj.ApplySystemDef(sysDef); mProject = proj; return(true); }
/// <summary> /// Extracts the operand offset from a data item. /// </summary> /// <param name="proj">Project reference.</param> /// <param name="offset">Offset of data item.</param> /// <returns>Operand offset, or -1 if not applicable.</returns> public static int GetDataOperandOffset(DisasmProject proj, int offset) { Anattrib attr = proj.GetAnattrib(offset); if (!attr.IsDataStart && !attr.IsInlineDataStart) { return(-1); } FormatDescriptor dfd = attr.DataDescriptor; // Is this numeric/Address or numeric/Symbol? if ((dfd.FormatType != FormatDescriptor.Type.NumericLE && dfd.FormatType != FormatDescriptor.Type.NumericBE) || (dfd.FormatSubType != FormatDescriptor.SubType.Address && dfd.FormatSubType != FormatDescriptor.SubType.Symbol)) { return(-1); } // Treat like an absolute address. Convert the operand // to an address, then resolve the file offset. int address = RawData.GetWord(proj.FileData, offset, dfd.Length, (dfd.FormatType == FormatDescriptor.Type.NumericBE)); if (dfd.Length < 3) { // Add the program bank where the data bank should go. Not perfect but // we don't have anything better at the moment. address |= attr.Address & 0x7fff0000; } int operandOffset = proj.AddrMap.AddressToOffset(offset, address); return(operandOffset); }
public LabelLocalizer(DisasmProject project) { mProject = project; mGlobalFlags = new BitArray(mProject.FileDataLength); LocalPrefix = "!?"; }
// IGenerator public void Configure(DisasmProject project, string workDirectory, string fileNameBase, AssemblerVersion asmVersion, AppSettings settings) { Debug.Assert(project != null); Debug.Assert(!string.IsNullOrEmpty(workDirectory)); Debug.Assert(!string.IsNullOrEmpty(fileNameBase)); Project = project; Quirks = new AssemblerQuirks(); Quirks.StackIntOperandIsImmediate = true; Quirks.LeadingUnderscoreSpecial = true; Quirks.Need24BitsForAbsPBR = true; Quirks.BitNumberIsArg = true; mWorkDirectory = workDirectory; mFileNameBase = fileNameBase; Settings = settings; mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); AssemblerConfig config = AssemblerConfig.GetConfig(settings, AssemblerInfo.Id.Tass64); mColumnWidths = (int[])config.ColumnWidths.Clone(); mHasPrgHeader = GenCommon.HasPrgHeader(project); }
/// <summary> /// Adds one or more entries to the address map for the specified segment. /// </summary> private static void AddAddressEntries(DisasmProject proj, SegmentMapEntry ent, int bufOffset, ChangeSet cs) { int addr = ent.Address; int segRem = ent.Segment.Length; while (true) { // Generate an ORG directive. int origAddr = proj.AddrMap.Get(bufOffset); UndoableChange uc = UndoableChange.CreateAddressChange(bufOffset, origAddr, addr); cs.Add(uc); // Compare amount of space in this bank to amount left in segment. int bankRem = 0x00010000 - (addr & 0xffff); if (bankRem > segRem) { // All done, bail. break; } // Advance to start of next bank. addr += bankRem; Debug.Assert((addr & 0x0000ffff) == 0); bufOffset += bankRem; segRem -= bankRem; Debug.WriteLine("Adding additional ORG at " + addr); } }
private void AddHeaderComment(DisasmProject proj, ChangeSet cs) { // Add header comment. StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format(Res.Strings.DEFAULT_HEADER_COMMENT_FMT, App.ProgramVersion)); sb.AppendLine(); foreach (SegmentMapEntry ent in mSegmentMap) { if (ent == null) { continue; } string segCmt = string.Format(Res.Strings.OMF_SEG_HDR_COMMENT_FMT, ent.Segment.SegNum, ent.Segment.Kind, ent.Segment.SegName, mFormatter.FormatAddress(ent.Address, true), ent.Segment.Length); sb.AppendLine(segCmt); } UndoableChange uc = UndoableChange.CreateLongCommentChange( LineListGen.Line.HEADER_COMMENT_OFFSET, null, new MultiLineComment(sb.ToString())); cs.Add(uc); }
/// <summary> /// Constructor. /// </summary> /// <param name="owner">Parent window.</param> /// <param name="firstOffset">Offset at top of selection.</param> /// <param name="nextOffset">Offset past bottom of selection, or -1 if only one /// line is selected.</param> /// <param name="project">Project reference.</param> /// <param name="formatter">Text formatter object.</param> public EditAddress(Window owner, int firstOffset, int nextOffset, int nextAddr, DisasmProject project, Formatter formatter) { InitializeComponent(); Owner = owner; DataContext = this; mFirstOffset = firstOffset; mNextOffset = nextOffset; mNextAddress = nextAddr; mFormatter = formatter; mMaxAddressValue = project.CpuDef.MaxAddressValue; // Compute load address, i.e. where the byte would have been placed if the entire // file were loaded at the address of the first address map entry. We assume // offsets wrap at the bank boundary. int fileStartAddr = project.AddrMap.OffsetToAddress(0); mBaseAddr = ((fileStartAddr + firstOffset) & 0xffff) | (fileStartAddr & 0xff0000); int firstAddr = project.GetAnattrib(firstOffset).Address; Debug.Assert(project.AddrMap.OffsetToAddress(firstOffset) == firstAddr); AddressText = Asm65.Address.AddressToString(firstAddr, false); LoadAddressText = '$' + mFormatter.FormatAddress(mBaseAddr, mBaseAddr > 0xffff); if (nextOffset >= 0) { NextAddressVis = Visibility.Visible; } NewAddress = -2; }
public GotoBox(DisasmProject proj, Formatter formatter) { InitializeComponent(); mProject = proj; mFormatter = formatter; TargetOffset = -1; }
public DataAnalysis(DisasmProject proj, Anattrib[] anattribs) { mProject = proj; mAnattribs = anattribs; mFileData = proj.FileData; mAnalysisParams = proj.ProjectProps.AnalysisParams; }
private DisasmProject InstantiateProject(string dataPathName, out FileLoadReport projectLoadReport) { DisasmProject project = new DisasmProject(); // always use AppDomain sandbox projectLoadReport = null; int testNum = GetTestNum(dataPathName); if (testNum < 2000) { // create new disasm project for data file byte[] fileData; try { fileData = LoadDataFile(dataPathName); } catch (Exception ex) { ReportErrMsg(ex.Message); return(null); } project.Initialize(fileData.Length); project.PrepForNew(fileData, Path.GetFileName(dataPathName)); // no platform symbols to load } else { // deserialize project file, failing if we can't find it string projectPathName = dataPathName + ProjectFile.FILENAME_EXT; if (!ProjectFile.DeserializeFromFile(projectPathName, project, out projectLoadReport)) { ReportErrMsg(projectLoadReport.Format()); return(null); } byte[] fileData; try { fileData = LoadDataFile(dataPathName); } catch (Exception ex) { ReportErrMsg(ex.Message); return(null); } project.SetFileData(fileData, Path.GetFileName(dataPathName)); project.ProjectPathName = projectPathName; project.LoadExternalFiles(); } TaskTimer genTimer = new TaskTimer(); DebugLog genLog = new DebugLog(); genLog.SetMinPriority(DebugLog.Priority.Silent); project.Analyze(UndoableChange.ReanalysisScope.CodeAndData, genLog, genTimer); return(project); }
public GotoBox(Window owner, DisasmProject proj, Formatter formatter) { InitializeComponent(); Owner = owner; DataContext = this; mProject = proj; mFormatter = formatter; TargetOffset = -1; }
/// <summary> /// Constructor. /// </summary> public Exporter(DisasmProject project, LineListGen codeLineList, Formatter formatter, ActiveColumnFlags leftFlags, int[] rightWidths) { mProject = project; mCodeLineList = codeLineList; mFormatter = formatter; mLeftFlags = leftFlags; ConfigureColumns(leftFlags, rightWidths); }
/// <summary> /// Cleans up, discarding the AppDomain if one was created. Do not continue to use /// the object after calling this. /// </summary> public void Cleanup() { if (DomainManager != null) { DomainManager.Dispose(); DomainManager = null; } mActivePlugins = null; mProject = null; }
public FormatSplitAddress(DisasmProject project, TypedRangeSet selection, Formatter formatter) { InitializeComponent(); mProject = project; mFormatter = formatter; mSelection = selection; mOutputReady = false; }
/// <summary> /// Constructor. Initial state is configured from an existing ProjectProperties object. /// </summary> /// <param name="owner">Parent window.</param> /// <param name="project">Project object.</param> /// <param name="projectDir">Project directory, if known.</param> /// <param name="formatter">Text formatter.</param> /// <param name="initialTab">Tab to open initially. Pass "Unknown" for default.</param> public EditProjectProperties(Window owner, DisasmProject project, string projectDir, Formatter formatter, Tab initialTab) { InitializeComponent(); Owner = owner; DataContext = this; mWorkProps = new ProjectProperties(project.ProjectProps); // make a work copy mProjectDir = projectDir; mFormatter = formatter; mInitialTab = initialTab; IsRelocDataAvailable = (project.RelocList.Count > 0); // Construct arrays used as item sources for combo boxes. CpuItems = new CpuItem[] { new CpuItem((string)FindResource("str_6502"), CpuDef.CpuType.Cpu6502), new CpuItem((string)FindResource("str_65C02"), CpuDef.CpuType.Cpu65C02), new CpuItem((string)FindResource("str_W65C02"), CpuDef.CpuType.CpuW65C02), new CpuItem((string)FindResource("str_65816"), CpuDef.CpuType.Cpu65816), }; DefaultTextScanModeItems = new DefaultTextScanMode[] { new DefaultTextScanMode(Res.Strings.SCAN_LOW_ASCII, TextScanMode.LowAscii), new DefaultTextScanMode(Res.Strings.SCAN_LOW_HIGH_ASCII, TextScanMode.LowHighAscii), new DefaultTextScanMode(Res.Strings.SCAN_C64_PETSCII, TextScanMode.C64Petscii), new DefaultTextScanMode(Res.Strings.SCAN_C64_SCREEN_CODE, TextScanMode.C64ScreenCode), }; MinCharsItems = new MinCharsItem[] { new MinCharsItem((string)FindResource("str_DisableStringScan"), DataAnalysis.MIN_CHARS_FOR_STRING_DISABLED), new MinCharsItem("3", 3), new MinCharsItem("4", 4), new MinCharsItem("5", 5), new MinCharsItem("6", 6), new MinCharsItem("7", 7), new MinCharsItem("8", 8), new MinCharsItem("9", 9), new MinCharsItem("10", 10), }; AutoLabelItems = new AutoLabelItem[] { new AutoLabelItem((string)FindResource("str_AutoLabelSimple"), AutoLabel.Style.Simple), new AutoLabelItem((string)FindResource("str_AutoLabelAnnotated"), AutoLabel.Style.Annotated), new AutoLabelItem((string)FindResource("str_AutoLabelFullyAnnotated"), AutoLabel.Style.FullyAnnotated), }; }
/// <summary> /// Returns the "base" operand offset. If the byte at the specified offset is not the /// start of a code/data/inline-data item, walk backward until the start is found. /// </summary> /// <param name="proj">Project reference.</param> /// <param name="offset">Start offset.</param> /// <returns></returns> public static int GetBaseOperandOffset(DisasmProject proj, int offset) { Debug.Assert(offset >= 0 && offset < proj.FileDataLength); while (!proj.GetAnattrib(offset).IsStart) { offset--; // Should not be possible to walk off the top of the list, since we're in // the middle of something. Debug.Assert(offset >= 0); } return(offset); }
/// <summary> /// Constructor. /// </summary> /// <param name="project">Project reference.</param> /// <param name="projectPathName">Full path to the project file.</param> public GenAndAsm(Window owner, MainController mainCtrl, DisasmProject project, string projectPathName) { InitializeComponent(); Owner = owner; mMainCtrl = mainCtrl; mProject = project; mWorkDirectory = Path.GetDirectoryName(projectPathName); mBaseFileName = Path.GetFileNameWithoutExtension(projectPathName); workDirectoryTextBox.Text = mWorkDirectory; }
/// <summary> /// Constructor. /// </summary> public ScriptManager(DisasmProject proj) { mProject = proj; if (!proj.UseMainAppDomainForPlugins) { CreateDomainManager(); } else { mActivePlugins = new Dictionary <string, IPlugin>(); } }
/// <summary> /// Finds and loads the specified data file. The file's length and CRC must match /// the project's expectations. /// </summary> /// <param name="dataPathName">Full path to file.</param> /// <param name="proj">Project object.</param> /// <param name="cancel">Returns true if we want to cancel the attempt.</param> /// <returns></returns> private byte[] FindValidDataFile(ref string dataPathName, DisasmProject proj, out bool cancel) { FileInfo fi = new FileInfo(dataPathName); if (!fi.Exists) { Debug.WriteLine("File '" + dataPathName + "' doesn't exist"); dataPathName = ChooseDataFile(dataPathName, Res.Strings.OPEN_DATA_DOESNT_EXIST); cancel = (dataPathName == null); return(null); } if (fi.Length != proj.FileDataLength) { Debug.WriteLine("File '" + dataPathName + "' has length=" + fi.Length + ", expected " + proj.FileDataLength); dataPathName = ChooseDataFile(dataPathName, string.Format(Res.Strings.OPEN_DATA_WRONG_LENGTH_FMT, fi.Length, proj.FileDataLength)); cancel = (dataPathName == null); return(null); } byte[] fileData = null; try { fileData = LoadDataFile(dataPathName); } catch (Exception ex) { Debug.WriteLine("File '" + dataPathName + "' failed to load: " + ex.Message); dataPathName = ChooseDataFile(dataPathName, string.Format(Res.Strings.OPEN_DATA_LOAD_FAILED_FMT, ex.Message)); cancel = (dataPathName == null); return(null); } uint crc = CRC32.OnWholeBuffer(0, fileData); if (crc != proj.FileDataCrc32) { Debug.WriteLine("File '" + dataPathName + "' has CRC32=" + crc + ", expected " + proj.FileDataCrc32); // Format the CRC as signed decimal, so that interested parties can // easily replace the value in the .dis65 file. dataPathName = ChooseDataFile(dataPathName, string.Format(Res.Strings.OPEN_DATA_WRONG_CRC_FMT, (int)crc, (int)proj.FileDataCrc32)); cancel = (dataPathName == null); return(null); } cancel = false; return(fileData); }
/// <summary> /// Determines the offset of the label that the operand's symbol references. /// </summary> /// <param name="gen">Source generator reference.</param> /// <param name="offset">Offset of instruction opcode.</param> /// <returns>The offset of the label, or -1 if the operand isn't a symbolic reference /// to a known label.</returns> private static int GetLabelOffsetFromOperand(IGenerator gen, int offset) { DisasmProject proj = gen.Project; Debug.Assert(proj.GetAnattrib(offset).IsInstructionStart); FormatDescriptor dfd = proj.GetAnattrib(offset).DataDescriptor; if (dfd == null || !dfd.HasSymbol) { return(-1); } return(proj.FindLabelOffsetByName(dfd.SymbolRef.Label)); }
public EditLvTableLocation(Window owner, DisasmProject project, int curOffset, int initialOffset) { InitializeComponent(); Owner = owner; DataContext = this; mProject = project; mCurrentOffset = curOffset; // curOffset is where the table actually is. initialOffset reflects changes // made on a previous invocation of this dialog. OffsetStr = initialOffset.ToString("x6"); }
/// <summary> /// Constructor. /// </summary> /// <param name="owner">Parent window.</param> /// <param name="proj">Disassembly project.</param> /// <param name="formatter">Text formatter.</param> /// <param name="curValue">Current value, or null if none set.</param> public EditDataBank(Window owner, DisasmProject proj, Formatter formatter, CodeAnalysis.DbrValue curValue) { InitializeComponent(); Owner = owner; DataContext = this; mProject = proj; mFormatter = formatter; PopulateComboBox(); DataBankStr = DbrValueToString(curValue); // sets combo box IsValid = true; }
public FormatAddressTable(Window owner, DisasmProject project, TypedRangeSet selection, Formatter formatter) { InitializeComponent(); Owner = owner; DataContext = this; mProject = project; mFormatter = formatter; mSelection = selection; IsValid = false; OutputPreviewList = new ObservableCollection <OutputPreviewItem>(); }
/// <summary> /// Constructor. /// </summary> public ScriptManager(DisasmProject proj) { mProject = proj; if (!proj.UseMainAppDomainForPlugins) { DomainManager = new DomainManager(UseKeepAliveHack); DomainManager.CreateDomain("Plugin Domain", PluginDllCache.GetPluginDirPath()); DomainManager.PluginMgr.SetFileData(proj.FileData); } else { mActivePlugins = new Dictionary <string, IPlugin>(); } }
/// <summary> /// Constructor. /// </summary> /// <param name="lvTables">List of tables from the DisasmProject.</param> /// <param name="symbolTable">Full SymbolTable from the DisasmProject. Used to /// generate globally unique symbol names.</param> /// <param name="project">Project reference.</param> /// <param name="uniquify">Set to true if variable names cannot be redefined.</param> public LocalVariableLookup(SortedList <int, LocalVariableTable> lvTables, DisasmProject project, bool uniquify) { mLvTables = lvTables; mSymbolTable = project.SymbolTable; mProject = project; mDoUniquify = uniquify; mCurrentTable = new LocalVariableTable(); mDupRemap = new Dictionary <string, string>(); if (uniquify) { mUniqueLabels = new Dictionary <string, UniqueLabel>(); } Reset(); }
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 }