package org.reasm.m68k.assembly.internal; import java.io.IOException; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; import org.reasm.m68k.InstructionSet; /** * The <code>ADDI</code>, <code>CMPI</code> and <code>SUBI</code> instructions. * * @author Francis Gagné */ @Immutable class AddiCmpiSubiInstruction extends TwoEaInstruction { @Nonnull static final AddiCmpiSubiInstruction ADDI = new AddiCmpiSubiInstruction(AddAndCmpEorOrSubForms.ADD); @Nonnull static final AddiCmpiSubiInstruction CMPI = new AddiCmpiSubiInstruction(AddAndCmpEorOrSubForms.CMP) { @Override boolean encodeTst(M68KAssemblyContext context, InstructionSize size, EffectiveAddress ea0, EffectiveAddress ea1) throws IOException { return CmpInstruction.encodeCmpiAsTst(context, size, ea0, ea1); } @Override Set<AddressingMode> getValidAddressingModesForDestinationOperand(InstructionSet instructionSet, EffectiveAddress ea0) { if (InstructionSetCheck.CPU32_OR_MC68020_OR_LATER.isSupported(instructionSet)) { return AddressingModeCategory.ALL_EXCEPT_IMMEDIATE_DATA; } return super.getValidAddressingModesForDestinationOperand(instructionSet, ea0); } }; @Nonnull static final AddiCmpiSubiInstruction SUBI = new AddiCmpiSubiInstruction(AddAndCmpEorOrSubForms.SUB); @Nonnull private final AddAndCmpEorOrSubForms forms; AddiCmpiSubiInstruction(@Nonnull AddAndCmpEorOrSubForms forms) { this.forms = forms; } @Override void assemble(M68KAssemblyContext context, InstructionSize size, EffectiveAddress ea0, EffectiveAddress ea1) throws IOException { if (ea0.isImmediateData()) { if (!this.forms.encodeQuick(context, size, ea0, ea1)) { if (!this.encodeTst(context, size, ea0, ea1)) { // ADDI/CMPI/SUBI don't accept address register direct for the destination. // If the destination is an address register direct, encode as ADDA/CMPA/SUBA. if (ea1.isAddressRegisterDirect()) { this.forms.encodeBase(context, size, ea0, ea1, true); } else { this.forms.encodeImmediate(context, size, ea0, ea1); } } } } } /** * Encodes the instruction as a <code>TST</code> instruction, if possible. * * @param context * the {@link M68KAssemblyContext} * @param size * the instruction size * @param ea0 * the source operand * @param ea1 * the destination operand * @return <code>true</code> if the instruction has encoded as a <code>TST</code> instruction, otherwise <code>false</code> * @throws IOException * an I/O exception occurred */ boolean encodeTst(@Nonnull M68KAssemblyContext context, @Nonnull InstructionSize size, @Nonnull EffectiveAddress ea0, @Nonnull EffectiveAddress ea1) throws IOException { return false; } @Override Set<AddressingMode> getValidAddressingModesForDestinationOperand(InstructionSet instructionSet, EffectiveAddress ea0) { // Overridden by CMPI return AddressingModeCategory.ALTERABLE; } @Override Set<AddressingMode> getValidAddressingModesForSourceOperand(InstructionSet instructionSet) { return AddressingModeCategory.IMMEDIATE_DATA; } }