mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-11 13:50:13 +00:00
4e5c34f457
This adds a new data format option, "binary include", that takes a filename operand. When assembly sources are generated, the section of file is replaced with an appropriate pseudo-op, and binary files are generated that hold the file contents. This is a convenient way to remove large binary blobs, such as music or sound samples, that aren't useful to have in text form in the sources. Partial pathnames are allowed, so you can output a sound blob to "sounds/blather.bin". For safety reasons, we don't allow the files to be created above the project directory, and existing files will only be overwritten if they have a matching length (so you don't accidentally stomp on your project file). The files are not currently shown in the GenAsm dialog, which lets you see a preview of the generated sources. The hex dump tool can do this for the (presumably rare) situations where it's useful. A new regression test, 20300-binary-include, has been added. The pseudo-op name can be overridden on-screen in the settings. We don't currently do anything new for text/HTML exports. It might be useful to generate an optional appendix with a hex dump of the excised sections. (issue #144)
301 lines
13 KiB
C#
301 lines
13 KiB
C#
/*
|
|
* Copyright 2019 faddenSoft
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
|
|
using Asm65;
|
|
|
|
namespace SourceGen.AsmGen {
|
|
/// <summary>
|
|
/// Common interface for generating assembler-specific source code.
|
|
/// </summary>
|
|
public interface IGenerator {
|
|
/// <summary>
|
|
/// Returns some strings and format options for use in for the display list, configurable
|
|
/// through the app settings "quick set" feature. These are not used when generating
|
|
/// source code.
|
|
///
|
|
/// This may be called on an unconfigured IGenerator, so this should not expect to
|
|
/// have access to project properties.
|
|
/// </summary>
|
|
/// <param name="pseudoOps">Table of pseudo-op names.</param>
|
|
/// <param name="formatConfig">Format configuration.</param>
|
|
void GetDefaultDisplayFormat(out PseudoOp.PseudoOpNames pseudoOps,
|
|
out Formatter.FormatConfig formatConfig);
|
|
|
|
|
|
/// <summary>
|
|
/// Configure generator. Must be called before calling any other method or using
|
|
/// properties, unless otherwise noted.
|
|
/// </summary>
|
|
/// <param name="project">Project to generate source for.</param>
|
|
/// <param name="workDirectory">Directory in which to create output files.</param>
|
|
/// <param name="fileNameBase">Name to use as base for filenames.</param>
|
|
/// <param name="asmVersion">Version of assembler to target. Pass in null
|
|
/// to target latest known version.</param>
|
|
/// <param name="settings">App settings object.</param>
|
|
void Configure(DisasmProject project, string workDirectory, string fileNameBase,
|
|
AssemblerVersion asmVersion, AppSettings settings);
|
|
|
|
/// <summary>
|
|
/// Project object with file data and Anattribs.
|
|
/// </summary>
|
|
DisasmProject Project { get; }
|
|
|
|
/// <summary>
|
|
/// Source code formatter.
|
|
/// </summary>
|
|
Formatter SourceFormatter { get; }
|
|
|
|
/// <summary>
|
|
/// Application settings.
|
|
/// </summary>
|
|
AppSettings Settings { get; }
|
|
|
|
/// <summary>
|
|
/// Assembler-specific behavior. Used to handle quirky behavior for things that
|
|
/// are otherwise managed by common code.
|
|
/// </summary>
|
|
AssemblerQuirks Quirks { get; }
|
|
|
|
/// <summary>
|
|
/// Label localization object. Behavior is assembler-specific.
|
|
/// </summary>
|
|
LabelLocalizer Localizer { get; }
|
|
|
|
/// <summary>
|
|
/// File offset to start generating code from, usually zero. Will be nonzero for files
|
|
/// with a header that is supposed to be generated by the assembler (e.g. C64 PRG).
|
|
/// </summary>
|
|
int StartOffset { get; }
|
|
|
|
/// <summary>
|
|
/// Generates source files on a background thread. Method must not make any UI calls.
|
|
/// </summary>
|
|
/// <param name="worker">Async work object, used to report progress updates and
|
|
/// check for cancellation.</param>
|
|
/// <returns>Object with list of pathnames of generated files.</returns>
|
|
GenerationResults GenerateSource(BackgroundWorker worker);
|
|
|
|
/// <summary>
|
|
/// Provides an opportunity for the assembler to replace a mnemonic with another, or
|
|
/// output an instruction as hex bytes.
|
|
/// </summary>
|
|
/// <param name="offset">Opcode offset.</param>
|
|
/// <param name="op">Opcode to replace.</param>
|
|
/// <returns>Replacement mnemonic, an empty string if the original is fine, or
|
|
/// null if the op is unsupported or broken and should be emitted as hex.</returns>
|
|
string ModifyOpcode(int offset, OpDef op);
|
|
|
|
/// <summary>
|
|
/// Provides an opportunity for the assembler to replace an instruction's format
|
|
/// descriptor with another. Only called if the instruction is explicitly formatted
|
|
/// (i.e. has a non-null descriptor).
|
|
/// </summary>
|
|
/// <param name="offset">Instruction offset.</param>
|
|
/// <param name="dfd">Existing descriptor.</param>
|
|
/// <param name="operand">Operand value.</param>
|
|
/// <returns>Replacement format descriptor. If no changes are desired, returns
|
|
/// the dfd argument.</returns>
|
|
FormatDescriptor ModifyInstructionOperandFormat(int offset, FormatDescriptor dfd,
|
|
int operand);
|
|
|
|
/// <summary>
|
|
/// Allows the generator to issue character encoding update instructions for source
|
|
/// files with more than one encoding.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This may be called for non-character numeric descriptors.
|
|
/// </remarks>
|
|
/// <param name="dfd">Format descriptor for character or string.</param>
|
|
void UpdateCharacterEncoding(FormatDescriptor dfd);
|
|
|
|
/// <summary>
|
|
/// Generates an opcode/operand pair for a short sequence of bytes (1-4 bytes).
|
|
/// Does not produce any source output.
|
|
/// </summary>
|
|
/// <param name="offset">Offset to data.</param>
|
|
/// <param name="count">Number of bytes (1-4).</param>
|
|
/// <param name="opcode">Opcode mnemonic.</param>
|
|
/// <param name="operand">Formatted operand.</param>
|
|
void GenerateShortSequence(int offset, int length, out string opcode, out string operand);
|
|
|
|
/// <summary>
|
|
/// Outputs zero or more lines of assembler configuration. This comes after the
|
|
/// header comment but before any directives. Useful for configuring the CPU type
|
|
/// and assembler options.
|
|
/// </summary>
|
|
void OutputAsmConfig();
|
|
|
|
/// <summary>
|
|
/// Outputs one or more lines of data for the specified offset.
|
|
/// </summary>
|
|
/// <param name="offset">Offset to data.</param>
|
|
void OutputDataOp(int offset);
|
|
|
|
/// <summary>
|
|
/// Outputs an equate directive. The numeric value is already formatted.
|
|
/// </summary>
|
|
/// <param name="name">Symbol label.</param>
|
|
/// <param name="valueStr">Formatted value.</param>
|
|
/// <param name="comment">End-of-line comment.</param>
|
|
void OutputEquDirective(string name, string valueStr, string comment);
|
|
|
|
/// <summary>
|
|
/// Outputs a series of local variable definitions.
|
|
/// </summary>
|
|
/// <param name="offset">Offset at which table is defined.</param>
|
|
/// <param name="newDefs">New definitions, i.e. just the variables that were defined
|
|
/// at this offset.</param>
|
|
/// <param name="allDefs">All variable definitions that are active at this point.</param>
|
|
void OutputLocalVariableTable(int offset, List<DefSymbol> newDefs,
|
|
LocalVariableTable allDefs);
|
|
|
|
/// <summary>
|
|
/// Outputs an address region directive.
|
|
/// </summary>
|
|
/// <param name="isStart">True if this is the start of a region.</param>
|
|
/// <param name="change">Address map change record.</param>
|
|
void OutputArDirective(CommonUtil.AddressMap.AddressChange change);
|
|
|
|
/// <summary>
|
|
/// Signals the code generator to flush any pending address region directives. Useful
|
|
/// for generation of non-hierarchical directives.
|
|
/// </summary>
|
|
void FlushArDirectives();
|
|
|
|
/// <summary>
|
|
/// Notify the assembler of a change in register width.
|
|
///
|
|
/// Merlin32 always sets both values (e.g. "MX %00"), cc65 sets each register
|
|
/// individually (".A16", ".I8"). We need to accommodate both styles.
|
|
/// </summary>
|
|
/// <param name="offset">Offset of change.</param>
|
|
/// <param name="prevM">Previous value for M flag.</param>
|
|
/// <param name="prevX">Previous value for X flag.</param>
|
|
/// <param name="newM">New value for M flag.</param>
|
|
/// <param name="newX">New value for X flag.</param>
|
|
void OutputRegWidthDirective(int offset, int prevM, int prevX, int newM, int newX);
|
|
|
|
/// <summary>
|
|
/// Output a line of source code. All elements must be fully formatted, except for
|
|
/// certain assembler-specific things like ':' on labels. The items will be padded
|
|
/// with spaces to fit specific column widths.
|
|
/// </summary>
|
|
/// <param name="label">Optional label.</param>
|
|
/// <param name="opcode">Opcode mnemonic.</param>
|
|
/// <param name="operand">Operand; may be empty.</param>
|
|
/// <param name="comment">Optional comment.</param>
|
|
void OutputLine(string label, string opcode, string operand, string comment);
|
|
|
|
/// <summary>
|
|
/// Output a line of source code. This will be output as-is.
|
|
/// </summary>
|
|
/// <param name="fullLine">Full text of line to outut.</param>
|
|
void OutputLine(string fullLine);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumeration of quirky or buggy behavior that GenCommon needs to handle.
|
|
/// </summary>
|
|
public class AssemblerQuirks {
|
|
/// <summary>
|
|
/// Does the assembler require a qualifier to be added to the operand when an instruction
|
|
/// formed with the Program Bank Register (JMP/JSR) attempts to access a bank zero
|
|
/// address from outside bank zero?
|
|
/// </summary>
|
|
public bool BankZeroAbsPBRRestrict { get; set; }
|
|
|
|
/// <summary>
|
|
/// Does the assembler expect the bit index for BBR/BBS/RMB/SMB to be expressed as
|
|
/// a separate argument?
|
|
/// </summary>
|
|
public bool BitNumberIsArg { get; set; }
|
|
|
|
/// <summary>
|
|
/// Are 8-bit constant args to MVN/MVP output without a leading '#'?
|
|
/// </summary>
|
|
public bool BlockMoveArgsNoHash { get; set; }
|
|
|
|
/// <summary>
|
|
/// Are the arguments to MVN/MVP reversed?
|
|
/// </summary>
|
|
public bool BlockMoveArgsReversed { get; set; }
|
|
|
|
/// <summary>
|
|
/// Does a leading underscore in a label have a special meaning? (e.g. 64tass)
|
|
/// </summary>
|
|
public bool LeadingUnderscoreSpecial { get; set; }
|
|
|
|
/// <summary>
|
|
/// Do we need to specify a 24-bit value for 16-bit absolute arguments that are
|
|
/// formed with the Program Bank Register (JMP/JSR)?
|
|
/// </summary>
|
|
public bool Need24BitsForAbsPBR { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is the assembler unable to generate relative branches that wrap around banks?
|
|
/// (Note this affects long-distance BRLs that don't appear to wrap.)
|
|
/// </summary>
|
|
public bool NoPcRelBankWrap { get; set; }
|
|
|
|
/// <summary>
|
|
/// Does the assembler support a type of label whose value can be redefined to
|
|
/// act as a local variable?
|
|
/// </summary>
|
|
public bool NoRedefinableSymbols { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is the assembler implemented as a single pass? (e.g. cc65)
|
|
/// </summary>
|
|
public bool SinglePassAssembler { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is the assembler's label width determination performed only in the first pass,
|
|
/// and not corrected when the actual width is determined?
|
|
/// </summary>
|
|
public bool SinglePassNoLabelCorrection { get; set; }
|
|
|
|
/// <summary>
|
|
/// Do 8-bit constant args to StackInt ops (BRK/COP) require a leading '#'?
|
|
/// </summary>
|
|
public bool StackIntOperandIsImmediate { get; set; }
|
|
|
|
/// <summary>
|
|
/// Does the assembler configure assembler widths based on SEP/REP, but doesn't
|
|
/// track the emulation bit?
|
|
/// </summary>
|
|
public bool TracksSepRepNotEmu { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Holds metadata generated by the assembly source generator.
|
|
/// </summary>
|
|
public class GenerationResults {
|
|
public List<string> PathNames { get; private set; }
|
|
public string ExtraOptions { get; private set; }
|
|
public List<BinaryInclude.Excision> BinaryIncludes { get; private set; }
|
|
|
|
public GenerationResults(List<string> pathNames, string extraOptions,
|
|
List<BinaryInclude.Excision> binaryIncludes) {
|
|
PathNames = CommonUtil.Container.CopyStringList(pathNames);
|
|
ExtraOptions = extraOptions;
|
|
BinaryIncludes = binaryIncludes;
|
|
}
|
|
}
|
|
}
|