// IAssembler public AssemblerVersion QueryVersion() { AssemblerConfig config = AssemblerConfig.GetConfig(AppSettings.Global, AssemblerInfo.Id.Tass64); if (config == null || string.IsNullOrEmpty(config.ExecutablePath)) { return(null); } ShellCommand cmd = new ShellCommand(config.ExecutablePath, "--version", Directory.GetCurrentDirectory(), null); cmd.Execute(); if (string.IsNullOrEmpty(cmd.Stdout)) { return(null); } // Windows - Stdout: "64tass Turbo Assembler Macro V1.53.1515\r\n" // Linux - Stdout: "64tass Turbo Assembler Macro V1.53.1515?\n" const string PREFIX = "Macro V"; string str = cmd.Stdout; int start = str.IndexOf(PREFIX); int end = (start < 0) ? -1 : str.IndexOfAny(new char[] { '?', '\r', '\n' }, start + 1); if (start < 0 || end < 0 || start + PREFIX.Length >= end) { Debug.WriteLine("Couldn't find version in " + str); return(null); } start += PREFIX.Length; string versionStr = str.Substring(start, end - start); CommonUtil.Version version = CommonUtil.Version.Parse(versionStr); if (!version.IsValid) { return(null); } return(new AssemblerVersion(versionStr, version)); }
// IAssembler public AssemblerVersion QueryVersion() { AssemblerConfig config = AssemblerConfig.GetConfig(AppSettings.Global, AssemblerInfo.Id.Merlin32); if (config == null || string.IsNullOrEmpty(config.ExecutablePath)) { return(null); } ShellCommand cmd = new ShellCommand(config.ExecutablePath, string.Empty, Directory.GetCurrentDirectory(), null); cmd.Execute(); if (string.IsNullOrEmpty(cmd.Stdout)) { return(null); } // Stdout: "C:\Src\WorkBench\Merlin32.exe v 1.0, (c) Brutal Deluxe ..." // Other platforms may not have the ".exe". Find first occurrence of " v ". const string PREFIX = " v "; // not expecting this to appear in the path string str = cmd.Stdout; int start = str.IndexOf(PREFIX); int end = (start < 0) ? -1 : str.IndexOf(',', start); if (start < 0 || end < 0 || start + PREFIX.Length >= end) { Debug.WriteLine("Couldn't find version in " + str); return(null); } start += PREFIX.Length; string versionStr = str.Substring(start, end - start); CommonUtil.Version version = CommonUtil.Version.Parse(versionStr); if (!version.IsValid) { return(null); } return(new AssemblerVersion(versionStr, version)); }
// IAssembler public AssemblerVersion QueryVersion() { AssemblerConfig config = AssemblerConfig.GetConfig(AppSettings.Global, AssemblerInfo.Id.Acme); if (config == null || string.IsNullOrEmpty(config.ExecutablePath)) { return(null); } ShellCommand cmd = new ShellCommand(config.ExecutablePath, "--version", Directory.GetCurrentDirectory(), null); cmd.Execute(); if (string.IsNullOrEmpty(cmd.Stdout)) { return(null); } // Windows - Stdout: "This is ACME, release 0.96.4 ("Fenchurch"), 22 Dec 2017 ..." // Linux - Stderr: "This is ACME, release 0.96.4 ("Fenchurch"), 20 Apr 2019 ..." const string PREFIX = "release "; string str = cmd.Stdout; int start = str.IndexOf(PREFIX); int end = (start < 0) ? -1 : str.IndexOf(' ', start + PREFIX.Length + 1); if (start < 0 || end < 0 || start + PREFIX.Length >= end) { Debug.WriteLine("Couldn't find version in " + str); return(null); } start += PREFIX.Length; string versionStr = str.Substring(start, end - start); CommonUtil.Version version = CommonUtil.Version.Parse(versionStr); if (!version.IsValid) { return(null); } return(new AssemblerVersion(versionStr, version)); }
// 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; } Quirks.SinglePassAssembler = true; mWorkDirectory = workDirectory; mFileNameBase = fileNameBase; Settings = settings; mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); AssemblerConfig config = AssemblerConfig.GetConfig(settings, AssemblerInfo.Id.Cc65); 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) { mAsmVersion = asmVersion.Version; // Use the actual version. } else { mAsmVersion = V0_97; // No assembler installed, use default. } // ACME isn't a single-pass assembler, but the code that determines label widths // only runs in the first pass and doesn't get corrected. So unlike cc65, which // generates correct zero-page acceses once the label's value is known, ACME // uses 16-bit addressing to zero-page labels for backward references if there // are any forward references at all. The easy way to deal with this is to make // all zero-page label references have explicit widths. // // Example: // * = $1000 // jmp zero // !pseudopc $0000 { // zero nop // lda zero // rts // } Quirks.SinglePassAssembler = true; Quirks.SinglePassNoLabelCorrection = true; if (mAsmVersion < V0_97) { Quirks.BlockMoveArgsNoHash = true; mBackslashEscapes = false; } mWorkDirectory = workDirectory; mFileNameBase = fileNameBase; Settings = settings; mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); AssemblerConfig config = AssemblerConfig.GetConfig(settings, AssemblerInfo.Id.Acme); mColumnWidths = (int[])config.ColumnWidths.Clone(); // ACME wants the entire file to be loadable into a 64KB memory area. If the // initial address is too large, a file smaller than 64KB might overrun the bank // boundary and cause a failure. In that case we want to set the initial address // to zero and "stream" the rest. int firstAddr = project.AddrMap.OffsetToAddress(0); if (firstAddr == Address.NON_ADDR) { firstAddr = 0; } if (firstAddr + project.FileDataLength > 65536) { mOutputMode = OutputMode.Streamable; } else { mOutputMode = OutputMode.Loadable; } }
// 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_56; // No assembler installed, use default. } Quirks.StackIntOperandIsImmediate = true; Quirks.LeadingUnderscoreSpecial = true; Quirks.Need24BitsForAbsPBR = true; Quirks.BitNumberIsArg = true; Quirks.BankZeroAbsPBRRestrict = 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(); // 64tass emulates a loader on a 64K system. The address you specify with // "* = <addr>" tells the loader where the code lives. If the project runs off the // end of memory, you get a warning message and an output file that has the last // part as the first part, because the loader wraps around. // // If (start_addr + total_len) doesn't fit without wrapping, we want to start // the code with "* = 0" (or omit it entirely) and use ".logical" for the first. // chunk. This allows us to generate the full 64K. Note that 65816 code that // starts outside bank 0 will always fail this test. // // Thus there are two modes: "loadable" and "streamable". We could output everything // as streamable but that's kind of ugly and prevents the PRG optimization. // // If the file has more than 64K of data in it, we need to add "--long-address" to // the command-line arguments. // Get start address. If this is a PRG file, the start address is the address // of offset +000002. bool hasPrgHeader = GenCommon.HasPrgHeader(project); int offAdj = hasPrgHeader ? 2 : 0; int startAddr = project.AddrMap.OffsetToAddress(offAdj); if (startAddr + project.FileDataLength - offAdj > 65536) { // Does not fit into memory at load address. mOutputMode = OutputMode.Streamable; mHasPrgHeader = false; } else { mOutputMode = OutputMode.Loadable; mHasPrgHeader = hasPrgHeader; } //Debug.WriteLine("startAddr=$" + startAddr.ToString("x6") + // " outputMode=" + mOutputMode + " hasPrg=" + mHasPrgHeader); }