package org.reasm.m68k.assembly.internal;
import java.io.IOException;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import org.reasm.m68k.messages.ShiftCountOutOfRangeErrorMessage;
/**
* A shift or a rotate instruction (<code>ASL</code>, <code>ASR</code>, <code>LSL</code>, <code>LSR</code>, <code>ROL</code>,
* <code>ROR</code>, <code>ROXL</code>, <code>ROXR</code>).
*
* @author Francis Gagné
*/
@Immutable
class ShiftRotateInstruction extends Instruction {
@Nonnull
static final ShiftRotateInstruction ASL = new ShiftRotateInstruction(0, 1);
@Nonnull
static final ShiftRotateInstruction ASR = new ShiftRotateInstruction(0, 0);
@Nonnull
static final ShiftRotateInstruction LSL = new ShiftRotateInstruction(1, 1);
@Nonnull
static final ShiftRotateInstruction LSR = new ShiftRotateInstruction(1, 0);
@Nonnull
static final ShiftRotateInstruction ROL = new ShiftRotateInstruction(3, 1);
@Nonnull
static final ShiftRotateInstruction ROR = new ShiftRotateInstruction(3, 0);
@Nonnull
static final ShiftRotateInstruction ROXL = new ShiftRotateInstruction(2, 1);
@Nonnull
static final ShiftRotateInstruction ROXR = new ShiftRotateInstruction(2, 0);
private final int operation;
private final int direction;
private ShiftRotateInstruction(int operation, int direction) {
this.operation = operation;
this.direction = direction;
}
@Override
void assemble2(M68KAssemblyContext context) throws IOException {
InstructionSize size = context.parseIntegerInstructionSize();
if (size == InstructionSize.INVALID) {
context.addInvalidSizeAttributeErrorMessage();
size = InstructionSize.DEFAULT;
}
if (context.numberOfOperands != 1 && context.numberOfOperands != 2) {
context.addWrongNumberOfOperandsErrorMessage();
}
final EffectiveAddress ea0 = context.ea0;
final EffectiveAddress ea1 = context.ea1;
if (context.numberOfOperands >= 2) {
// Parse the shift count.
context.getEffectiveAddress(context.getOperandText(0), AddressingModeCategory.DATA_REGISTER_DIRECT_OR_IMMEDIATE_DATA,
InstructionSize.LONG, ea0);
// Parse the destination operand.
context.getEffectiveAddress(context.getOperandText(1), AddressingModeCategory.DATA_REGISTER_DIRECT, size, ea1);
// Encode the instruction.
if (ea0.isDataRegisterDirect()) {
context.appendWord((short) (0b11100000_00100000 | ea0.getRegister() << 9 | this.direction << 8
| encodeIntegerSizeStandard(size) | this.operation << 3 | ea1.getRegister()));
} else if (ea0.isImmediateData()) {
final int immediateData = ea0.word1 << 16 | ea0.word2;
if (immediateData < 1 || immediateData > 8) {
context.addTentativeMessage(new ShiftCountOutOfRangeErrorMessage());
}
context.appendWord((short) (0b11100000_00000000 | (immediateData & 7) << 9 | this.direction << 8
| encodeIntegerSizeStandard(size) | this.operation << 3 | ea1.getRegister()));
}
} else if (context.numberOfOperands == 1) {
// Parse the destination operand.
context.getEffectiveAddress(context.getOperandText(0), AddressingModeCategory.DATA_ALTERABLE, InstructionSize.WORD, ea0);
if (ea0.isDataRegisterDirect()) {
// Encode the instruction.
context.appendWord((short) (0b11100000_00000000 | 0b001 << 9 | this.direction << 8
| encodeIntegerSizeStandard(size) | this.operation << 3 | ea0.getRegister()));
} else {
if (size != InstructionSize.DEFAULT && size != InstructionSize.WORD) {
context.addInvalidSizeAttributeErrorMessage();
}
// Encode the instruction.
ea0.word0 |= 0b11100000_11000000 | this.operation << 9 | this.direction << 8;
context.appendEffectiveAddress(ea0);
}
}
}
}