/*
* 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 {
///
/// Common interface for generating assembler-specific source code.
///
public interface IGenerator {
///
/// 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.
///
/// Table of pseudo-op names.
/// Format configuration.
void GetDefaultDisplayFormat(out PseudoOp.PseudoOpNames pseudoOps,
out Formatter.FormatConfig formatConfig);
///
/// Configure generator. Must be called before calling any other method or using
/// properties, unless otherwise noted.
///
/// Project to generate source for.
/// Directory in which to create output files.
/// Name to use as base for filenames.
/// Version of assembler to target. Pass in null
/// to target latest known version.
/// App settings object.
void Configure(DisasmProject project, string workDirectory, string fileNameBase,
AssemblerVersion asmVersion, AppSettings settings);
///
/// Project object with file data and Anattribs.
///
DisasmProject Project { get; }
///
/// Source code formatter.
///
Formatter SourceFormatter { get; }
///
/// Application settings.
///
AppSettings Settings { get; }
///
/// Assembler-specific behavior. Used to handle quirky behavior for things that
/// are otherwise managed by common code.
///
AssemblerQuirks Quirks { get; }
///
/// Label localization object. Behavior is assembler-specific.
///
LabelLocalizer Localizer { get; }
///
/// 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).
///
int StartOffset { get; }
///
/// Generates source files on a background thread. Method must not make any UI calls.
///
/// Async work object, used to report progress updates and
/// check for cancellation.
/// Object with list of pathnames of generated files.
GenerationResults GenerateSource(BackgroundWorker worker);
///
/// Provides an opportunity for the assembler to replace a mnemonic with another, or
/// output an instruction as hex bytes.
///
/// Opcode offset.
/// Opcode to replace.
/// 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.
string ModifyOpcode(int offset, OpDef op);
///
/// 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).
///
/// Instruction offset.
/// Existing descriptor.
/// Operand value.
/// Replacement format descriptor. If no changes are desired, returns
/// the dfd argument.
FormatDescriptor ModifyInstructionOperandFormat(int offset, FormatDescriptor dfd,
int operand);
///
/// Allows the generator to issue character encoding update instructions for source
/// files with more than one encoding.
///
///
/// This may be called for non-character numeric descriptors.
///
/// Format descriptor for character or string.
void UpdateCharacterEncoding(FormatDescriptor dfd);
///
/// Generates an opcode/operand pair for a short sequence of bytes (1-4 bytes).
/// Does not produce any source output.
///
/// Offset to data.
/// Number of bytes (1-4).
/// Opcode mnemonic.
/// Formatted operand.
void GenerateShortSequence(int offset, int length, out string opcode, out string operand);
///
/// 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.
///
void OutputAsmConfig();
///
/// Outputs one or more lines of data for the specified offset.
///
/// Offset to data.
void OutputDataOp(int offset);
///
/// Outputs an equate directive. The numeric value is already formatted.
///
/// Symbol label.
/// Formatted value.
/// End-of-line comment.
void OutputEquDirective(string name, string valueStr, string comment);
///
/// Outputs a series of local variable definitions.
///
/// Offset at which table is defined.
/// New definitions, i.e. just the variables that were defined
/// at this offset.
/// All variable definitions that are active at this point.
void OutputLocalVariableTable(int offset, List newDefs,
LocalVariableTable allDefs);
///
/// Outputs an address region directive.
///
/// True if this is the start of a region.
/// Address map change record.
void OutputArDirective(CommonUtil.AddressMap.AddressChange change);
///
/// Signals the code generator to flush any pending address region directives. Useful
/// for generation of non-hierarchical directives.
///
void FlushArDirectives();
///
/// 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.
///
/// Offset of change.
/// Previous value for M flag.
/// Previous value for X flag.
/// New value for M flag.
/// New value for X flag.
void OutputRegWidthDirective(int offset, int prevM, int prevX, int newM, int newX);
///
/// 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.
///
/// Optional label.
/// Opcode mnemonic.
/// Operand; may be empty.
/// Optional comment.
void OutputLine(string label, string opcode, string operand, string comment);
///
/// Output a line of source code. This will be output as-is.
///
/// Full text of line to outut.
void OutputLine(string fullLine);
}
///
/// Enumeration of quirky or buggy behavior that GenCommon needs to handle.
///
public class AssemblerQuirks {
///
/// 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?
///
public bool BankZeroAbsPBRRestrict { get; set; }
///
/// Does the assembler expect the bit index for BBR/BBS/RMB/SMB to be expressed as
/// a separate argument?
///
public bool BitNumberIsArg { get; set; }
///
/// Are 8-bit constant args to MVN/MVP output without a leading '#'?
///
public bool BlockMoveArgsNoHash { get; set; }
///
/// Are the arguments to MVN/MVP reversed?
///
public bool BlockMoveArgsReversed { get; set; }
///
/// Does a leading underscore in a label have a special meaning? (e.g. 64tass)
///
public bool LeadingUnderscoreSpecial { get; set; }
///
/// Do we need to specify a 24-bit value for 16-bit absolute arguments that are
/// formed with the Program Bank Register (JMP/JSR)?
///
public bool Need24BitsForAbsPBR { get; set; }
///
/// Is the assembler unable to generate relative branches that wrap around banks?
/// (Note this affects long-distance BRLs that don't appear to wrap.)
///
public bool NoPcRelBankWrap { get; set; }
///
/// Does the assembler support a type of label whose value can be redefined to
/// act as a local variable?
///
public bool NoRedefinableSymbols { get; set; }
///
/// Is the assembler implemented as a single pass? (e.g. cc65)
///
public bool SinglePassAssembler { get; set; }
///
/// Is the assembler's label width determination performed only in the first pass,
/// and not corrected when the actual width is determined?
///
public bool SinglePassNoLabelCorrection { get; set; }
///
/// Do 8-bit constant args to StackInt ops (BRK/COP) require a leading '#'?
///
public bool StackIntOperandIsImmediate { get; set; }
///
/// Does the assembler configure assembler widths based on SEP/REP, but doesn't
/// track the emulation bit?
///
public bool TracksSepRepNotEmu { get; set; }
}
///
/// Holds metadata generated by the assembly source generator.
///
public class GenerationResults {
public List PathNames { get; private set; }
public string ExtraOptions { get; private set; }
public GenerationResults(List pathNames, string extraOptions) {
PathNames = CommonUtil.Container.CopyStringList(pathNames);
ExtraOptions = extraOptions;
}
}
}