package org.reasm.m68k.assembly.internal;
import java.io.IOException;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import org.reasm.AssemblyMessage;
import org.reasm.Value;
import org.reasm.m68k.messages.AlignmentMustNotBeZeroOrNegativeErrorMessage;
import org.reasm.m68k.messages.OffsetMustNotBeNegativeErrorMessage;
import com.google.common.primitives.UnsignedLongs;
/**
* The <code>CNOP</code> directive.
*
* @author Francis Gagné
*/
@Immutable
class CnopDirective extends Mnemonic {
@Nonnull
static final CnopDirective CNOP = new CnopDirective();
@Nonnull
private static final CardinalValueVisitor.ErrorFactory OFFSET_NEGATIVE_VALUE_ERROR_FACTORY = new CardinalValueVisitor.ErrorFactory() {
@Override
public AssemblyMessage createMessage() {
return new OffsetMustNotBeNegativeErrorMessage();
}
};
@Nonnull
private static final CardinalValueVisitor.ErrorFactory ALIGNMENT_NEGATIVE_VALUE_ERROR_FACTORY = new CardinalValueVisitor.ErrorFactory() {
@Override
public AssemblyMessage createMessage() {
return new AlignmentMustNotBeZeroOrNegativeErrorMessage();
}
};
private CnopDirective() {
}
@Override
void assemble(M68KAssemblyContext context) throws IOException {
context.sizeNotAllowed();
if (context.requireNumberOfOperands(2)) {
final CardinalValueVisitor cardinalValueVisitor = context.cardinalValueVisitor;
final Value offsetValue = evaluateExpressionOperand(context, 0);
if (offsetValue != null) {
cardinalValueVisitor.reset(0, OFFSET_NEGATIVE_VALUE_ERROR_FACTORY);
Value.accept(offsetValue, cardinalValueVisitor);
final long offset = cardinalValueVisitor.getValue();
final Value alignmentValue = evaluateExpressionOperand(context, 1);
if (alignmentValue != null) {
cardinalValueVisitor.reset(1, ALIGNMENT_NEGATIVE_VALUE_ERROR_FACTORY);
Value.accept(alignmentValue, cardinalValueVisitor);
final long alignment = cardinalValueVisitor.getValue();
if (alignment != 0) {
long boundary = UnsignedLongs.divide(context.programCounter, alignment) * alignment;
if (boundary + offset < context.programCounter) {
boundary += alignment;
assert boundary + offset >= context.programCounter;
}
final long paddingSize = boundary + offset - context.programCounter;
for (long i = 0; UnsignedLongs.compare(i, paddingSize) < 0; i++) {
context.appendByte((byte) 0);
}
} else {
context.addTentativeMessage(new AlignmentMustNotBeZeroOrNegativeErrorMessage());
}
}
}
}
}
}