package org.reasm.m68k.assembly.internal;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import org.reasm.m68k.InstructionSet;
/**
* The <code>CMP</code> instruction.
*
* @author Francis Gagné
*/
@Immutable
class CmpInstruction extends TwoEaInstruction {
@Nonnull
static final CmpInstruction CMP = new CmpInstruction();
@Nonnull
private static final AddAndCmpEorOrSubForms FORMS = AddAndCmpEorOrSubForms.CMP;
@Nonnull
private static final Set<AddressingMode> DATA_OR_ADDRESS_REGISTER_DIRECT_OR_ADDRESS_REGISTER_INDIRECT_WITH_POSTINCREMENT = Collections
.unmodifiableSet(EnumSet.of(AddressingMode.DATA_REGISTER_DIRECT, AddressingMode.ADDRESS_REGISTER_DIRECT,
AddressingMode.ADDRESS_REGISTER_INDIRECT_WITH_POSTINCREMENT));
static boolean encodeCmpiAsTst(@Nonnull M68KAssemblyContext context, @Nonnull InstructionSize size,
@Nonnull EffectiveAddress ea0, @Nonnull EffectiveAddress ea1) throws IOException {
if (context.optimizeCmpiToTst) {
if (ea0.isImmediateData()) {
// TST only accepts an address register direct as the destination on CPU32 and on MC68020 or later
if (!ea1.isAddressRegisterDirect()
|| InstructionSetCheck.CPU32_OR_MC68020_OR_LATER.isSupported(context.instructionSet)) {
final int immediateData;
switch (size) {
case LONG:
immediateData = ea0.word1 << 16 | ea0.word2;
break;
default:
immediateData = ea0.word1;
break;
}
if (immediateData == 0) {
// Encode as TST
OneEaInstruction.TST.encode(context, size, ea1);
context.appendEffectiveAddress(ea1);
return true;
}
}
}
}
return false;
}
private CmpInstruction() {
}
@Override
void assemble(M68KAssemblyContext context, InstructionSize size, EffectiveAddress ea0, EffectiveAddress ea1) throws IOException {
if (!CmpmInstruction.assembleCmpm(context, size, ea0, ea1)) {
if (!encodeCmpiAsTst(context, size, ea0, ea1)) {
if (!FORMS.encodeBase(context, size, ea0, ea1, true)) {
FORMS.encodeImmediate(context, size, ea0, ea1);
}
}
}
}
@Override
Set<AddressingMode> getValidAddressingModesForDestinationOperand(InstructionSet instructionSet, EffectiveAddress ea0) {
if (ea0.isImmediateData()) {
return AddiCmpiSubiInstruction.CMPI.getValidAddressingModesForDestinationOperand(instructionSet, ea0);
}
if (ea0.isAddressRegisterIndirectWithPostincrement()) {
return DATA_OR_ADDRESS_REGISTER_DIRECT_OR_ADDRESS_REGISTER_INDIRECT_WITH_POSTINCREMENT;
}
return AddressingModeCategory.DATA_OR_ADDRESS_REGISTER_DIRECT;
}
@Override
Set<AddressingMode> getValidAddressingModesForSourceOperand(InstructionSet instructionSet) {
return AddressingModeCategory.ALL;
}
}