package org.reasm.m68k.assembly.internal;
import java.io.IOException;
import java.util.Set;
import javax.annotation.Nonnull;
import org.reasm.commons.messages.ValueOutOfRangeErrorMessage;
class BitManipulationInstruction extends TwoOperandIntegerInstruction {
@Nonnull
static final BitManipulationInstruction BCHG = new BitManipulationInstruction(0b01 << 6, AddressingModeCategory.DATA_ALTERABLE);
@Nonnull
static final BitManipulationInstruction BCLR = new BitManipulationInstruction(0b10 << 6, AddressingModeCategory.DATA_ALTERABLE);
@Nonnull
static final BitManipulationInstruction BSET = new BitManipulationInstruction(0b11 << 6, AddressingModeCategory.DATA_ALTERABLE);
@Nonnull
static final BitManipulationInstruction BTST = new BitManipulationInstruction(0b00 << 6, AddressingModeCategory.DATA,
AddressingModeCategory.DATA_EXCEPT_IMMEDIATE_DATA);
private final int opcode;
@Nonnull
private final Set<AddressingMode> validAddressingModesForDestinationDynamicForm;
@Nonnull
private final Set<AddressingMode> validAddressingModesForDestinationStaticForm;
private BitManipulationInstruction(int opcode, @Nonnull Set<AddressingMode> validAddressingModesForDestination) {
this(opcode, validAddressingModesForDestination, validAddressingModesForDestination);
}
private BitManipulationInstruction(int opcode, @Nonnull Set<AddressingMode> validAddressingModesForDestinationDynamicForm,
@Nonnull Set<AddressingMode> validAddressingModesForDestinationStaticForm) {
this.opcode = opcode;
this.validAddressingModesForDestinationDynamicForm = validAddressingModesForDestinationDynamicForm;
this.validAddressingModesForDestinationStaticForm = validAddressingModesForDestinationStaticForm;
}
@Override
void assemble(M68KAssemblyContext context, InstructionSize size) throws IOException {
final EffectiveAddress ea0 = context.ea0;
final EffectiveAddress ea1 = context.ea1;
// Parse the source operand.
context.getEffectiveAddress(context.getOperandText(0), AddressingModeCategory.DATA_REGISTER_DIRECT_OR_IMMEDIATE_DATA,
InstructionSize.LONG, ea0);
if (ea0.isDataRegisterDirect()) {
// Parse the destination operand.
context.getEffectiveAddress(context.getOperandText(1), this.validAddressingModesForDestinationDynamicForm,
InstructionSize.BYTE, ea1);
// Encode the instruction (dynamic form).
ea1.word0 |= 0b00000001_00000000 | this.opcode | ea0.getRegister() << 9;
context.appendEffectiveAddress(ea1);
} else if (ea0.isImmediateData()) {
// Parse the destination operand.
context.getEffectiveAddress(context.getOperandText(1), this.validAddressingModesForDestinationStaticForm,
InstructionSize.BYTE, 4, ea1);
// Encode the instruction (static form).
ea1.word0 |= 0b00001000_00000000 | this.opcode;
context.appendWord(ea1.word0);
context.appendWord((short) (ea0.word2 & 0xFF)); // bit number
context.appendEffectiveAddress(ea1, 1);
final int immediateData = ea0.word1 << 16 | ea0.word2;
if (immediateData < 0 || immediateData > 0xFF) {
context.addTentativeMessage(new ValueOutOfRangeErrorMessage(immediateData));
}
} else {
return;
}
if (size != InstructionSize.DEFAULT) {
if (size != (ea1.isDataRegisterDirect() ? InstructionSize.LONG : InstructionSize.BYTE)) {
context.addInvalidSizeAttributeErrorMessage();
}
}
}
}