package org.reasm.m68k; import java.util.Map; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; import org.reasm.Configuration; import ca.fragag.Consumer; /** * Contains configuration options specific to the M68000 family assembler. * * @author Francis Gagné */ @Immutable public final class ConfigurationOptions { /** The key used in a {@link Configuration} for ConfigurationOptions objects. */ @Nonnull public static final Object KEY = new Object(); /** The option key for {@link #automaticEven()}. Value type: {@link Boolean}. */ @Nonnull public static final String AUTOMATIC_EVEN = "automaticEven"; /** The option key for {@link #optimizeCmpiToTst()}. Value type: {@link Boolean}. */ @Nonnull public static final String OPTIMIZE_CMPI_TO_TST = "optimizeCmpiToTst"; /** The option key for {@link #optimizeMoveToMoveq()}. Value type: {@link Boolean}. */ @Nonnull public static final String OPTIMIZE_MOVE_TO_MOVEQ = "optimizeMoveToMoveq"; /** The option key for {@link #optimizeToAddqSubq()}. Value type: {@link Boolean}. */ @Nonnull public static final String OPTIMIZE_TO_ADDQ_SUBQ = "optimizeToAddqSubq"; /** The option key for {@link #optimizeUnsizedAbsoluteAddressingToPcRelative()}. Value type: {@link Boolean}. */ @Nonnull public static final String OPTIMIZE_UNSIZED_ABSOLUTE_ADDRESSING_TO_PC_RELATIVE = "optimizeUnsizedAbsoluteAddressingToPcRelative"; /** The option key for {@link #optimizeUnsizedBranches()}. Value type: {@link Boolean}. */ @Nonnull public static final String OPTIMIZE_UNSIZED_BRANCHES = "optimizeUnsizedBranches"; /** The option key for {@link #optimizeZeroDisplacement()}. Value type: {@link Boolean}. */ @Nonnull public static final String OPTIMIZE_ZERO_DISPLACEMENT = "optimizeZeroDisplacement"; /** * Creates a new ConfigurationOptions with the specified options. * * @param options * a {@link Map} of option names (keys) to values. The option names are the name of the public methods in this class * and are also available as constants in this class. The option names are case sensitive. * @param invalidEntriesConsumer * an object that receives entries in the specified options that are invalid. If this is <code>null</code>, invalid * entries are ignored. * @return the ConfigurationOptions */ public static ConfigurationOptions create(@Nonnull Map<String, Object> options, @CheckForNull Consumer<Map.Entry<String, Object>> invalidEntriesConsumer) { if (options == null) { throw new NullPointerException("options"); } boolean automaticEven = false; boolean optimizeCmpiToTst = false; boolean optimizeUnsizedBranches = false; boolean optimizeUnsizedAbsoluteAddressingToPcRelative = false; boolean optimizeToAddqSubq = false; boolean optimizeMoveToMoveq = false; boolean optimizeZeroDisplacement = false; for (Map.Entry<String, Object> option : options.entrySet()) { final Object value = option.getValue(); boolean isEntryValid = false; switch (option.getKey()) { case AUTOMATIC_EVEN: if (value instanceof Boolean) { automaticEven = ((Boolean) value).booleanValue(); isEntryValid = true; } break; case OPTIMIZE_CMPI_TO_TST: if (value instanceof Boolean) { optimizeCmpiToTst = ((Boolean) value).booleanValue(); isEntryValid = true; } break; case OPTIMIZE_MOVE_TO_MOVEQ: if (value instanceof Boolean) { optimizeMoveToMoveq = ((Boolean) value).booleanValue(); isEntryValid = true; } break; case OPTIMIZE_TO_ADDQ_SUBQ: if (value instanceof Boolean) { optimizeToAddqSubq = ((Boolean) value).booleanValue(); isEntryValid = true; } break; case OPTIMIZE_UNSIZED_ABSOLUTE_ADDRESSING_TO_PC_RELATIVE: if (value instanceof Boolean) { optimizeUnsizedAbsoluteAddressingToPcRelative = ((Boolean) value).booleanValue(); isEntryValid = true; } break; case OPTIMIZE_UNSIZED_BRANCHES: if (value instanceof Boolean) { optimizeUnsizedBranches = ((Boolean) value).booleanValue(); isEntryValid = true; } break; case OPTIMIZE_ZERO_DISPLACEMENT: if (value instanceof Boolean) { optimizeZeroDisplacement = ((Boolean) value).booleanValue(); isEntryValid = true; } break; } if (!isEntryValid && invalidEntriesConsumer != null) { invalidEntriesConsumer.accept(option); } } return new ConfigurationOptions(automaticEven, optimizeCmpiToTst, optimizeMoveToMoveq, optimizeToAddqSubq, optimizeUnsizedAbsoluteAddressingToPcRelative, optimizeUnsizedBranches, optimizeZeroDisplacement); } private final boolean automaticEven; private final boolean optimizeCmpiToTst; private final boolean optimizeMoveToMoveq; private final boolean optimizeToAddqSubq; private final boolean optimizeUnsizedAbsoluteAddressingToPcRelative; private final boolean optimizeUnsizedBranches; private final boolean optimizeZeroDisplacement; private ConfigurationOptions(boolean automaticEven, boolean optimizeCmpiToTst, boolean optimizeMoveToMoveq, boolean optimizeToAddqSubq, boolean optimizeUnsizedAbsoluteAddressingToPcRelative, boolean optimizeUnsizedBranches, boolean optimizeZeroDisplacement) { this.automaticEven = automaticEven; this.optimizeCmpiToTst = optimizeCmpiToTst; this.optimizeUnsizedBranches = optimizeUnsizedBranches; this.optimizeUnsizedAbsoluteAddressingToPcRelative = optimizeUnsizedAbsoluteAddressingToPcRelative; this.optimizeToAddqSubq = optimizeToAddqSubq; this.optimizeMoveToMoveq = optimizeMoveToMoveq; this.optimizeZeroDisplacement = optimizeZeroDisplacement; } /** * Gets a value indicating whether misaligned instructions or data should automatically be aligned. * * @return <code>true</code> to automatically align misaligned instructions or data, or <code>false</code> to leave it * misaligned */ public final boolean automaticEven() { return this.automaticEven; } /** * Gets a value indicating whether the <code>CMPI</code> instruction should be encoded as <code>TST</code> when the immediate * data is zero (<code>#0</code>). * * @return <code>true</code> to encode the <code>CMPI</code> instruction as <code>TST</code> when the immediate data is zero, or * <code>false</code> to always encode the <code>CMPI</code> instruction as a <code>CMPI</code> instruction */ public final boolean optimizeCmpiToTst() { return this.optimizeCmpiToTst; } /** * Gets a value indicating whether the <code>MOVE</code> instruction should be encoded as <code>MOVEQ</code> if possible. * * @return <code>true</code> to encode the <code>MOVE</code> instruction as <code>MOVEQ</code> if possible, or * <code>false</code> to always encode the <code>MOVE</code> instruction as a <code>MOVE</code> instruction */ public final boolean optimizeMoveToMoveq() { return this.optimizeMoveToMoveq; } /** * Gets a value indicating whether the <code>ADD</code>, <code>ADDA</code>, <code>ADDI</code>, <code>SUB</code>, * <code>SUBA</code> and <code>SUBI</code> instructions should be encoded as <code>ADDQ</code> and <code>SUBQ</code> * respectively if possible. * * @return <code>true</code> to encode <code>ADD</code>, <code>ADDA</code>, <code>ADDI</code>, <code>SUB</code>, * <code>SUBA</code> or <code>SUBI</code> instructions as <code>ADDQ</code> or <code>SUBQ</code> if possible, or * <code>false</code> to always encode such instructions using the normal encoding */ public final boolean optimizeToAddqSubq() { return this.optimizeToAddqSubq; } /** * Gets a value indicating whether an effective address using unsized absolute addressing should be encoded using the program * counter indirect with displacement mode, if it is shorter. * * @return <code>true</code> to use the program counter indirect with displacement mode if the encoding is shorter, or * <code>false</code> to use the appropriate absolute addressing mode */ public final boolean optimizeUnsizedAbsoluteAddressingToPcRelative() { return this.optimizeUnsizedAbsoluteAddressingToPcRelative; } /** * Gets a value indicating whether unsized branches should use the shortest valid encoding. * * @return <code>true</code> to use the shortest valid encoding for unsized branches, or <code>false</code> to use the word-size * encoding */ public final boolean optimizeUnsizedBranches() { return this.optimizeUnsizedBranches; } /** * Gets a value indicating whether an effective address using the address register indirect with displacement mode with a base * displacement of zero should be encoded using the address register indirect mode instead. * * @return <code>true</code> to use the address register indirect mode, or <code>false</code> to use the address register * indirect with displacement mode */ public final boolean optimizeZeroDisplacement() { return this.optimizeZeroDisplacement; } }